mercurius-js / mercurius-typescript

TypeScript usage examples and "mercurius-codegen" for Mercurius

Home Page:https://mercurius.dev

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Exclude field resolver / loader fields from query resolver return type

aldis-ameriks opened this issue · comments

It would be great is if the resolver return types could be generated taking into account existing field resolvers / loaders.

e.g. given types

type Query {
  user: User!
}

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

Using graphql-codegen, the user query resolver return type would be created as:

type User = {
  __typename?: 'User'
  id: Scalars['ID']
  name: Scalars['String']
  company: Scalars['String']
  country: Scalars['String']
}

All required fields would be generated as mandatory.

However, we may not want to return all fields from the query resolver and use field resolvers or loaders for some of the fields.

const resolvers = {
  Query: {
    // Here company and country could be excluded from return types because they exist as field resolver / loader.
    user: (root, args, context) => ({ id: '1', name: 'name' })
  },
  User: {
    company: () => 'company'
  }
}

const loaders = {
  User: {
    country: (queries, context) => 'country'
  }
}

One popular suggestion is to introduce custom type mapping and override the types that would be generated by graphql-codegen. But if this could be handled automatically, it would be a huge time saver and a win for type accuracy.

Anything further than that would end up probably being highly inaccurate, the types are intended to be statically generated, if your intention is to give the resolvers to mercurius-codegen to be runtime analyzed would be unnecessarily hard, and force the developer to follow some kind of convention, which would mean limitations

Unless I'm mistaken, the DeepPartial would also mark all the fields in the return type of the query as optional, even those that are mandatory for graphql, resulting in inaccurate return types for query resolvers.

You are right about the runtime. I'd imagine mercurius-codegen would have to plug into mercurius and generate the schema types during runtime taking into account the field resolvers from executable schema. The type generation could be behind a flag and enabled during local development. But I don't think it would force the developer to follow some specific conventions. Graphql schema would always be the same, no matter how the resolvers, loaders are structured in the project.

I don't really know how I feel about it. I understand your concern about increased complexity, but on the other hand, it would be amazing if more accurate, automated type safety could be achieved than what is now possible with graphql-codegen.

After loaders codegen I am planning to give support for graphql operations, to improve mercurius-integration-testing type-safety (and for possible code reuse in monorepos). After those two things I could think of something more complex, but the work needed vs rewards doesn't look that great.

And DeepPartial is needed for field resolvers to work properly at the moment, since if a query returns an object type, but doesn't return a specific field it would complain, even if a field resolver that is resolving that missing returning field exists.

After loaders codegen I am planning to give support for graphql operations, to improve mercurius-integration-testing type-safety (and for possible code reuse in monorepos). After those two things I could think of something more complex, but the work needed vs rewards doesn't look that great.

I partially agree with the rewards. There's definitely not that much benefit in small projects, but it can definitely be useful in mid to large projects, where developers want to achieve accurate type safety.

And DeepPartial is needed for field resolvers to work properly at the moment, since if a query returns an object type, but doesn't return a specific field it would complain, even if a field resolver that is resolving that missing returning field exists.

Yes, I understand that. Alternatively, it's also possible to define the exact return types of query resolvers by using custom type mappers, but that's a lot of manual work, especially in larger projects, and partially defeats the purpose of generating the types in the first place.
So using graphql-codegen you end up having either inaccurate types, or doing the manual work of defining custom type mappers.

I can't say with certainty if the benefits would be worth the increased complexity. But maybe it's something to consider.

I'm closing this issue for now, since it's not priority