graphql-js Queries can be in any order, but apparently input types cannot

445 Views Asked by At

Attempting to follow an example of nested mutations:

It looks like with graphql-js I can have forward references for queries but not for mutations.

For example, if I have two types, Person and User, it is legal for Queries to have forward references:

const UserType = new graphql.GraphQLObjectType({
  name: 'UserType',
  description: 'A user',
  fields: () => ({
    uuid: {type: (graphql.GraphQLString)},
    person: {
      type: PersonType,
      resolve: (root, {args}, request ) => {
        return db.personGetByUUID(request.user, root.person);
      }
    },
  })
});
const PersonType = new graphql.GraphQLObjectType({ [...]

However this forward reference is not legal for mutations:

const UserInputType = new graphql.GraphQLInputObjectType({
  name: 'UserInputFields',
  description: 'input type for creation or update of a user',
  fields: {
    uuid: {type: (graphql.GraphQLString)},
    person: {type: (PersonInputType)},
  }
});

const PersonInputType = new graphql.GraphQLInputObjectType({ [...]

If I attempt this I get the error ReferenceError: PersonInputType is not defined

My understanding was that GraphQL allows you to start at any node in a graph an create a logical tree view for querying or mutating the graph. This appears to be true for queries but not for mutations.

Is this a missing feature, limitation of Javascript, or am I doing something wrong?

1

There are 1 best solutions below

5
On BEST ANSWER

Actually you can.

The fields property on GraphQL types, could be either an object, or a function that returns an object. When you need to reference a type that hasn't been defined yet, you simply wrap the whole field object inside a function. Just like what you did when defined UserType.

const UserInputType = new graphql.GraphQLInputObjectType({
  name: 'UserInputFields',
  description: 'input type for creation or update of a user',
  fields: () => ({ // <----------- function that returns the object
    uuid: {type: (graphql.GraphQLString)},
    person: {type: (PersonInputType)},
  })
});

const PersonInputType = new graphql.GraphQLInputObjectType({ [...]

Quoting from the docs:

When two types need to refer to each other, or a type needs to refer to itself in a field, you can use a function expression (aka a closure or a thunk) to supply the fields lazily.