crystal icon indicating copy to clipboard operation
crystal copied to clipboard

Order of Ops and Effect of makeExtendSchemaPlugin and makeProcessSchemaPlugin

Open shellscape opened this issue 3 years ago • 2 comments
trafficstars

Summary

I did my best to search through the docs and the issues here (tried org:graphile "makeExtendSchemaPlugin" "makeProcessSchemaPlugin" which yielded just one isssue).

I'm curious about the order of operations (if any) and how makeExtendSchemaPlugin and makeProcessSchemaPlugin effect one another. In testing, I created two plugins;

  1. one with makeExtendSchemaPlugin that added a mutation to the schema (where there were none):
makeExtendSchemaPlugin({
  typeDefs: gql`
    type Mutation {
      bar: Boolean
    }
  `,
  resolvers: {
    Query: {
      foo: () => false
    }
  }
});
  1. and one with makeProcessSchemaPlugin that simply outputs the node name using mapSchema from @graphql-tools/utils.

I then added those two plugins, in that order to the appendPlugins array. The result was surprising. Both the use of mapSchema and printSchema yielded the same result: the Mutation was missing.

I'd like to further understand the internals at play here. On the surface and based on the docs, I would expect anything added to the schema via makeExtendSchemaPlugin to appear when I iterate over or print the schema. Please help me understand the process here. If possible, please let me know in which plugin or hook I might be able to view the schema in it's final form.

Additional context

On a whim, right after I opened this issue, I changed my typeDefs to include extend before type Mutation:

makeExtendSchemaPlugin({
  typeDefs: gql`
    extend type Mutation {
      bar: Boolean
    }
  `,
  resolvers: {
    Query: {
      foo: () => false
    }
  }
});

And the Mutation appeared in both the printed schema and mapSchema results. I'd still like to know more about the internals when you have the time to share, and would love to know more about why makeExtendSchemaPlugin seems to specifically require extend when the type hasn't previously been added to the schema. I'm guessing there's a reason there rather than a bug.

shellscape avatar Aug 01 '22 13:08 shellscape

@benjie some additional curious behavior that I can't find documentation around:

makeExtendSchemaPlugin({
  typeDefs: gql`
    type Foo {
      bar: Boolean
    }
  `
});
builder.hook('GraphQLObjectType', (field, _, context) => {
  const { scope } = context;
  if (!scope.pgIntrospection) {
    console.log('context:', context);
    console.log('scope:', scope);
    console.log('\n');
  }
  return field;
});

In this scenario, I see log output for what looks like every ObjectType, but I don't see any output for the Foo type.

What's especially curious is that I can add logging at this line, and verify that the scope is being passed to newWithHooks. https://github.com/graphile/graphile-engine/blob/fb4b7f6c1680aa52105013b45b5f4a4639feb0ba/packages/graphile-utils/src/makeExtendSchemaPlugin.ts#L318

shellscape avatar Aug 01 '22 17:08 shellscape

makeProcessSchemaPlugin runs after the schema has been built, so it runs at the very end.

makeExtendSchemaPlugin runs whilst the schema is being built.

I'd still like to know more about the internals when you have the time to share, and would love to know more about why makeExtendSchemaPlugin seems to specifically require extend when the type hasn't previously been added to the schema. I'm guessing there's a reason there rather than a bug.

makeExtendSchemaPlugin is somewhat hacky; but essentially the Mutation type is still created internally and just gets omitted if it has no fields. You can skip MutationPlugin if you want the built in mutation type to not be generated.

But I don't see any output for the Foo type.

If the Foo type isn't used then it won't be created. Try adding extend type Query { foo: Foo } to your typeDefs.

benjie avatar Aug 01 '22 18:08 benjie

Thanks for the explanation. I think there's enough there to close this one as explained.

shellscape avatar Aug 24 '22 13:08 shellscape