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

How can I make a smart comment add a directive to the output? #1706

Closed
mobinni opened this issue Jan 31, 2023 · 6 comments
Closed

How can I make a smart comment add a directive to the output? #1706

mobinni opened this issue Jan 31, 2023 · 6 comments

Comments

@mobinni
Copy link

mobinni commented Jan 31, 2023

Summary

I want to be able to comment on a table with any type of custom directive @pii and have that show up on the schema generation side.

I've tried multiple different approaches with a plugin, the closest I've gotten is to creating a directive in the schema, but I don't need that to happen as I stitch the schema into a larger one that has the directive defined. Really I just need to be able to tell the schema to take the comment of @pii and output it to the schema

function PIITag(builder: any) {
  builder.hook("GraphQLSchema", (schemaConfig: any, build: Build) => {
    return {
      ...schemaConfig,
      directives: [
        ...(schemaConfig.directives || []),
        build.newWithHooks(build.graphql.GraphQLDirective,
          { name: 'notPii', locations: ['FIELD_DEFINITION', 'OBJECT'], args: {} },
          { name: 'pii', locations: ['FIELD_DEFINITION', 'OBJECT'], args: {} }
        )
      ],
    }
  });
}

This doesn't lead to the desired output.

Desired output:

comment on function health_check() is E'@notPii true';
type Query {
  """
  Exposes the root query type nested one level down. This is helpful for Relay 1
  which can only query top level fields if they are in a particular form.
  """
  query: Query!
  healthCheck: Boolean @notPii
}

any help here would be appreciated

@benjie
Copy link
Member

benjie commented Jan 31, 2023

This is not possible in GraphQL today; there are open proposals for it but we haven’t formed a solution yet.

Here’s a good starting point for your research:

graphql/graphql-spec#300

@benjie benjie closed this as completed Jan 31, 2023
@mobinni
Copy link
Author

mobinni commented Jan 31, 2023

@benjie is there no other way to achieve this, even in post-processing of the schema?

@benjie
Copy link
Member

benjie commented Feb 1, 2023

There is no way to represent this in the GraphQL introspection system currently, so tools such as GraphiQL can never pick it up.

Apollo do something like this with federation but it’s highly custom and involves adding an “_sdl” field to the public schema.

@mobinni
Copy link
Author

mobinni commented Feb 2, 2023

I figured out a way to do it in post-processing, however, it requires you to manually annotate your schema with the custom directives.

This means that Postgraphile itself won't utilize the custom directives internally, but if you're stitching your schema into a larger one that requires annotations to be added to meet the standards of the linting you can achieve an enriched schema by means of post-processing.

  1. generate your new schema in memory using createPostGraphileSchema
  2. load the prior schema using @graphql-tools loadFilesSync
  3. Write a method to collect the directives from the old schema using visit
  4. Create a directive map to add the values to (Only add nodes that have the custom directives you want to migrate)
const collectCustomDirectiveNodes = ... => {
  let directiveMap: DirectiveMap = {
    ObjectTypeDefinition: {},
    FieldDefinition: {},
    FragmentDefinition: {},
    InputValueDefinition: {},
    InputObjectTypeDefinition: {},
    InterfaceTypeDefinition: {},
  };
...
 visit(schemaDocumentNode, {
    ObjectTypeDefinition(node) {
      directiveMap = assignNodeWithCustomDirectives(
        directiveMap,
        Kind.OBJECT_TYPE_DEFINITION,
        node
      );
...
  return directiveMap;
}
  1. Visit the new schema and if the nodes match by name add the old directives to the new node
const addCustomDirectivesToNewSchema = ... => 
  const filteredSchemaAst = visit(parse(printSchemaWithDirectives(schema)), {
    ObjectTypeDefinition(node) {
      return addDirectivesToNode(
        directiveMap,
        Kind.OBJECT_TYPE_DEFINITION,
        node
      );
    },
  ...
  return buildASTSchema(filteredSchemaAst);
}
  1. Write new schema to file
  newSchema = addCustomDirectivesToNewSchema(...)
  fs.writeFileSync(
      <path>,
      printSchemaWithDirectives(newSchema)
    );

@benjie
Copy link
Member

benjie commented Feb 2, 2023

(For anyone following this issue, the above only affects the SDL representation of the schema - it will not be present in GraphQL introspection and thus cannot be seen by tooling such as GraphiQL. Until this is standardized, using something like this is a hack and could cause you breakage when GraphQL adds official metadata via directives.)

@mobinni
Copy link
Author

mobinni commented Feb 2, 2023

This is true, it's solely a work-around for my particular use-case where I'm stitching my representation into a larger schema and the server-side consumes the SDL. This is not recommended unless you're doing something similar

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