typescriptgraphqlgraphql-codegen

How to apply mappers only to the parent and not to the resolver's return type?


In our graphql server there are essentially two types that exist in parallel.

  1. The resolver return type, generated by graphql-codegen
  2. The custom type existing internally before returning

The custom types are the actual entities that exist within our application before them being exposed by graphql.

Question

Is it possible to configure graphql-codegen to type the parent parameter of a resolver with an internal type while keeping the default resolver return type?

Why do I want this?

In some cases, I need to limit some of the fields exposed to graphql. For example, imagine I have an internal type with some interface like:

interface Pet {
  petId: string;
  name: string;
  birthdate: string;
  type: 'dog' | 'fish' | 'cat';
}

and a graphql schema like so:

enum PetType {
  dog,
  fish,
  cat
}

type Pet {
  petId: String!
  name: String!
  age: Int!
  type: PetType!
}

Query {
  findPet(petId: String!): Pet
}

Now, for whatever reason I've decided not to expose the Pet's birthdate but I need to access the Pet's birthdate to calculate the age.

const myRootPetResolver: Query['findPet'] = async (_, args, context) => {
  const { petId } = args;
  const { database } = context;

  // fetch some data from the database
  const pet = await database.findPet(petId);

  return pet;
}

const myPetAgeResolver: PetResolver['age'] = async (parent, args, context) => {
  const { birthdate } = parent; // ❌ Error birthdate does not exist on graphql type
  const { database } = context;

  return new Date().getFullYear() - new Date(birthdate).getFullYear();
}

The above won't work because the parent type is the graphql generated type and not the internal type from that I've returned in the root resolver.

I tried with a graphql-codegen plugin using a property called mappers which allows to override the default parent and return type of resolvers with a custom type. While this sort of solves the problem, it overrides the return type completely with the custom type.. making the generated types from the graphql schema meaningless.

Is there a way to override only the parent type without return type? allowParentTypeOverride looked promising but this seems to require manually indicating the parent type in each resolver.


Solution

  • Here Charly, from The Guild, working on GraphQL Code Generator.

    Have you tried enabling the allowParentTypeOverride option to be able to manually force the parent type?

    enter image description here

    Here is an example of how you would setup your resolvers:

    import { Resolvers, UserResolvers } from '../resolvers-types'
    
    type Email = string
    
    interface UserModel {
      email: Email
    }
    
    const userResolvers: UserResolvers<any, UserModel> = {
      email: (parent) => {
        parent
        // ^ of type `UserModel` (not the GraphQL one)
        return ''
      }
    }
    
    const resolvers: Resolvers = {
      User: userResolvers
    }