5 ms·
As someone who's worked with both approaches, at all levels of the stack (both backend and frontend), I think the paper (at least, its abstract) is missing the
by emilecantin 6y ago
As someone who's worked with both approaches, at all levels of the stack (both backend and frontend), I think the paper (at least, its abstract) is missing the point.
While I do "feel" faster when working with GraphQL, I think the main benefit is that it abstracts away the busywork of transferring data between frontend and backend.
Writing a backend becomes more about describing what data is available, on what terms, how it fits together, and the operations you can do on it (mutations). Gone is the busywork of writing routes, handling CRUD in a zillion slightly different ways, etc.
On the frontend, Apollo-client lets me just write my app, not having to handle data-fetching, loading & caching for the zillionth time. I need an additional field? Just add it to the query! No need to get everyone involved.
Of course, there are traps you can easily fall into with Apollo's caching, N+1 queries on the backend, etc. But in my experience, while you do have to "drop down a level" sometimes to fix these, you spend most of your time at the "higher level".
- zanellato19 6y agoI have the opposite experience working on the backend. GraphQL is too prone to N+1s and other inefficiencies because its in direct opposition of the way data is stored. Its much harder to make an efficient resolver than it is making an efficient REST endpoint. 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.
- gabereiser 6y agoCan you give some concrete examples on the N+1 problem? I’ve heard this before but never experienced it.
- dudul 6y agoa query that lets you fetch a list of posts, each post has an author field. So if you ask for these, a naive backend will "resolve" the author for each post individually (so N queries to the DB to fetch 1 author each time) as opposed to a single resolution for the batch of authors.
- tynorf 6y agoI think the classic example is article list with author details. You load the articles (one query), then for each article you load its author (N queries). Naive use of an ORM causes this: 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')`).
- baumandm 6y agoImagine you're working on a bespoke blog engine for your company, so you have a GraphQL API that lets you query for all articles or just a single article. 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.
- zachrip 6y agoThe solution for this is to use something like dataloader btw. It essentially waits for all these queries (I believe it uses queueMicrotask under the hood) and batches them. Not unlike other db batching proxies.
- valeness 6y agoWouldn't it be more resource efficient to traverse the graph ahead of time and prefetch all related resources with a single query?
- zachrip 6y agoThis is more or less what dataloader accomplishes. Generally speaking when creating a gql service, graph traversal is not app code but library code.
- zanellato19 6y ago
- TheCoelacanth 6y agoIn my experience, N+1 queries are roughly as easy to run into with naive GraphQL as with naive REST. When you are optimizing the queries, it's slightly easier to get rid of the N+1 behavior in GraphQL than in REST because you can see exactly what data the client is trying to get and can fetch data differently based on that instead of needing to come up with your own way for the API to describe what data to fetch.
- SkyPuncher 6y ago> In my experience, N+1 queries are roughly as easy to run into with naive GraphQL as with naive REST. 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.
- Technically 6y ago> GraphQL is too prone to N+1s and other inefficiencies because its in direct opposition of the way data is stored. A GraphQL server stack makes a lot more sense when you structure the data around the queries you want to make. This often isn't realistic when converting an existing relational model. There's an inherent tradeoff with the backend you use between SQL-like querying and GraphQL-like querying—they're built around different use cases. I'd recommend approaching GraphQL data modeling around the indexes used to support the queries you want to use—you can then bound (and, if you want, restrict) the resulting number of backend queries based on the input query, not the backing data. However, this would represent large shift from using an ORM dedicated to SQL access for many developers.
- chris_st 6y agoThis is definitely my experience, particularly in using Hasura (particularly via the wonderful NHost[0], a fantastic database service). I believe that Hasura knows how to not do N+1 queries. [0] https://nhost.io https://nhost.io
- 5Qn8mNbc2FNCiVV 6y agoTry looking at the generated sql. Afaik it's (almost) always a single sql query being ran
- yen223 6y agoHasura generates one SQL query per top-level field. Hasura takes advantage of Postgres's JSON features to compile a deeply-nested graphql query into a single query. It's pretty impressive too. For any deeply-nested query, like fetching the 1-to-many children of 1-to-many children of some entity, a lot of ORMs will often have to resort to doing N+1 queries, which adds a surprising amount of latency to a request.
- vmware513 6y agoAgree, a good library on frontend level simplify the whole development process. Ember Data solves almost everything so you can focus on features and deliver the app in no time.
- emilecantin 6y agoSounds interesting, is it tied to Ember or does it just share the name? That's one thing that's great about Apollo; it's not too tied to any other tech / framework (except GraphQL, of course).
- vmware513 6y agoEmber - Ember Data live together nicely. If you would prefer an independent modern Data library, try out Orbit.js. https://orbitjs.com/ https://orbitjs.com/