💯 GraphQL by PoP now supports field/directive-based versioning

— 9 minute read

I just added support for another lovely new feature in GraphQL by PoP: the ability to independently version fields and directives, which can then be selected in the query through field/directive arguments. It is similar to how REST supports versioning, but extremely fine grained: instead of versioning the whole API, or the endpoint, what is versioned is a single field or directive, and a query can involve different versions for different fields.

Versioning the schema this way solves a basic problem produced by the evolution strategy adopted by GraphQL: when deprecating a field, as to replace it with a newer implementation, the new field will need to have a new field name. Then, if the deprecated field cannot be removed (eg: because some clients are still accessing it, from queries that were never revised), then these fields tend to accumulate, making the schema have different fields for a same functionality, most of them already outdated, and the new, latest implementation of the field not able to have the original field name, indeed polluting the schema and making it not as lean as it should be.

Querying permalink

Let's see it in action. In this query, field userServiceURLs has 2 versions, 0.1.0 and 0.2.0, and we can choose one or the other through field argument versionConstraint:

Please notice that the name of the argument is not version by versionConstraint: we can pass rules to select the version, following the semantic versioning rules used by Composer:

It works for directives too:

Strategies for versioning permalink

What happens if we do not pass the versionConstraint? This depends on the implementation of the API, which can choose what strategy to follow:

Use the old version by default, until a certain date in which the new version becomes the default:

Keep using the old version until a certain date, in which the new version will become the default one to use; while in this transition period, ask the developers to explicitly add a version constraint to the old version before that date, through a new warning entry in the query:

Use the latest version, and encourage the users to explicitly state which version to use:

Use the latest version of the field whenever the versionConstraint is not set, and encourage the users to explicitly define which version must be used, showing the list of all available versions for that field through a new warning entry:

Choosing the version for all fields in the query permalink

Adding the versionConstraint parameter in the GraphQL endpoint itself (set in the GraphiQL client below as /api/endpoint/?versionConstraint=^0.1) will implicitly define that version constraint in all fields:

Any field can still override this default value with its own versionConstraint:

Visualizing the schema for some version permalink

We can also add the versionConstraint parameter in the GraphQL Voyager to visualize the schema for a specific version. For instance, in the default schema:

GraphQL default interactive schema

...field userServiceURLs has the following signature, which corresponds to version 0.1.0:

Field description for version 0.1.0

However, when adding ?versionConstraint=^0.2 to the URL (which in turn sets this parameter on the endpoint), we can visualize the schema for that version constraint. Then, field userServiceURLs has this different signature, corresponding to version 0.2.0:

Field description for version 0.2.0

Please also notice that I have added the field's version as part of the field's description; that is because, currently, GraphQL doesn't feature a version attribute queryable through introspection.