graphqlapollo-servergraphql-tools

What's the programmatic difference between a GraphQL query and an Object field?


Does anyone know how I could programmatically differentiate between a graphql query and a field? I'm talking about this:

type User {
  id: ID! <-- this would be a field
}

type Query {
  getUsers: [User]! <-- this would be a query 
}

I've tried to look at it every which way, but they are pretty much identical, both are of type FieldDefinition and have the exact same structure. So is there a way to do this? I'm trying to write an auth schema directive that applies to both and is very similar, but it should do one thing differently if the directive was applied to a query.

If all else fails I can create two separate directives, but it would be really nice if the same directive could be reused and the consumer of it wouldn't have to worry about where it was applied to, it just worked.


Solution

  • GraphQL supports three types of operations -- queries, mutations and subscriptions. An individual schema has to support queries, but the other two types are optional. For each operation that a schema does support, it defines a single type to serve as the root of that operation. We refer to these three types as root operation types. By convention, we usually name these types Query, Mutation and Subscription, but they could have any other names as well.

    If using SDL, we specify which types are associated with each operation like this:

    schema {
      query SomeType
      mutation SomeOtherType
    }
    

    if you're using Apollo Server, the above step is not necessary, but can be done to override the defaults Apollo provides.

    If you're using plain GraphQL.js, then the root operation types are defined as part of your schema object:

    const schema = new GraphQLSchema({
      query: SomeType,
      mutation: SomeOtherType,
    })
    

    Because Query or Mutation is an object type like any other, it's important to remember that a field on the Query like getUsers is still just a field. Colloquially, we refer to these fields as queries (and fields on the mutation root type as mutations), but they are still just fields.

    However, given a GraphQLResolveInfo object, you can identify which type a field belongs to, and you can also identify the three root operation types. So you can do something like this this:

    const { parentType, schema } = info
    const isQueryField = parentType === schema.getQueryType()