Errors are harder, because HTTP codes are not used and monitoring is a lot more complicated. I see value in GraphQL - but I think it brings a lot of cost to the table.
Errors are harder, because HTTP codes are not used and monitoring is a lot more complicated. I see value in GraphQL - but I think it brings a lot of cost to the table.
We're currently dealing with this on a REST API right now. If you have highly relational data, you run N+1 risks regardless. I think people misplace blame on REST/GraphQL when they will have fundamental data issues either way.
We're exploring a few ways of solving it, but they honestly all resemble GraphQL.
articles = Article.load(limit=10)
for article in articles:
# .author implicitly runs a query
author_name = article.author.name
This can be avoided in ORMs providing prefetching (e.g. `Article.load(eager_load='author')`).Now the product folks want to add comments, so you add a new comments field on your article, with a new field resolver that queries the database for comments like SELECT * FROM comments WHERE article_id = ?.
This works great when viewing a single article: the frontend makes a single query to the GraphQL API, which makes 2 database queries: one for the article details and one for the comments
But then the product folks want to update the article search page with a expandable comment section for each article, so you can preview the comments for an article. Easy enough, all you have to do is add the comment field to the GraphQL query for the article search page, it's a GraphQL success story!
But now when the article search page loads, it runs 1 GraphQL query that retrieves 20 articles, and for each one it runs the SQL query to load comments. So instead of making 2 database queries it's 21.
Now we have performance scaling along with the number of results on the page, which is not ideal.
If I conscientiously create an API endpoint that allows you to fetch articles with their comments, I'm gonna craft that query to avoid the N+1 problem. So when someone uses it, perf isn't scaling linearly.
With GraphQL, you can have a frontend person add comments without anyone from the backend team modifying anything. They say "yay it works, GraphQL is amazing", and nobody realizes this is causing scaling problems because nobody on backend actually thought about it.
Well, they can do that with REST as well. They will just make a bunch of requests. That is what usually happens in the real world.
However, the difference is that with REST, it all just looks like isolated independent requests. With graphQL it becomes more clear that someone wants to query all comments in just one query, so it's much more easy to detect and optimize for that case.
For me, GraphQL wins here.
One difference is that if the front-end makes N+1 REST calls, it's (hopefully) obvious to the front-end developer. It's also generally easy to map the REST requests to the database queries being made.
Swap it all out for a single GraphQL query and now you have no idea how it will perform or whether it was optimized for the specific fields you are requesting.
Another difference is that REST-style solutions won't work for GraphQL. Imagine you're making a bunch of REST calls, e.g. querying for a list of articles then querying for a list of comments for each one. You can ask the backend team for a new endpoint that returns them all in one query, easy enough.
But with GraphQL schemas, the potential graph of data is too large to write custom SQL queries that efficiently fetch everything in one batch. For example:
{
articles {
title
contents
author {
name
articles {
title
contents
comments {
content
author {
...
}
}
}
}
comments {
content
author {
name
}
}
}
}
Maybe a bit contrived, but it illustrates my point. Due to the ability to traverse relationships it's much easier to find yourself in a situation where the implementation of the GraphQL resolvers is not ideal for the usage, but it theoretically will work.E.g. the following REST
/articles-with-comments?number=20
which returns title, contents etc. would map to a completely new query in graphql articlesWithComments(number: Integer) {
title
contents
...
}
so it is exactly as easy to optimize. Of course this is not very composable, but that is equally true for both solutions.Every layer would send off one query, unless they’re dependent on each other, but it’d be a far cry from N+1
I don't see this as a major problem.