1

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.

DanielOrtel
  • 103
  • 9

2 Answers2

2

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()
Daniel Rearden
  • 80,636
  • 11
  • 185
  • 183
  • yeah, I was parsing the `parentType` to string and comparing it directly to `"Query"`, `schema.getQueryType()` seems cleaner – DanielOrtel Oct 17 '19 at 09:39
0

After looking at every possible console log, I think I may have found it, so if anyone interested:

A Query called getUsers if defined as so:

type Query {
  getUsers: [User]!
}

will have a parentType of Query. Similar with mutations, the parentType for that is Mutation. You can access it in resolvers(or directives which extend resolvers) by:

async function resolver(parent, args, context, info) {
  // will be "Query" for queries and `Mutation` for mutations, 
  // and the parent object for anything else, ex. "User" for `type User {}`

  console.log(info.parentType) 
}

Will need to investigate this further to see if it works for every scenario, but in theory it should. If I find any issues with the approach, I'll post a comment.

DanielOrtel
  • 103
  • 9