GraphQL - Yay or Nay?
Graham Cox Jan 6 '17
(I've just written all of this out, on my phone, on the bus to work, and then accidentally refreshed the page and lost it. So sorry if this seems a bit abbreviated)
GraphQL has been around for a while now. And a lot of things have been written about it - almost all of which is good. So, is it ready for primetime usage and should you jump on it? Of course not. There are bad things and problems with it as well, and these need to be considered along with the good before you decide if it's the right choice.
GraphQL is an alternative to REST for your Web APIs. It exposes your data as a directed graph, allowing you to traverse it in your requests and retrieve not only the individual data you want but other linked data at the same time. You can also be in control from the client over exactly which data you want to retrieve. Between the two of these points, you get a huge saving in network time - a single request can be made to retrieve exactly the data you want, spanning multiple resource types, and not returning data that you don't care about.
Unfortunately, even though the schema itself is designed to be a nice graph with interlinked data as makes sense, the actual queries don't have any concept of namespacing. All of your top level query fields are just bundled together in one big bag, and the client developer has to work out which ones are actually relevant. Imagine a blog site - you might have top level query fields for Users, Posts and Tags all bundled together. And probably not just one field for each. Likely you will have query fields for Get By ID and Search for each of these. As your schema grows, this mess just gets worse.
Mutations make this even worse. In the retrieval world, the design is built around nested data. You would retrieve a Post, and as a sub-field of the Post you would retrieve the Comments. Mutations must be top level. This means that you have your mutations for manipulating Comments and Likes bundled in the same bag as those for Users, Posts and Tags. And you are likely to have even more of these than query fields - in the CRUD world you will likely have mutations for Create, Update and Delete for each of the resources you are working with.
In general, these two problems are the biggest pain points that I personally have with GraphQL. My other complaints are generally insignificant in comparison - in that they can be worked around if you are careful.
Whilst the actual schema itself can get messy, the code that is used to build the schema can get even worse. It is difficult to have clean code that writes a circular schema and is spread across multiple small files. Almost all of the examples that I've seen are in a single file - because it's easy. And almost all of the examples that I have seen that are in multiple files are linear. And realistically, your data is going to have cycles in it. (From the Blog example again, imagine the graph being User -> Post -> Comment -> User. Cycle right there). There are ways to handle this, but they aren't well documented and can be confusing to get working.
Versioning is the other big problem. A lot of people have the opinion that, because the Client is in control of requesting only the fields that it needs, the whole concept of Versioning can go away. If you want to remove a field, you just deprecate it and you're done. However, without versioning you can never actually get rid of that field - because it's possible that somebody is still using it. And you have difficulty with changing the semantics of a field, because you are keeping it around just changing the way it works. Imagine taking a date field that was in seconds-since-epoch and changing it to ISO-8601. Or worse, to millis-since-epoch. Clients will not see the field as deprecated, and will now just be broken. At least in the ISO-8601 change you will have an obvious break that can be picked up easily by eye. In the millis-since-epoch change it's still a number, and it can be difficult to tell by eye that the number is not 1,000 times larger than before.
The only answer I've seen for Versioning is to do the same as in the REST world. Introduce versioning outside of the GraphQL controller for breaking changes. Either by use of different URLs or by the use of headers. You then end up running different, parallel schemas for a time until you discontinue support for the old one. It works but it's crude.
So, is GraphQL ready? It depends a lot on what you are doing. If you are doing something internal, or relatively small, then by all means go for it. The worst case is that you learn something from it. If you are doing something larger and for public consumption then consider it, but be very careful because you are more likely to hit the problems that it has.