Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Force Generating Models Doesn't Work with Go Field Force Resolver Directive #3241

Open
Dan6erbond opened this issue Sep 4, 2024 · 0 comments

Comments

@Dan6erbond
Copy link

Dan6erbond commented Sep 4, 2024

What happened?

I am building a GraphQL schema that makes a lot of use of interfaces and relations, where my internal models don't quite match up with the GQL representation so I need GQLGen to generate these models. For that I used the @goModel(forceGenerate: true) directive on my model which works fine.

However, the schema also has a lot of relations that need to be returned in field resolvers which is where I would want to use the @goField(forceResolver: true) directive.

If I combine the two it seems no model is generated, and GQLGen errors out with:

merging type systems failed: unable to bind to interface: github.com/Dan6erbond/gqlgen-force-directives-playground/models.PrivateTodo does not satisfy the interface github.com/Dan6erbond/gqlgen-force-directives-playground/graph/model.Todo
exit status 1
graph\resolver.go:1: running "go": exit status 1

What did you expect?

I expected GQLGen to generate the models and the resolvers.

Without the @goField directive it works fine, I get these models:

type PrivateTodo struct {
	ID   string `json:"id"`
	Text string `json:"text"`
	Done bool   `json:"done"`
	User *User  `json:"user"`
}

func (PrivateTodo) IsTodo() {}

type ProjectTodo struct {
	ID      string   `json:"id"`
	Text    string   `json:"text"`
	Done    bool     `json:"done"`
	User    *User    `json:"user"`
	Project *Project `json:"project"`
}

func (ProjectTodo) IsTodo() {}

The current workaround I have is configuring the models and resolvers via the gqlgen.yml file, but with how large our API is, it's getting bloated and I'd prefer to make use of directives.

Minimal graphql.schema and models to reproduce

Schema:

directive @goModel(
  model: String
  models: [String!]
  forceGenerate: Boolean
) on OBJECT | INPUT_OBJECT | SCALAR | ENUM | INTERFACE | UNION

directive @goField(
  forceResolver: Boolean
  name: String
  omittable: Boolean
) on INPUT_FIELD_DEFINITION | FIELD_DEFINITION

directive @goTag(
  key: String!
  value: String
) on INPUT_FIELD_DEFINITION | FIELD_DEFINITION

directive @goExtraField(
  name: String
  type: String!
  overrideTags: String
  description: String
) on OBJECT | INPUT_OBJECT

interface Todo
  @goModel(
    model: "github.com/Dan6erbond/gqlgen-force-directives-playground/graph/model.Todo"
  ) {
  id: ID!
  text: String!
  done: Boolean!
  user: User!
}

type PrivateTodo implements Todo @goModel(forceGenerate: true) {
  id: ID!
  text: String!
  done: Boolean!
  user: User! @goField(forceResolver: true)
}

type ProjectTodo implements Todo @goModel(forceGenerate: true) {
  id: ID!
  text: String!
  done: Boolean!
  user: User! @goField(forceResolver: true)
  project: Project! @goField(forceResolver: true)
}

type User {
  id: ID!
  name: String!
}

type Project {
  id: ID!
  name: String!
}

type Query {
  todos: [Todo!]!
}

input NewTodo {
  text: String!
  userId: String!
}

type Mutation {
  createTodo(input: NewTodo!): Todo!
}

Models:

package models

type Todo struct {
	Type string
	PrivateTodo
	ProjectTodo
}

type PrivateTodo struct {
	Text   string
	Done   bool
	UserID uint
}

type ProjectTodo struct {
	Text      string
	Done      bool
	UserID    uint
	ProjectID uint
}

Important: Enable the autobinding on the models folder so that GQLGen skips generating the PrivateTodo and ProjectTodo models by default.

autobind:
  - "github.com/Dan6erbond/gqlgen-force-directives-playground/graph/model"
  - "github.com/Dan6erbond/gqlgen-force-directives-playground/models"

I have a sandbox repo here that showcases the issue on main and shows the workaround on feature/without-force-resolver.

versions

  • go run github.com/99designs/gqlgen version: v0.17.49
  • go version: go version go1.22.3 windows/amd64
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant