无法在gqlgen的GraphQL模型中使用UUID作为ID类型。

huangapple go评论114阅读模式
英文:

Unable to use UUID for ID types within gqlgen's GraphQL models

问题

我正在尝试在Go模型中使用UUID类型(来自模块github.com/gofrs/uuid)。通常,除非我知道它们不会被增强,否则我会手动定义模型。这是我目前的代码:

package model

import "github.com/gofrs/uuid"

type Category struct {
	ID          uuid.UUID `json:"id"`
	Name        string    `json:"name"`
	Description string    `json:"description"`
	Picture     string    `json:"picture,omitempty"`
}
# GraphQL Schema

...

type Category {
  id: ID!
  name: String!
  description: String!
  picture: String
}

gqlgen配置文件如下:

autobind:
  - <module-id>/path/to/model

...

models:
  ID:
    model:
      - github.com/99designs/gqlgen/graphql.ID
      - github.com/gofrs/uuid.UUID
  Int:
    model:
      - github.com/99designs/gqlgen/graphql.Int
      - github.com/99designs/gqlgen/graphql.Int32
      - github.com/99designs/gqlgen/graphql.Int64

...

schema:
  - graph/*.graphql

struct_tag: json

使用这个设置,我收到以下错误消息:

validation failed: packages.Load: /path/to/application/graph/prelude.generated.go:2177:17: ec.unmarshalInputID undefined (type *executionContext has no field or method unmarshalInputID)
/path/to/application/graph/prelude.generated.go:2182:12: ec._ID undefined (type *executionContext has no field or method _ID)

exit status 1
graph/resolver.go:3: running "go": exit status 1

是否有一种方法可以在ID上 "本地" 使用UUID类型,而不必使用string类型并手动进行自动转换?

我曾以为这个一般用例已经被框架覆盖了 🤔


更新

我已经提交了一个拉取请求,希望这项工作对大多数人都有好处,因为UUID现在被更多地使用(或采用)。

英文:

I'm trying to use a UUID type (from module github.com/gofrs/uuid) within Go models. I do usually define models manually, unless I know they won't be augmented. This is what I currently have:

package model

import &quot;github.com/gofrs/uuid&quot;

type Category struct {
	ID          uuid.UUID `json:&quot;id&quot;`
	Name        string    `json:&quot;name&quot;`
	Description string    `json:&quot;description&quot;`
	Picture     string    `json:&quot;picture,omitempty&quot;`
}
# GraphQL Schema

...

type Category {
  id: ID!
  name: String!
  description: String!
  picture: String
}

The gqlgen configuration file looks like:

autobind:
  - &lt;module-id&gt;/path/to/model

...

models:
  ID:
    model:
      - github.com/99designs/gqlgen/graphql.ID
      - github.com/gofrs/uuid.UUID
  Int:
    model:
      - github.com/99designs/gqlgen/graphql.Int
      - github.com/99designs/gqlgen/graphql.Int32
      - github.com/99designs/gqlgen/graphql.Int64

...

schema:
  - graph/*.graphql

struct_tag: json

With this setup, I get this error message:

validation failed: packages.Load: /path/to/application/graph/prelude.generated.go:2177:17: ec.unmarshalInputID undefined (type *executionContext has no field or method unmarshalInputID)
/path/to/application/graph/prelude.generated.go:2182:12: ec._ID undefined (type *executionContext has no field or method _ID)

exit status 1
graph/resolver.go:3: running &quot;go&quot;: exit status 1

Is there a way to use the UUID type "natively" for IDs without resorting in string types and doing the auto-conversion manually?

I was under the assumption that this general use case was covered by the framework 🤔


Updates

I went ahead and send a pull request for this work. I think this should be something most people will benefit from these days, where UUIDs are used (or adopted) more often.

答案1

得分: 0

这个实现应该可以工作(需要对包名称、标识符等进行一些调整):

// uuid.go

package graphql

import (
	"errors"
	"io"

	"github.com/gofrs/uuid"
)

func MarshalUUID(t uuid.UUID) Marshaler {
	if t.IsNil() {
		return Null
	}
	return WriterFunc(func(w io.Writer) {
		_, _ = io.WriteString(w, t.String())
	})
}

func UnmarshalUUID(v interface{}) (uuid.UUID, error) {
	if str, ok := v.(string); ok {
		return uuid.FromString(str)
	}
	return uuid.Nil, errors.New("input must be an RFC-4122 formatted string")
}

我创建了一个拉取请求,其中包含这个完全的实现。如果合并,将不再需要这个,因为它将成为内置行为。

英文:

This implementation should work (with some adjustments around packages names, identifiers, etc.):

// uuid.go

package graphql

import (
	&quot;errors&quot;
	&quot;io&quot;

	&quot;github.com/gofrs/uuid&quot;
)

func MarshalUUID(t uuid.UUID) Marshaler {
	if t.IsNil() {
		return Null
	}
	return WriterFunc(func(w io.Writer) {
		_, _ = io.WriteString(w, t.String())
	})
}

func UnmarshalUUID(v interface{}) (uuid.UUID, error) {
	if str, ok := v.(string); ok {
		return uuid.FromString(str)
	}
	return uuid.Nil, errors.New(&quot;input must be an RFC-4122 formatted string&quot;)
}

> I created a pull request with this exact implementation. If merged, this wouldn't be needed anymore because it will be a built-in behavior.

huangapple
  • 本文由 发表于 2023年8月4日 23:12:22
  • 转载请务必保留本文链接:https://go.coder-hub.com/76837198.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定