Comically, all of these concepts (type systems, schemas, metadata in general, etc.) is exactly what most people hated about SOAP. Instead of just the payload, you had to mess about with a WSDL, and that lead folks to enjoy REST. Well, in REST, using something like JSON Schema, you have the choice of using them, as do your clients.

Aren't interested in JSON? Look into Protocol Buffers like ProtoBuff or Cap'n Proto . They're an identical concept to the GraphQL type system, and have been implemented in a bajillion languages too.

Evolution / Versioning

Versioning is a really big, muddy, awful topic in the world of APIs, and most of us agree that every approach is a minefield .

Some folks will version in the URI, making /v1/foos and /v1/bars , then make /v2/foos and /v2/bars . If nothing changed between v1 and v2 for bars, anyone using the API doesn't know that, and has to go read some documentation to find out before they can upgrade. That leads to slow uptake, and now you have two endpoints for ages.

Some folks will start the same, with /v1/foos and /v1/bars , but then only create /v2/foos , leaving /v1/bars in place. That can be slightly better, but if (for example) the Api::v1::AppController and Api::v2::AppController have ever-so-slightly different error formats and your client is not aware of that, then a v1 or v2 error might pop up when the client is only coded to support v2 or v1. I've seen this cause a JavaScript error in production that broke the app.

That whole mess of nonsense can be avoided by not versioning your API. As daft as this might initially sound, if you can avoid changing a contract, that means less work for clients. The server can handle converting data from one format to another, or a new representation can eventually be created to replace the old representation. Replacing representations and fields carefully over time as things change is called evolution .

At a previous company offering crowdsourced carpooling, we switched from /matches to /riders , and internally those two representations shared a lot of code. "Matches" was deprecated, and clients started using the new "riders" concept. Over a few months, the internals changed to a much cleaner solution for riders. We eventually dropped the matches endpoint/serializers/logic entirely, without the riders contract changing. That helped us move fast on the code, but keep our contracts relevant for our clients until they didn't need them anymore.

That is not always possible in a rapid-application environment where things change drastically all the time. Startups love their "agile philosophies", pivots, etc., which can throw evolution out the window. As somebody who has worked for those companies, we would simply make a new API (copy, paste, tweak) and throw the old one out once a new iPhone app was launched and usage dropped below acceptable levels. There was no interest in "keeping the service alive for decades", which is a core tenant of REST, but that's ok, we were RESTish.

As pointed out in my GraphQL vs REST: Overview , easily being able to track field usage by clients is something that gives GraphQL an edge on most endpoint-based APIs. If a client wants to use field "foo" and you want to remove it, you know that their app will break.

Earlier in the article, we looked at sparse fieldsets, which can help here. If the endpoint-based API offers sparse fieldsets as an option, and clients use them, there will be trackable insight into which clients are using specific fields just like GraphQL. One downside here is that only clients requesting ?fields= will be detectable, unless the API goes a step further and requires the use of ?fields= !

I don't know if I would do it, but it's an option.

Query Language

GraphQL is primarily a query language, but if you'd like an endpoint-based API to have a query language, you can give it one.

OData has a strong slogan: the best way to REST. That's a big claim, but OData provides a lot of stuff that people seem to like about GraphQL. Not only does it offer machine-readable metadata similar to JSON Schema, and a powerful explorer similar to GraphiQL , but it provides a syntax and tooling to allow you to use a query language: