0

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 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.

x80486
  • 6,627
  • 5
  • 52
  • 111
  • If it's not covered ... well, the current maintainer is rather quick when it comes to supporting new PRs. ;) Otherwise, you could create a custom model `type ID uuid.UUID` with `uuid.UUID` coming from `github.com/gofrs/uuid.UUID`, implement the marshaling logic there and reference this custom type as `model` for `ID` in the config file. – NotX Aug 04 '23 at 20:39

1 Answers1

0

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.

x80486
  • 6,627
  • 5
  • 52
  • 111