crystal icon indicating copy to clipboard operation
crystal copied to clipboard

Error when trying to add a directive with any arguments via makeExtendSchemaPlugin

Open benweint opened this issue 1 year ago • 3 comments

Summary

I'm trying to write a Postgraphile plugin which (among other things) adds several directives to my GraphQL schema. Adding directives via makeExtendSchemaPlugin seems to work if those directives have no arguments, but if they do have arguments, I see an error:

Plugin code

const AddDirectivePlugin = makeExtendSchemaPlugin(() => {
  return {
    typeDefs: gql`
      directive @foobar(x: Int!) on FIELD_DEFINITION
    `,
  };
});

Error messsage:

/Users/ben/src/ouch-my-finger/node_modules/graphile-build/dist/makeNewBuild.js:232
                throw new Error("Must not call build.getTypeByName before 'init' phase is complete");
                      ^

Error: Must not call build.getTypeByName before 'init' phase is complete
    at Object.getTypeByName (/Users/ben/src/ouch-my-finger/node_modules/graphile-build/dist/makeNewBuild.js:232:23)
    at getType (/Users/ben/src/ouch-my-finger/node_modules/graphile-utils/dist/makeExtendSchemaPlugin.js:436:32)
    at getType (/Users/ben/src/ouch-my-finger/node_modules/graphile-utils/dist/makeExtendSchemaPlugin.js:443:53)
    at /Users/ben/src/ouch-my-finger/node_modules/graphile-utils/dist/makeExtendSchemaPlugin.js:527:34
    at Array.reduce (<anonymous>)
    at getArguments (/Users/ben/src/ouch-my-finger/node_modules/graphile-utils/dist/makeExtendSchemaPlugin.js:524:25)
    at /Users/ben/src/ouch-my-finger/node_modules/graphile-utils/dist/makeExtendSchemaPlugin.js:312:42
    at Array.forEach (<anonymous>)
    at init (/Users/ben/src/ouch-my-finger/node_modules/graphile-utils/dist/makeExtendSchemaPlugin.js:126:30)
    at SchemaBuilder.applyHooks (/Users/ben/src/ouch-my-finger/node_modules/graphile-build/dist/SchemaBuilder.js:98:30)

Steps to reproduce

  1. Check out the add-directive-with-args-error branch of my fork of ouch-my-finger here
  2. Within the working copy, try to start a postgraphile server (yarn postgraphile -c postgres:///my_db -s app_public) - it shouldn't matter what's in the DB

Expected results

I would expect the directive to be added to the GraphQL schema presented by Postgraphile, and to see no error on startup.

Actual results

I get this error:

❯ yarn postgraphile -c postgres:///ben -s ben
yarn run v1.22.21
warning ../../package.json: No license field
$ postgraphile -c postgres:///ben -s ben
Server listening on port 5678 at http://[::]:5678/graphql
/Users/ben/src/ouch-my-finger/node_modules/graphile-build/dist/makeNewBuild.js:232
                throw new Error("Must not call build.getTypeByName before 'init' phase is complete");
                      ^

Error: Must not call build.getTypeByName before 'init' phase is complete
    at Object.getTypeByName (/Users/ben/src/ouch-my-finger/node_modules/graphile-build/dist/makeNewBuild.js:232:23)
    at getType (/Users/ben/src/ouch-my-finger/node_modules/graphile-utils/dist/makeExtendSchemaPlugin.js:436:32)
    at getType (/Users/ben/src/ouch-my-finger/node_modules/graphile-utils/dist/makeExtendSchemaPlugin.js:443:53)
    at /Users/ben/src/ouch-my-finger/node_modules/graphile-utils/dist/makeExtendSchemaPlugin.js:527:34
    at Array.reduce (<anonymous>)
    at getArguments (/Users/ben/src/ouch-my-finger/node_modules/graphile-utils/dist/makeExtendSchemaPlugin.js:524:25)
    at /Users/ben/src/ouch-my-finger/node_modules/graphile-utils/dist/makeExtendSchemaPlugin.js:312:42
    at Array.forEach (<anonymous>)
    at init (/Users/ben/src/ouch-my-finger/node_modules/graphile-utils/dist/makeExtendSchemaPlugin.js:126:30)
    at SchemaBuilder.applyHooks (/Users/ben/src/ouch-my-finger/node_modules/graphile-build/dist/SchemaBuilder.js:98:30)

benweint avatar Jan 11 '24 15:01 benweint

It's likely that what you're trying to do doesn't make sense (e.g. I suspect it requires https://github.com/graphql/graphql-spec/issues/300, which GraphQL doesn't support at this time) and I can't think of anything useful that a FIELD_DEFINITION directive would do in PostGraphile currently...

Nonetheless, this is the code that needs reworking:

https://github.com/graphile/crystal/blob/f13e3ca034db540fdc198571114f8afef07c7341/graphile-build/graphile-utils/src/makeExtendSchemaPlugin.ts#L569-L585

Specifically it needs to be more like the code in the block above it, i.e. there needs to be a build.registerDirective(name, scope, () => ({ locations, args, description })) instead. This'll involve building that out across the entire stack; which is currently very low priority due to the aforementioned "it's not useful" issue.

benjie avatar Jan 12 '24 17:01 benjie

Thanks @benjie! The directive location in this example is somewhat arbitrary. Let me explain the motivating use case:

We're using a Postgraphile service as a subgraph within a supergraph composed together via Apollo federation. With Apollo federation, an executable directive must be defined and identically so across all subgraphs in order for it to appear in the final supergraph schema.

This means that even if our Postgraphile subgraph has no need for this particular directive (ours indeed doesn't), we still have a requirement of defining the directive in our schema, so as to not cause it to be removed from the composed supergraph schema.

The test case as written is against a FIELD_DEFINITION directive, but the same problem reproduces with a directive defined as applicable to FIELD, QUERY, MUTATION, etc (locations for executable directives).

benweint avatar Jan 12 '24 23:01 benweint

Makes sense. We're looking for a few people to fund work on Federation support (or do it!) so if that's something you're able to help with, do get in touch. It's likely to be a good couple of weeks of work (not specifically this directive thing, that's probably closer to a half day to a day... If it works the way I hope it might; but of course this is part of the whole Federation super-task) and there's only a few people interested so it's relatively low priority for me otherwise.

benjie avatar Jan 13 '24 00:01 benjie