Forward compatiblity in GraphQL

Forward compatiblity in GraphQL


4

GraphQL is well-known for its easy to maintain backward-compatibility of APIs defined with it. You’re supposed to just add new fields/types every time you need them and never remove old ones, only mark them with @deprecated directive. Thus, your server could evolve independently of its clients versions.

However, I have a quite opposite problem: we have many independent servers, some of which could not be updated ever, and client (potentially) could connect to anyone of them. Thus, when client adopts new fields in API types, that were introduced in some newer server, and then it connects to the older one, it will get the error, because it will try to query fields that do not exist on that server.

How do I handle this type of situation in GraphQL?

The only thing I came up with is to have a top-level query field, that will return a list of supported types, as a string list. Thus, whenever you want to add a new filed in the existing type foo, you just add a new type foo2 and add this type to the list of supported types. Thus the client could decide what types it can use and, accordingly, what features it could show. However, this looks quite scary due to, well, graph nature of GraphQL: it is very hard to guaranty that clinet’s query won’t get to some unsupported type via some quirky path.

The other solution is, of course, just version the whole API and treat any change to schema as incompatible API version. But this looks, well, either too stiff, or too laborious to maintain.

P.S. I suppose, that, maybe GraphQL is just not a good solution for this type of situations, but, as usually happens, we decided to go with GraphQL far before we could foresee these use-cases.

2 Answers
2


0

… usually there is no state with ‘could not be updated ever’ servers

How it wouldn’t affect REST servers? Just responds with 404 for /api/Vxxx – clearly not supported new version? Better DX than with graphQL? I don’t think so.

Possible solutions:

  • provide APIs with some query version (+loadable schema) – ask devs to use at app beginning (with login query);
  • add ‘field introduced in API version xxx’ in docs;
  • keep a list of servers with supported API versions;
  • some service/server queryable for [nearest] server with minimum API version xxx.


0

I am not completely satisfied with that approach, but the best I managed to come up with is:

  • Have two (or more) forms of the query, one for the older and one for the newer schema.
  • Query the __schema metaobject to find out which members do and don’t exist.
  • Pick the correct query accordingly.

Unfortunately it’s not possible to exclude the non-existent field with @include(if:)/@skip(if:) directives, because directives are evaluated after type-checking, so you’ll either need multiple query documents or use some client-side templating to build them.



Leave a Reply

Your email address will not be published. Required fields are marked *