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 "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
}
The gqlgen
configuration file looks like:
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
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 "go": exit status 1
Is there a way to use the UUID
type "natively" for ID
s 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 🤔
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.
This implementation should work (with some adjustments around packages names, identifiers, etc.):
// 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")
}
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.