4 ms·
What is the benefit of every request being POST? This makes caching a harder problem to solve. Also, why is every status code 200 even in the event of an error
by throwaway413 4y ago
What is the benefit of every request being POST? This makes caching a harder problem to solve.
Also, why is every status code 200 even in the event of an error? They want you to pass an error key in your payload and have your client be processing the payload to understand the status of the response. Why are we reinventing the wheel here, for what benefit? GraphQL had some really appealing concepts going for it like the whole querying a single source of truth for multiple data sources, and only getting the data you need. But in practice, the benefits do not seem to outweigh the costs.
- wollsmoth 4y agoThis confused me too, working on the client side. But part of the benefit of gql is you can do multiple queries in one call. Any or none of those could fail.
- throwaway413 4y agoPlaying devils advocate here: Is the status code query specific or request specific? If I have a resolver that can handle multiple queries, does it matter if one or more queries internally fails? Doesn’t that mean the request was either degraded or failed entirely? Seems like extra overhead for the frontend when the queries are just a means to data which is generally parsed and validated anyways, so aren’t query-level status within a single request sort of redundant to a frontend? IMO status code should be request level, but I can see the reasoning you’re presenting about query-level. Interesting thought.
- giaour 4y agoA common scenario where a partial failure may occur is throttling. If you have a client that is permitted to perform 10 query per second and they submit a GraphQL request with 11 queries, the server is within its rights to return the results of the first 10 queries and an error for the 11th. This would allow the client to only retry the 11th query rather than all 11 (which, if throttling were enforced at the request level, would always result in a 429 response).
- throwaway413 4y agoInteresting, I see how that would not be as easily replicated with traditional REST. You would either need a bunch of requests or your client would need to be intimately familiar with the API. This leads me to think GQL has some benefits when used for semi-public/cross-team consumption (as opposed to a tight relationship between server and client or more monolithic apps), as there is more “opinion” in place by design to allow clients less familiar with the intricacies of the API to still use it efficiently. This is also furthered by another commentor pointing out the cross-protocol capability of GQL, as maybe different teams or companies integrating your API may have different needs in that way. Thanks for the info!
- striking 4y agoYou can use GET. https://graphql.org/learn/serving-over-http/#get-request https://graphql.org/learn/serving-over-http/#get-request That being said, caching needs to be done at the resolution layer rather than the request layer. Under REST, APIs are generally modeled as returning individual objects or lists of one kind of object, which makes requests a reasonable thing to cache. Under GraphQL, each resolver returns a different type of content, and the mixed bag of content means that there should probably be different cache policies and invalidation for each kind of data provided by each resolver. The status code being 200 even though your query is wrong or failed to correctly return data makes sense for the same reason. If you got a 500 because one field failed to correctly resolve, but the rest of the query was fine, the 500 is only telling you that something went wrong without letting you know exactly what it is. In GraphQL, we should save the status codes for request-level network issues rather than semantic issues with the request or the response.
- throwaway413 4y agoSure you can query over GET but to a single endpoint - so no ability to utilize built in browser caching for any requests you want to optimize unless you offload them from graphql. As for the 500, you can pass error details in the payload just as GraphQL would return as well, so sure you can get specifics of what went wrong. There’s clearly value in GQL for specific use cases but IMO it’s often an early over-optimization that shouldn’t encapsulate your entire data layer until you actually need it for reasons and not just to stay bleeding edge.
- TurningCanadian 4y agoYou can query multiple endpoints and have the server return the most restrictive cache time. https://www.apollographql.com/docs/apollo-server/performance/caching#calculating-cache-behavior https://www.apollographql.com/docs/apollo-server/performance...
- striking 4y agoMy point was that request level caching basically doesn't make sense for GraphQL anyway. I feel like you haven't replied to that point. And if you're reading the error details from the payload anyway, why bother with setting the error code when it has another, request-level, meaning? Not sure how any of this proves GQL is a premature optimization when caching could just as well be considered a premature optimization.
- TurningCanadian 4y agoGraphQL itself doesn't care whether it arrives over GET or POST. That's an implementation decision. The main problem is the limit on GET query length in some browser and server combinations. There are ways around that though. Example workaround: https://www.apollographql.com/docs/apollo-server/performance/apq/ https://www.apollographql.com/docs/apollo-server/performance...
- throwaway413 4y agoYep, the limit was a big piece of this issue and I forgot that detail. And nice, I’ll have to look into that! Thanks for this info, good to know.
- giaour 4y agoGraphQL treats HTTP as a dumb pipe. All semantically relevant information is encoded in the GraphQL messages, and none of the HTTP metadata is relevant to the query posed by the client or the response returned by the server. In theory, this allows the same processor to be used over alternative transport mechanisms and paradigms (e.g., over MQTT or Kafka topics) without adapting the messages themselves to the transport.
- throwaway413 4y agoNice, that’s a cool benefit, good point.
- gavinray 4y ago> "In theory, this allows the same processor to be used over alternative transport mechanisms and paradigms (e.g., over MQTT or Kafka topics) without adapting the messages themselves to the transport." This is something that doesn't get mentioned often/a lot of people don't grasp. It's transport agnostic, and this means you can do GraphQL over high performance transports if you have the requirements. Recent HN top post by Dan Luu: "In defense of simple architectures" discusses how they do this https://danluu.com/simple-architectures/ https://danluu.com/simple-architectures/ > "Some areas where we’re happy with our choices even though they may not sound like the simplest feasible solution are with our API, where we use GraphQL, with our transport protocols, where we had a custom protocol for a while, and our host management, where we use Kubernetes. For our transport protocols, we used to use a custom protocol that runs on top of UDP, with an SMS and USSD fallback, for the performance reasons described in this talk. With the rollout of HTTP/3, we’ve been able to replace our custom protocol with HTTP/3 and we generally only need USSD for events like the recent internet shutdowns in Mali)." > "As for using GraphQL, we believe the pros outweigh the cons for us:"
- ojkelly 4y agoYou can combine multiple queries into one request in such a way that transport layer caching just isn’t effective. If you’re making a content and read heavy website, you can run GraphQL over GET, and cache traditionally. The spec says nothing about the transport layer itself. Why return 200 for a request, when part of it failed? Separation of concerns. Network layer errors are one thing, application layer errors are another. They require different resolutions. With a network layer issue, you could retry, or perhaps you need to fetch a new access token then retry. For application layer issues, say you request data on 4 different entities, but the service for one of those types is down. Should you chuck out the whole request, or return everything and something like a Problem or Error type for the failed one? Perhaps you tried to access a field you don’t have permissions for, or require elevated permissions. Should you fail the whole request, or return an error on the field itself, allowing you to inform the user what you need them to do to continue? The point is precisely that the client processes the error closest to where it’s relevant. This works especially well with component based rendering.