6 ms·
I am curious if anyone went to GraphQL without regrets?
by etaty 10y ago
I am curious if anyone went to GraphQL without regrets?
- e1g 10y agoWe've been using GraphQL for everything since late 2015. All recent code is GraphQL-first, and all old code is proxied by a GraphQL layer in front of it. Our application helps BigCos to understand if they pay people fairly and to run smart pay reviews. It's a relatively small codebase, ~100k LOC, but it's essential complexity is in managing and connecting dispersed data about employees and markets. GraphQL allows us to represent the natural links within this data, then the app frontends can present whatever business information is helpful in that page/sidebar/widget/card without separate endpoints. With REST, we had the same problems with every feature: over/under-fetching, can't express relationships well, and can't evolve the schema easily. When we tried to work around these issues (e.g. "v2?fields=a,b,c"), we ended up with a poorly implemented subsection of GraphQL that's not benefiting from Facebook's experience. To compare to the world of databases, I view REST as a Key-Value protocol and GraphQL as an SQL with joins and functions. If all you need is to lookup a document, don't overcomplicate it. But if you need to express relations, you don't want to do that in userland. The only advantage of REST is using a widely known standard with rich tooling and well-published "best practices" (that just try to work around REST limitations).
- daliwali 10y agoREST describes relationships very well, via hyperlinks. You navigated to this page via a hyperlink. If your API doesn't do that, it's not REST, this is what people usually mean when they point out that an API isn't complying to the REST style.
- justinsaccount 10y agoREST describes relationships just fine. Now return a list of 100 documents that each have a list of related comments. Your client just needs to request GET /documents GET /documents/1/comments GET /documents/2/comments GET /documents/3/comments GET /documents/4/comments GET /documents/5/comments .. GET /documents/99/comments GET /documents/100/comments Easy, right?
- daliwali 10y agoEasy mode: GET /documents?include=comments Think of how this can be done on a web page. The documents page has a link to follow, "include comments", which links to "?include=comments". The exact query doesn't matter, what's important is that a client can discover new information without needing any out-of-band information.
- e1g 10y agoThat's where we started. The next natural step will be - "Thanks for the comments, now the user needs to sort them by votes/date, ok?" and the URL starts looking like a query anyway, so you're on the way of re-implementing GraphQL. Then do you send avatars/timestamps/changeflags for all comments, or only on main body in this endpoint? Now you have the over/under-fetching problems. The step after that will be "Oh there are 300 of them - I just want the top 3 comments first, and a pager for the rest ok?" and you simply can't do that with the structure REST mandates.
- daliwali 10y ago>the structure REST mandates. There is no structure that REST mandates, if there were it would be a specification and not an architectural style. There is nothing that says that you can't query for that: GET /comments?sort=votes&limit=3 The exact string doesn't matter, what matters is the client can discover this. How HTML does this is by generating query parameters based on form inputs.
- e1g 10y agoREST limits my knowledge only to the primary key of the relationship. Given a trivial question like "here's a user, I need her friends and their countries of birth" and the REST answer is a separate endpoint or an O(n) operation on the client because these are _separate resources_. You want the country flag too? I'm sorry, I can't support that requirement. With GraphQL, it's - user(handle: "daliwali") { name, friends { country { name, population, flag } } } No separate endpoint. You want to show to the client how many dogs those friends have, and if any of them play frisbee? No problems, and no backend engineers involved. This is why I said REST is a key-value protocol like in redis. With redis you can either embed a small objects (which is not a relationship) or keep a PK of the relationships (which means many queries). The more consumers your API has, and the higher the latency, the more expensive either of those choices becomes.
- daliwali 10y agoYou are correct that in a REST system, every resource has a "primary key", that is the URL. Where you are wrong is that REST doesn't mandate that a resource can only be accessed by its "primary key". There is nothing stopping me from requesting the following URL: GET /users/daliwali?fields=name&include=friends,friends.country Any client would be able to follow that link and get something out of it, whether it's JSON or HTML, without needing specialized tooling such as a GraphQL client. A hyperlink makes that query widely accessible and interoperable with any HTTP client.
- fixermark 10y agoWe're reasoning about a simple case, however. GraphQL is recursive, and HTTP parameters are generally not. You can use them to wrap a recursive language, but at that point you're just using the URL as a transport layer for the recursive language, and if the language is expressive enough it won't fit in a GETtable URL anyway... Past a threshold of complexity, you get into wanting that GraphQL client.
- daliwali 10y agoIn reply to fixermark, there is also nothing stopping you from very complicated queries in REST. There is not even a requirement that the server must respond immediately. For example I could request: POST /queries With some raw database query as the payload (please don't actually do this) and the server could respond with HTTP 202 Accepted, meaning that it's going to take some time to process, meanwhile check back at the URL in the Location header when it's finished. REST does not mandate any upper bound on complexity, that's up to you to decide.
- ako 10y agoAny idea how it compares to oData?
- e1g 10y agoSorry, no experience with oData so can't give a useful comparison. One obvious difference is that GraphQL requires a structured query, which will always guarantee the structure of the response data. It's like static typing for business data objects. oData seems to embrace REST, so when I request a resource /person/james I have no assurances about what the response will look like. What fields are present? Is "email" a string or an array of strings? What's deprecated? RTFM. GraphQL is explicit so I know exactly what data is used in what views - makes change and debugging that much easier.
- lenkite 10y agoOData requests and responses have schemas, so you definitely have assurances on the field types. You _do_ know that email is a string or array of strings. http://docs.oasis-open.org/odata/odata/v4.0/odata-v4.0-part3-csdl.html http://docs.oasis-open.org/odata/odata/v4.0/odata-v4.0-part3...
- netghost 10y agoDo you expose your GraphQL endpoint to customers, or just use it internally?
- e1g 10y agoWe expose GraphQL to two high value customers, but the pains of having a stable public API are so great that I wouldn't recommend it to any startup without a damn good reason.