Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add ability to extend/wrap/apply modifications to output schema in plugin hook #959

Open
roman-vanesyan opened this issue Jul 28, 2021 · 1 comment

Comments

@roman-vanesyan
Copy link

roman-vanesyan commented Jul 28, 2021

As far as I understand it isn't possible to update/apply middlewares to generate schema right in the plugin.

To better cover the requested feature I'd like to provide a small example:
I'd like to use graphql-shield package to add authorization logic to my GraphQL layer and I'd like to define graphql-shield rules right in the mutationField and queryField calls under the shield field, for instance:

export const createWorkspace = mutationField("createWorkspace", {
  type: "Workspace",
  args: {
    name: nonNull(stringArg()),
    description: stringArg(),
  },

  shield: isAuthenticated,

  resolve: (_, args, { workspace, currentUser }) =>
    workspace.createWorkspace({ userId: currentUser!.id, ...args }),
});

The primary use of graphql-shield as middleware applied by graphql-middleware package (to better understand how graphql-shield is working please checkout official doc page: https://www.graphql-shield.com/docs). So normally to apply graphql-shield to schema we need to do:

const permissions = shield({
  Mutation: {
    createWorkspace: isAuthenticated,
  }
})

// later
schema = applyMiddleware(schema, permissions);

So as it can be seen because graphql-shield applies middleware to the schema I need to somehow to apply it to the generated schema by nexus and taking into the account that I'd like to define shield permissions right on the nexus schema definition I need a way to apply modifications in the plugin to the final schema. So imagine onAfterBuild plugin hook would allow us to provide a custom schema, then something like this would be possible:

export const shieldPlugin = (): NexusPlugin => {
  let rules;

  return plugin({
    name: "ShieldPlugin",
    description: "Add support for graphql-shield.",
    fieldDefTypes,
    onBeforeBuild() {
      rules = Object.create(null);
    },
    onAddOutputField(field) {
      if (!(field.parentType in rules)) {
        rules[field.parentType] = {};
      }

      if (!isNil(field.shield)) {
        rules[field.parentType][field.name] = field.shield;
      }
    },
    onAfterBuild(schema) {
      const {schema: ret } = applyMiddleware(schema, shield(rules));
      return ret;
    },
  });
};

As it already been said, I propose to add ability to onAfterBuild plugin hook to return a new modified schema.

@tgriesser
Copy link
Member

I think this seems like a reasonable thing to add.

Basically you want to change the signature to onAfterBuild(schema): GraphQLSchema | void, where if a new schema is returned, it's used?

So:

onAfterBuildFns.forEach((fn) => fn(schema))

return { schema, missingTypes, finalConfig }

becomes:

let finalSchema = schema
onAfterBuildFns.forEach((fn) => {
  finalSchema = fn(finalSchema) ?? finalSchema
})

return { schema: finalSchema, missingTypes, finalConfig }

Want to open a PR?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants