One consideration I rarely see mentioned when discussing REST vs. TechDuJour is:
who are your users?
If you develop an API for your front-end team, use the fastest, most efficient protocol. Use something that you can change quickly. Optimize for speed in all regards.
If you develop an API for other users and they expect that API to be around for a while and gradually grow, then you need to think about how much pain are you going to subject your users to when your API changes.
GraphQL: You will not get your domain model right on the first attempt. So you will need to change your "Graph". Your "Graph" might change substantially. How do you deal with that?
REST: Same thing: There are well-known standards how to grow and evolve a true RESTful API. Yet, you may still mess with your users, declare a /v2/ endpoint and discontinue /v1/
Not a general solution, but with Hasura, one approach we have seen is to use Postgres views to keep the old graph around as your data model changes.
In general API evolution is tricky and perfect decoupling between API clients and servers not possible (the article talks about this). What one can aim for is a combination of:
1) Adding new query parameters should not break clients
2) Adding new fields to the responses should not break clients
3) Adding new serialization formats (for newer clients) should not break existing clients
#1 & #2 is roughly what you get with GraphQL optional fields.
Phil Sturgeon has good articles on API Versioning[1] and Evolvability[2] for REST API's
"perfect decoupling between API clients and servers not possible "
Well, the ultimate REST client: the browser, comes pretty close to that.
It doesn't care if you are rendering an app to manage your bank account or a blog or Hacker News.
If you've made a catastrophic and backwards-incompatible error, a common solution is to write "V2" fields and then reimplement the previous iteration's fields with the new resolvers. Old clients will then be able to continue to resolve fields they expect, while new clients will be able to take advantage of new features. This is generally pretty rare, because usually the usecase is that you're expanding the graph, and generally if you have followed the rules and best practices in writing the graph then expanding the graph should just work in a backwards-compatible way.
(aside: I agree that changing your graph / domain model is likely, and I take a dim view of tools that automatically generate APIs as a result.)
I've also seen https://github.com/ef-eng/graphql-query-rewriter and consider it an interesting thought, but have never seen it in production (and most people are rightly worried about doing such a thing).
GraphQL is our API for our frontend team, but it's also our API for end user devs. We just run it through an app that generates a REST API from a subset of our usual schema graph. (The decision was made not to expose the raw subset itself mostly just to cut down on docs duplication and avoid confusion for clients that don't know or need to know GraphQL.) This comes with advantages like allowing the use of `_expand` fields like you'd see on Stripe's API (https://stripe.com/docs/api/expanding_objects), without us having to break a sweat.
Comments
One consideration I rarely see mentioned when discussing REST vs. TechDuJour is:
If you develop an API for your front-end team, use the fastest, most efficient protocol. Use something that you can change quickly. Optimize for speed in all regards.If you develop an API for other users and they expect that API to be around for a while and gradually grow, then you need to think about how much pain are you going to subject your users to when your API changes.
GraphQL: You will not get your domain model right on the first attempt. So you will need to change your "Graph". Your "Graph" might change substantially. How do you deal with that?
REST: Same thing: There are well-known standards how to grow and evolve a true RESTful API. Yet, you may still mess with your users, declare a /v2/ endpoint and discontinue /v1/
Not a general solution, but with Hasura, one approach we have seen is to use Postgres views to keep the old graph around as your data model changes.
In general API evolution is tricky and perfect decoupling between API clients and servers not possible (the article talks about this). What one can aim for is a combination of:
1) Adding new query parameters should not break clients 2) Adding new fields to the responses should not break clients 3) Adding new serialization formats (for newer clients) should not break existing clients
#1 & #2 is roughly what you get with GraphQL optional fields.
Phil Sturgeon has good articles on API Versioning[1] and Evolvability[2] for REST API's
[1] https://apisyouwonthate.com/blog/api-versioning-has-no-right... [2] https://phil.tech/2018/api-evolution-for-rest-http-apis/
"perfect decoupling between API clients and servers not possible "
Well, the ultimate REST client: the browser, comes pretty close to that. It doesn't care if you are rendering an app to manage your bank account or a blog or Hacker News.
If you've made a catastrophic and backwards-incompatible error, a common solution is to write "V2" fields and then reimplement the previous iteration's fields with the new resolvers. Old clients will then be able to continue to resolve fields they expect, while new clients will be able to take advantage of new features. This is generally pretty rare, because usually the usecase is that you're expanding the graph, and generally if you have followed the rules and best practices in writing the graph then expanding the graph should just work in a backwards-compatible way.
(aside: I agree that changing your graph / domain model is likely, and I take a dim view of tools that automatically generate APIs as a result.)
I've also seen https://github.com/ef-eng/graphql-query-rewriter and consider it an interesting thought, but have never seen it in production (and most people are rightly worried about doing such a thing).
GraphQL is our API for our frontend team, but it's also our API for end user devs. We just run it through an app that generates a REST API from a subset of our usual schema graph. (The decision was made not to expose the raw subset itself mostly just to cut down on docs duplication and avoid confusion for clients that don't know or need to know GraphQL.) This comes with advantages like allowing the use of `_expand` fields like you'd see on Stripe's API (https://stripe.com/docs/api/expanding_objects), without us having to break a sweat.