What is up with schema directives right now?

Attempting to migrate a pretty small service over to v3 for testing, and for a while directives seemed to be in a weird place.

I originally used attachDirectiveResolvers, and then SchemaDirectiveVisitor came out, and that was something on my to-do list to migrate over, as apparently attachDirectiveResolvers was deprecated.

Now I’m trying to port a few simple directive resolvers over to the current pattern, and here’s where things get confusing for me.

API is confusing, documentation inconsistent
Apollo states to more-or-less do what @graphql-tools states to use, and it says “schema directives are a legacy feature”, on the migration guide, but that link is dead.

Looking at the documentation for @graphql-tools, it states a general Schema Directive pattern that relies on using transforms, and in the Apollo docs I see reference to makeExecutableSchema({schemaTransforms}), but that API doesn’t appear to exist according to the type definitions on makeExecutableSchema.

On top of that, the pattern used in @graphql-tools uses transforms, but the documentation on the Apollo side uses visitors, and I don’t see anywhere a clear way to implement my directives coming from either party.

@graphql-tools states a general pattern for what a schema directive should look like, but actual implementation is specific to the server framework. But when looking at Apollo’s API, it seems to reference tooling present in @graphql-tools that doesn’t appear to exist anymore.

Thoroughly confused here. Are visitors still the pattern to use here?

Adding directives to a federated service

buildFederatedSchema/buildSubgraphSchema accepts typeDefs and resolvers, similar to makeExecutableSchema, but it’s unclear if I need to do these in a particular order.

Do I need to make an executable. schema first, and then turn it into a federated schema, or do I need to build a federated schema and make it executable? How do I actually do that, when the results of buildFederatedSchema and makeExecutableSchema can’t cleanly pipe into each other?

I can’t simply make an executable schema and then make that schema federated, because they each accept lower-level types and output a schema, and neither of them appear to allow a schema as input, so I appear to need to make an executable schema, pull out the typedefs, and then make a federated schema from that.

This seems like a pretty simple use-case, and for the life of me I can’t figure out a way to do this that doesn’t feel like a hack.


Maybe I’m just confused, but the docs are just making me more confused right now. Can anybody give me a breakdown of the current state of schema directives?

1 Like

Hello! Apologies for the rough experience with custom directives lately. This stems from two very similarly timed events:

  • The release of Apollo Server 3, which removes built-in support for the schemaDirectives option (this removal was to remove Apollo Server’s dependency on a long-outdated version of graphql-tools)

  • The release of graphql-tools v8, which removes support for the SchemaDirectiveVisitor-based API in favor of mapSchema and getDirectives

With the release of AS3, we needed to make updates to our custom directives article, which is now available. However, this article still uses the SchemaDirectiveVisitor API, which means its guidance is not compatible with graphql-tools v8. It’s on my backlog to update it to use the new API.

In the meantime, the custom directives article works with graphql-tools v7 and earlier, and the graphql-tools docs can hopefully help you jump in with v8 immediately. (I’ll certainly be using them to update our article :grinning_face_with_smiling_eyes:)

2 Likes

I’d like to bring all my stuff up to speed at once, and I can wait a little bit to do so; when can I expect this all to hopefully be buttoned up? Any issues I can watch in GH?

1 Like

I’ve created an issue for tracking here.

I can’t guarantee a timeframe for the article’s updates to be completed, but I plan to spend time on this next week and am hopeful that the migration is straightforward.

1 Like

An update to the custom directives article is now live. Let me know if this does the trick for moving stuff over!

Note the following:

  • Because the graphql-tools docs already took care of migrating the article’s long list of examples, I’ve removed those examples and link to their docs instead of duplicating information.

  • The CodeSandbox linked in the article will automatically update eventually to reflect v8 changes to its backing repo (but it hasn’t yet :grinning_face_with_smiling_eyes:).

1 Like

Thanks! I’ll check it out.

Is there an example of this using federation? I am not sure on how to add the directives when using, buildSubgraphSchema([{ typeDefs, resolvers }]);

Currently we do something like:

schema = buildSubgraphSchema([{ typeDefs, resolvers }]);
SchemaDirectiveVisitor.visitSchemaDirectives(schema, directives);

We could use graphql-tools for the SchemaDirectiveVisitor support, but it would be nice to update our subgraphs to the new paradigm and graphql-tools v8. Any federation options here? Thank you!

Hello, thanks for the followup question! You’re absolutely correct that we don’t currently have federation-specific guidance for the new directive method. I’ll investigate this this week.

1 Like

Hello again! The subgraph-specific section on custom schema directives has now been updated.

Using @graphql-tools v8 transformer functions with a subgraph requires minimal changes (just make sure to apply transformer functions to the subgraph schema before providing that schema to ApolloServer).

Make sure to check out the Important considerations notice at the top of the section for additional guidance. Hope this helps!

Hello, I am trying to upgrade our graphql-tools package to the latest version - we use it for the custom schema directives (for our subgraphs) - I am still trying to grasp the new implementation but my question is - the documentation only considers that there is only one schema directive that we are applying

i.e

// Transform the schema by applying directive logic
schema = upperDirectiveTransformer(schema, 'upper');

// Provide the schema to the ApolloServer constructor
const server = new ApolloServer({schema});

I am struggling with how we can combine all of our directives when we are calling them before server initialization

i.e. if I had upperDirectiveTransformer, dateFormatDirectiveTransformer … how should it work ? Is there a standard pattern / examples ? Is something like a reducer that should be used in these situations ? Should there be only a single transformer that based on the names passed should transform our schema ?

or is this what should be done ?

schema = upperDirectiveTransformer(schema, 'upper');
schema = dateFormatDirectiveTransformer(schema, 'formatDate');

^ this seems clunky

I’m also in the middle of migrating from SchemaDirectiveVisitor to the new graphql-tools API, and I’m beginning to grasp it, but it would be great if there were actually one or more examples stepping through the conversion of a SchemaDirectiveVisitor class to the new mapSchema/MapperKind API. Does such a thing exist already, and if so, could anyone post the link(s)?

Thanks!

for anyone who encounters issue with how to initialize multiple schema directives for your server