> With all of those caveats noted, HTTP/2 should put to rest any notion of the need to minimise the number of requests for APIs; the protocol makes them cheap enough to not practically matter. Go ahead and design a highly granular HTTP API to meet the needs of your clients
This seems highly misleading and missing the point. Sure, you can send a lot of requests in parallel with http/2. But you still incur significant latency if these multiple requests are dependent on one another and serialized. For instance, suppose you have 2 granular APIs that:
- Returns all friends for the specific user
- Returns the name, age and hometown for a specific user
Suppose your client wants to get all of a user's friends whose hometown is NYC. Even with http/2, it has to use the first API, wait for the response containing a list of userIDs, then use the second API to get all of their hometowns.
Whereas with GraphQL, it facilitates building a single API call that says "give me all friends for a specific user, along with each friend's hometown". Now, there is only one round-trip latency cost. Not two. Even with the overhead improvements mentioned, the cost of two back-to-back round-trips would be much higher. It is very odd that this isn't mentioned in the article or any of the other articles they reference.
Not only that, but the resulting set will have inconsistencies if the database changes between the two requests. It's very unusual for HTTP applications to maintain transactional consistency over multiple requests.
This can be a security issue among other things, and even when it isn't, it can result in the display of glitchy data, whose inconsistency persists in the client which fetched them.
For example, you get all of the user's friends' userIDs. Then the DB is changed to remove one of the friends (by that friend). Then that friend changes their hometown to a new place, that they don't want the original user to know, and expects the original user can't see.
Then you do the second API call to get the hometowns of the userIDs. The result contains the new place that you should not have been able to access, and maybe it's shown on a screen for an unbounded time after that, or printed in a report.
Similar issues occur when fetching data to sum into totals and finding it doesn't match an expected total, or expecting some logical constraint to hold for every item in the result because it's implied by the original query.
(Live-streamed query updates turn these into momentary glitches, which is still wrong but at least those disappear from view soon after.)
Fields: /users/*/hometown
in the same request.It feels like it’s solving all the wrong problems to me - who actually wants to put varnish in between GraphQL client and server? Caching can be done more efficiently at either end. And this doesn’t provide a replacement for a query language, just moves some of the optimizations to the transport (http2) layer.
Now I’m wondering why Apollo doesn’t use http2 push to batch requests, instead of merging queries. Or does it?
Better yet, submit a request asking for all friends whose hometown is NYC (or whose hometown is the same as one of the user's previous hometowns, or...). That way only a subset of the data needs transmitting.
GET users/<id>/friends
?fields=friend.*
&where=hometown:'NYC'
&aggregate=distinctI wasn't sold on the GraphQL hype then, and I'm still not, but this article seems to miss the point. [Edit: I mean, it agrees, but it does so poorly]
A lot of people TALK about the lack of multiple back-and-forth, and about not wasting unnecessary data, but honestly, that wasn't a big deal. I expect there are some situations where that comes into play, but for most people the appeal of GraphQL lies elsewhere. If HTTP/2 means that's less of a big deal, I don't expect much change.
The legit upside to GraphQL was that backend could change rapidly without breaking compatibility for existing consumers. Some changes could be fixed purely frontend by changing the query, but if we needed new data that wasn't provided (or a variation on data that was provided) the backend could add that AND NOT IMPACT EXISTING CONSUMERS. That's not the only benefit (and remember, I remain a skeptic) but that was by far the biggest and was definitely real.
Even if the claims of HTTP/2 rendering the call overhead are correct (see other comments to doubt that), that has no impact on this value of GraphQL.
Why not?
A litmus test for a well designed GraphQL API is: could you tell what the client looks like and what the client does simply by looking at the schema? GraphQL forced everyone to think about the end-user experience, and to be on the same page. Literally. And that is it’s greatest strength.
Having used REST (with swagger/openAPI), gRPC and now graphQL, the most painful thing has been the tribal militance from supporters of each, defending their own vested interest.
It's almost like different tools are useful for different things.
This is something I really wish I understood before going down the road of graphql. I think it's a great technology, but the developers supporting it are making it nearly impossible for a legacy codebase to ever adopt.
Ex: so many JS codebases use redux. Apollo is a popular graphql framework that supported redux integration for some time, then suddenly ripped it out. They cited performance concerns, but I looked through the code myself and it would seem they just have a bias against redux. This issue thread makes that especially evident: https://github.com/apollographql/apollo-client/issues/2273
We were very lucky to have found that before breaking ground on the work.
I prefer interacting with GraphQL over RESTful interfaces. From my experience, it's less prone running into bugs inherent to client-side joins of API responses, easier to evolve iteratively, and generally more pleasant to work with thanks to its introspectable declarative schema and flexible query language.
HTTP2 is just a transport, you still need to put something on it, like gRPC.
Seems natural that GraphQL will evolve to use it, and benefit from the technical improvements.
I really like the server push model, but not sure how to square it with GraphQL way of doing things.
Yeah me too, I would compare restful to GraphQL and HTTP2 to HTTP1. It is also annoying that the author hardly mentions restful APIs or it's shortcomings.
I feel like I'm missing something, as that seems incredibly limited, especially with things like performance (where queries need to be tuned and refined and custom written. Just a simple SELECT * FROM X INNER JOIN Y and horrible N+1 isn't good enough)
Can someone please explain what is GraphQL once and for all?
BTW - I may be wrong / misunderstanding something here as I'm only in the research phase, but here's what I got:
GraphQL is an alternative to REST as a way for clients to query servers for information. In a REST query, you hit an endpoint and add optional query params. But you get back results based purely on what the server has been singularly designed to give back. For example, if I query:
GET /users/1
I'll get back a user object that the server has been programmed to return. It's of course possible to customize this with query params, and do something like:
GET /users/1?only_include=first_name,last_name
But that's the exception to most RESTful APIs, not the norm.
In a GraphQL query, the client specifies _exactly_ which fields it wants back, and that's baked into the design. So the client would submit a query like this:
{ user(id: "1") { first_name last_name } }
And the server would return exactly the object the client asked for.
There's no magic here -- that's the part that many people have trouble explaining. When you write your GraphQL server, you still need to write the actual queries (<--- this is the key!). But structurally, you write more generic queries -- you'd say "when a client requests a user, run this SQL", "when a client requests first_name on a user, run this SQL", etc. etc.
That way on the server, you write isolated query resolvers (called, amazingly enough, resolvers), each of which get run when a query comes in.
This is as opposed to a RESTful approach, where you'd do a more traditional single SQL query for the /users/:id endpoint (SELECT * FROM USERS WHERE ID = ... )
Hope that makes sense (and is accurate!)
In short: it allows you to query a database much more naturally in one go, rather than having to fetch data, and depending on that data then fetch more data. On top of that, it's typed, relatively easy to learn and well documented. I'd highly recommend it, even if it's a tad more complicated than plain REST.
The server must fulfil this contract by providing methods (called resolvers) for each field.
The client must fulfil this contract by only asking for available fields.
The query language is built to support highly nested data.
Now, the N+1 problem you are talking about is not a GraphQL problem, but an implementation problem. Depending on how you write your server methods you can get it down to very few db calls (some use a thing called dataloader. Other tools are hasura or postgraphile)
Much more important to me is how it allows the backend and frontend to work closer together. I can simply send the frontend developers my schema and then they know exactly what each endpoint returns, down to the exact type of the returned keys. There's no more back and forth on what the data for a new endpoint is supposed to look like. Either the backend devs take lead and hand a schema to the frontend devs, or the frontend devs take the lead and hand a schema to the backend devs.
Other than that there's quite a lot of really cool tooling. On the backend (python/django) I'm no longer needing to write long-winded serializers for each specific kind of view. I can simply make a query object that returns the right database query. On the frontend (typescript/react) they no longer need to write types for each API view, they can simply hand the schema to a code generator and get a file out declaring all the types the API deals with.
GraphiQL is awesome for both frontend and backend devs, At the very least it's a tidy small editor for queries. It allows you to run queries as you're developing or testing views. The documentation pane shows all the return types and expected arguments and types even if you don't put any effort into documenting anything. If you do put effort into documenting it becomes a powerful API documentation that's be easy to keep up-to date.
We're still in the early days of using graphQL but what I've seen so far certainly is worth the growing pains we're going through. The only real nitpick I have is the poor documentation of graphene-python, quite a lot of crucial use cases have you running around stack overflow and the source code to find answers. The case that gave us the most trouble so far (backend and frontend) is what to do with errors. We've gone the route of having views returning a union of the result and a global error type, which seems to be working nicely so far.
Of course the richer queries are nice too, but for us they seem to be mostly limited to making queries return less info when possible. e.g. when querying users you don't always need to return the entire user, which graphQL supports nicely, allowing you to elude profile photos or other expensive-to-calculate-columns whenever needed.
``` user { id, first_name } ```
would on the back end map to a function that runs something like.
``` select id, first_name from users ```
So the fields are dynamic in a way. Allowing you to select only the data you want. You can also nest data calls, like joins.
``` user { id, first_name, user_profile { bio, recent_comments } } ```
This would execute the above. Then take that user object into a query context. That query context allows you grab any elements from the parent returned object. I.E. the user id.
That would then execute the nested query like
``` select bio, recent_comments from user_profile where id = $user.id ```
So instead of rest end points. You are building a number of functions that return an object. You can then define relations that operate off of those returned objects. You can also restrict queries in production. So only white listed / approved queries are run.
A schema is a list of all these objects that may be returned and their relation also including type. Instead of a reverse proxy like nginx. There is schema stitching. Which combines all the schemas into one big schema. When querying it will proxy the respective calls to the respective back end services.
I did a talk on GraphQL a bit ago, so it may be out dated.
https://blog.animus.design/kotlin-backend-presentation/
Corresponding repo
https://gitlab.com/AnimusDesign/KotlinIMDBDemo/blob/master/a...
I've not used Graphql in production. When I was researching it's ecosystem anything outside of JS leaved a bit to be desired. That being said. It's a solution to a problem.
Openapi can generate clients. But if you need to make six calls. It's not performance or transit time. It's cleaning up the errors on that. Waiting for one to respond then another. From that vantage point I see the benefit. One query get what you need. If anything fails along the way it stops. It shifts the error checking pattern to the server.
Additionally in react and even mobile. There are redux or state machine stores that operate strictly off of graph ql. You've now centralized data retrieval, and state management of the app. That's a pretty big win.
https://www.apollographql.com/docs/react/data/local-state/
All of this is very beneficial to the front end / mobile. Easing data retrieval, being more expressive and type safe. But it's the front end driving how data is presented and stored to an extent. By using graphql to get the best support you should be running on node.
It needs a filter and it definitely needs to be applied to a limited, custom view of the actual underlying data, but… that’s what you have to do anyway with a REST or GraphQL API.
By the time you’re done making your REST/GraphQL API “really flexible” couldn’t you just build an SQL filter?
All the APIs I used to so far are so limited. For example there’s no easy way to query multiple posts at once on GitHub’s GQL while that could have be an extremely simple `SELECT title FROM issues WHERE id IN (13,57)`
A few weeks ago I found an interesting open-source project that tries to combine the best of GraphQL and REST, though it's more tilted towards REST.
https://www.graphiti.dev/guides/
We haven't switched our API over just yet, but are planning to do so.
2. HTTP/2 doesn't make latency/speed of light zero.
3. Outside of performance, GraphQL is a type-safe, error-minimal way to perform joins and searches.
But. I use GraphQL. GraphQL is a whole toolchain around client-server interactions. (IMHO) It's a pain to get started using is, but then the benefits of tooling start to compound.
HTTP2 won't replace GraphQL. Perhaps a set of libraries that use HTTP2 effectively. Even then I'd be surprised if it was a huge departure from GraphQL fundamentals - but you never know.
Batching almost seems like a nice-to-have.
query {
user {
first_name
last_name
}
settings {
debug
paid
}
}
could be translated into:GET /user/first_name GET /user/last_name GET /settings/debug GET /settings/paid
And you could represent any gql query as a multiplexed http2 call. And you could then have the server use a persistent user scoped dataloader (or some other shared cache) to resolve all that data and respond to each of those queries.
That's roughly an isomorphism between graphql and http2.
If Backend have few data entities, or the requirements are extremely clear, your team is not likely to get the full spectrum of benefits.
If you have a large number of existing Backend data entities, or expect a large number to be created - GraphQL is a very handy spec. But if the Frontend/Product are EXPLORING how use the data, and unsure exactly how to best utilize the data types, OR they are supporting many permutations of APIs, GraphQL is a game changer. Write a python decorator to generate resolvers...
- and BOOM, Backend and Frontend will never have to negotiate over a rigid & novel API contract again.
The other stuff, like introspective documentation, sophisticated Frontend state management, and so on are great conveniences, but are not the point.
As far as HTTP2 and Frontend goes, I'm excited as it solves a fundamental networking problem. And theoretically saves us from having to bundle. But this is not what I personally consider a big Frontend problem.
In most large webapps with network-connected components, you don't want each component to make a discrete network call and pump its data straight into the component. Often you will want to use the response and update a global state, to ensure nothing is out of date. This encourages you to colocate your network logic, with some facilities for this. The GraphQL ecosystem ticks this box. Additionally network requests are a complicated flow, due to APIs having different semantics, needing to shunt value objects through promise/callback chains and the need to covering various edge cases. This encourages codification of network logic, which again, GraphQL does a great job of.
This is of course quite complicated stuff, and if you don't need the Frontend magic - you can just put your GraphQL query on a fetch, and use it like a REST endpoint.
And of course - if you don't really need the spec, I'd say think very hard before adding GraphQL.
That said, big fan of HTTP2 (although last I looked, the perf envelope created by plotting no. of connections against speed, the shape told me "don't rely on this yet").
Majority of the latency/bandwidth wins can be achieved with a well architected jsonapi. This should not be your only reason for choosing GraphQL.