I'm only familiar with REST and not GraphQL, but this sounds interesting. Just from the name GraphQL sounds like a query language -- how can one do operations that change state (i.e., analogous to PUT/POST) rather than just query it? Thanks.
It’s a QL in the sense that it accepts a client specified schema, that looks how the client wants the data to be returned.
How does it mutate then? SQL can mutate, I’m not sure why this would be any different. Basically, like SQL’s UPDATE, and INSERT, GQL can have “methods” associated with parts of the schema.
REST semantics are a distraction. The best possible outcome of REST is when developers are encouraged to consider the concept of "idempotency" when they stumble upon the technical definition of the "PUT" verb. Everything else is line noise.
GraphQL has a schema with types. It makes it very straightforward and approachable for all developers to reason about what an API should deliver up-front, and also easy to reason about what is and is not a breaking change. Automatic validation of queries against the schema also saves massive amounts of time in writing validation logic.
There are still things that could be better with GraphQL. The query language is... interesting. The whole thing is still very client-server asymmetric -- look at a client query syntax versus the schema syntax you'll use on the server side for three seconds and you'll immediately and viscerally know what I mean -- and that strikes me as disappointing in this age. It's still very easy for developers to fall into mental quicksand which causes them to make many individual requests even when GraphQL would let them batch things up into one. And so on.
But overall: yes, working on a GraphQL stack is an awesome experience compared to going it alone with REST and JSON and crossed fingers.
Fundamentals vs. changing tech. "Idempotency" as a concept is fundamental. Which header means what for some cache layer is not. REST unavoidably has a lot of things in it that are changing tech. (Nominally, it has a lot of fundamentals in it too, but per the other REST discussion on the homepage, which fundamentals it encompasses seems to vary on a person-by-person basis.)
I tend to write publicly facing APIs so this conversation is colored a little by that. An internal API or Microservice is a different story.
I don't think it is either of. I use both. In the same API. The two are largely compatible.
All REST APIs can be modeled in RPC style APIs and that's no different with GraphQL.
I've done APIs where I have a GraphQL facade in front of REST and REST Facades infront of GraphQL by having all my REST endpoints be two lines
1. Graph QL query
2. Format result as REST
That first like maps to a graphQL query and the second one can be standardized for all your REST endpoints.
I tend to like REST in-front of GraphQL better since it allows for some performance optimizations when you know ahead of time all the data you need to grab.
And since GraphQL can be mapped to classes you could also just skip the GraphQL query compile and use the classes directly from your REST with only a few more lines of code.
Overall I like GraphQL a lot because it allows the frontend to make less round trips to the server and makes it easier to exclude data you don't want (which helps when data is large). Json:API tries to solve some of this with includes, related, and fields but it doesn't quite allow as much expressiveness as GraphQL.
For read and search operations I typically rate limit per machine based on probability that machine gets hit using machine signature. And as a secondary (more leniant metric, just IP).
I don't centrally track rates unless a signature comes close to 1/N the limit where N is the number of nodes. At which point I will talk to the other nodes Peer to Peer.
Can still be abused but works pretty well most of the time. It also doesn't work if you have a number of nodes that is approximating your rate limit because if you do, you hit 1/N on request #1.
For that reason I tend to choose pretty lenient rate limits (call it one request a second with bursts in a 5 minute window)
For write I use OAuth2 with bearer tokens being a JWT token with a short expiry. I only need to maintain a blacklist of invalidated tokens for the length of the expiry. Rate limiting would work the same way as reads.
Mostly, NOTE: I'm using python/django/graphene server side and apollo client side.
I love how flexible it is for client developers and because the great client side libraries it helps to eliminate a ton of boiler plate code on the client side.
My biggest complaint has been "lost" exceptions and caching.
Because it's possible for an exception to be thrown server side on one field while the other ones succeed I've been plagued with hard to monitor/find errors. I ended up writing a shim to parse the response in an attempt to get more insight into #errors / fields (this has also been really helpful for monitoring slow queries in new relic since all requests go to the same endpoint which breaks a ton of APM monitoring).
My other issue has been around caching, in apollo there are ways to say "don't use the cache for this request", but it's not to give an object a cache ttl. My app allows users to search for events that are happening near them right now, and I've run into several issues where apollo decided that an event from yesterday should be added to a result. It happened frequently enough even with queries that included times as an argument that I ended up basically implementing a "middleware" between what apollo gives back and the component, which felt really ugly.
I've never looked at graphene before (I've stopped spending time learning about each fad) but this really looks like it solves a real problem I've experienced. Definitely going to try it out.
you should take a look at the caching policies (fetch policy) apollo client provides as well as the error policy. neither are easy to find
for the error policy, you basically control the behavior (for each client instance or each request) when a request is considered failed. none, ignore and all. [1]
fetch policy allows you immense control over caching. this all depends on what you're doing but in some instances it can even make sense to never cache any requests, depending on how you application is structured. the docs are hard to google for this, but here's a link for you [2]
So I understand that I can use the cache, not use the cache, or use the cache and always go over network for the entire request but that's all client side. GraphQL in general lacks a good answer for object level caching (so in my case I just filter things out before they make it to the component). It also lacks a solution for the server to indicate to the client how long something should be cached (like you would with cache headers or Etags)
It's just really annoying that I have a ton of queries that return lists of objects, where each object has an easily known expiration time, and there's no way to say, "cache this result but remove the elements that have expired". I can't even say, "cache this list until X time", which would be very easy in a RESTful environment. I know there are extensions to support caching but none of them are universal yet. I'm hopeful that the community will land on an answer for object level cache expiration.
Regarding monitoring, I would recommend to check out Apollo Engine if you haven't already. Basically middleware on the server side that injects error and performance info into the extensions object of the response which is then sent to them and presented in a nice UI.
I’ve played with it a little, and I may resort to creating a proxy node app that reads through to the python app exclusively so I can get better monitoring.
I just have to chime in and thank you for all the hard work with Graphene! You have almost become a meme at the office, we're looking at the latests RC's at the office and talking about what Syrus might be up to this time :-). As a side note, I'm happy to read about Quiver and I hope it becomes a sustainable business!
The productivity gains from having a client-server interface that is dead simple to reason about more than made up for the initial investment cost. We can refactor API schemas without worrying about breaking existing client code. We also saw performance gains from saving on network round trips.
I'd agree with this sentiment, on the backend, it isn't really easier and it's not really harder either. You end up dealing with different problems than with REST (as noted, different types of performance problems, more issues with error handling have been my biggest two).
The frontend developers see the biggest improvements, they have one endpoint to worry about and using a library like Apollo makes things really nice.
Overall, I think the improvements are worth it, especially when working on internal APIs.
my experience is just ok. as someone here puts it, great for frontend devs but bad for backend devs.
if you have db schemas on the backend if using orm, get ready to duplicate them again for graphql.
and on the frontend, get prepared to write out every songle fields you need from the backend. i can imagine it may be brutal for those who have a lot of changes in their schemas.
my conclusion is that, since im a fullstack who does both frontend and backend, i feel myself getting a bit more fatigued than when i was doing rest style api. i find myself wanting rest time to time, esp at times i dont feel like writing out all the fields i need back that i cant remember off top of my head.
> and on the frontend, get prepared to write out every songle fields you need from the backend. i can imagine it may be brutal for those who have a lot of changes in their schemas.
Wouldn’t you need to do this in some form anyway (since those fields would be displayed or used in some way)?
Right - what I meant was more like when you get some data you probably want to display it in the UI and would already be doing something like ‘Hi ${user.name}, your age is ${user.age}’. This is affected by schema changes irrespective of the way the API is invoked.
Not at all (we rolled our own back end). The added complexity of building queries to join our API ended up creating such a quagmire of SQL that any dev coming in will basically have to learn our own custom ORM.
As a frontend dev, I had a positive experience with one service because the backend was far more willing to add new query options. The much publicized "only get what you ask for" part was largely irrelevant.
I am, however, unsettled at the prospect is losing all the built in network and browser caching for idempotent calls (mostly I'm unsettled because no one else seems to seriously consider the issue - it may end up too small to matter, but I dont trust that anyone else here has honestly evaluated it).
Another poster mentioned the issue with partial errors, which sounds like something else that will not get the upfront attention it deserves, while not being an immediate dealbreaker. Add in to that how to manage deprecation of particular query statements as they can no longer be distinguished as distinct endpoints.
My other concern is how much magic frontend libraries provide. This magic looks great if your app is nothing more than input/output over CRUD calls, but sounds very brittle if your app has client side logic (and while perhaps a webapp should ideally avoid that, other services can also be clients.)
So far I have concerns but not concrete problems, I just worry that we wont be able to confirm the severity until we've already invested and committed, particularly when our initial adopters are so enthusiastic. At the same time I don't want to be the guy unwilling to change and adopt new things.
We found our sweet spot in terms of enabling the flexibility of front-end devs experimenting and defining their own queries while maintaining cacheability. During development, front-end devs use the Graphiql endpoint to play around with the data and figure out exactly what they want. Once that's settled, we turn it into a persisted query that is stored on the server and keyed by a unique ID that the client apps use in production instead of the raw GraphQL payload. You add a small amount of overhead for the coordination to create the persisted queries, but we're considering even building a self service process in the future.
Is it fair to say that your system relies, more or less, upon one server change per client request change/new request type? Doesn't sound like a dealbreaker necessarily, but I thought this was a big part of the problem GraphQL was supposed to solve.
You're going to get responses from people who have invested a considerable amount of time in something they already had plans for (a "sunk cost") so I'm not sure you will get the sort of information you are after here.
Also, many people who have only recently adopted GraphQL, as it is relatively new. These people will not have the long-term experience necessary to assess GraphQL in hindsight.
There is an advantage to making technology decisions behind-the-curve, choosing mature, "battle-tested" technology, even if it means overlooking some known warts, and missing out on what's "hot". We can call this being a "late-adopter". I am most interested in N-years-later perspectives where N is around 3 or more.
I'll be the voice of someone who is actively implementing GraphQL for the first time.
We were mid-way through our project before realizing GraphQL might be a better fit for our use case so we paused for a week to play around with it and see if we could stand up something inside of our project that made sense.
GraphQL felt very "plug and play" to us. Aside from having to re-work some validation to fit into GraphQL's idea of mutations, we were mostly able to drop our existing models and logic directly in and see it working right away.
Having built very well defined REST APIs (and SOAP before that) for years, the flexibility that GraphQL offers made me feel a bit "uneasy" at first but I have come around to appreciating how much freedom it gives the front-end to only request the data they need.
I'm usually the type to shy away from flashy new doodads and stick with what I know is safe+reliable, especially in an enterprise environment, but as the project continues I'm feeling more and more confident in our choice. I suppose only time will tell though.
GraphQL has magic record-level caching that I do not understand but somehow appears to sometimes work and sometimes doesn't (but using the default apollo-client, you can't easily turn it off)
Sure, but as always in software that's still better than the speculations of people who have no experience using it but think they can make an informed comparison.
Absolutely. Before GraphQL we were making a monumental effort to build a REST API. After deliberating on exactly what REST was and how we’d represent a few red haired resources, we were spending a lot of client time fetching deep trees through resource links. When we moved to GraphQL it solved a lot of the administrative and philosophical headaches and considerably reduced the number of connections, wasted data, and made our client code so much simpler through easily grokked queries. Highly recommmend GraphQL to anyone.
I should also mention that we finished our migration ahead of schedule. It was super easy to have GraphQL alongside REST, and we quickly iterated on converting each rest call to graphQL.
We’ve also found that on boarding our new hires is much simpler. There’s a lot of misinformation about REST, and we were having to retrain people, and when they wanted to see our schema we would then have to teach them swagger as well. With GraphQL we just send them to the official docs with our schema with is our single source of truth for the API and they come back a day later ready to go. Generally GraphQL being more standardized and centrally managed has been great from a training perspective.
We wrote our own server in C++. We also have a few smaller graphql endpoints running the official JS implementation on express. On the client side we are using relay modern.
Out of curiosity, what does "tech them swagger" entail? I was under the impression that most of it was automated and that it's more of a standard than an implementation.
Teach them Swagger? Do you mean to generate Swagger or to consume it? Because as far as clarity I don't think Swagger could be clearer, what with the interactive endpoint GUI and copy/paste curl commands and so on.
With a standard REST interface, you have to name all such combinations in advance. Possibly build custom code for each. With GraphQL, you specify them all at once, and are guided towards implementing code that will handle that. (There's no magic in GraphQL, of course, but the conceptualization alone can be useful. And if you're already in some particular ecosystem, they may have some localized magic you can use.)
You could just take your GraphQL backend and implement those specialized REST calls, sure, but then why not expose it?
There is a "standard" REST interface described in the paper on REST. There are a lot of rules/guidelines for a RESTful API but many API's don't follow them and tend to be a mix of REST and JSON RPC.
Not really. With REST, the server dictates the minimum requirements of the client. In GraphQL, the client dictates its own requirements, and the server is able to respond with no more and no less than what the client requires. Also REST necessitates multiple HTTP queries to fetch multiple resources. This is not a requirement of GraphQL.
> the client dictates its own requirements, and the server is able to respond with no more and no less than what the client requires.
The burden of dictating specs is just shifted around, and it seems the workload on the server side is bigger with h GraphQL (wider range of cases to handle).
Your graphql library will handle that for you. The server defines data as it knows, the client asks for data that it wants, and the library does the transform work.
What will the library handle ?
From my understanding it’s only the query parsing and the data filtering part. Correct me if I’m wrong.
You still have to do the data mapping, fetching everything from DB in a reasonable way, and make sure it all makes sense performance wise.
All of that will be needed for any API, but it seems to me GraphQL adds the uncertainty on how much data will be exchanged (lots of small queries ? a few big queries ?), what can be optimized, how will cache behave etc.
I remember a study on te github API on how some types of queries would make it crawl excessively. It fear it becomes a nightmare to try to cover for all the cases that can go wrong.
Yes, it handles data filtering, field renaming, etc, which turns out to be a big chunk of work if you're working on APIs to support multiple frontend experiences (the BFF pattern).
I don't know what your use case is, but it sounds like you should just try it, I can only say that for us (multiple FE experiences, pushing logic to backend), it's been very good. If you have a different usecase, ymmv.
Overall it acknowledges GraphQL's advantages, while warning that the data retrieval part shouldn't be done naively.
An excerp
> We note that this issue is somehow acknowledged by the Github GraphQL interface and, as a safety measure to avoid queries that might turn out to be too resource-intensive, it introduces a few syntactic restrictions [7]. As one such restriction, Github imposes a maximum level of nesting for queries that it accepts for execution.
However, even with this restriction (and other syntactic restric- tions imposed by the Github GraphQL interface [7]), Github fails to avoid all queries that hit some resource limits when executed
When I was a freshman in HS, a friend and I were playing Betrayal at Krondor late one night, just talking randomly about the stupid things that nerdy freshman talk about. At some point he just turns to me with this weird look on his face and says, completely ernest, "I just realized... I'm literally a red-headed step-child."
There was this long pause and then we both just started laughing.
File under: shit that doesn't happen any more because nobody plays single-player games side-by-side, late at night any longer.
"We moved to GraphQL because things were bad, and now things are good. GraphQL is amazing".
I don't want this to come off as a personal attack (and I apologize if it does), but your comment contains absolutely no information whatsoever regarding a specific situation/use-case, nothing from which the rest of us can formulate our own opinions on the REST/GraphQL discussion.
My interpretation was: “We did ReST trying to follow dogma and ended up with a badly designed API that din’t fit our needs. Switching to a tech with less dogma on how to do things led us to a better API-design with a better fit” (inferring some context from my own experience here, could be wrong)
In the end I would guess you can end up in a similar place with a standard fetch-json design if you just ignore ReST dogma and focus on getting the API into a shape that fits the need.
Not saying ReST dogma is necessarily wrong, or bad, just that it’s easy to get lost in design when focusing more on learning others design than understanding the actual problem you’re trying to solve.
For reference we’re switching from the non dogmatic get/post requests over http to graphql and it’s been equally good for us too for different reasons.
Also consider that a second implementation of a system is always going to be cleaner than the first because you actually know what you need to do. This is an inherent bias inherent to any GraphQL migration story.
This sounds a little over-the-top. There are certainly cases where REST would be the better recommendation over GraphQL. I have no idea what your specific requirements were but if building a REST API was a 'monumental effort' then GraphQL was probably a good choice for you. That does not mean that in all cases GraphQL > REST.
In my opinion, I think GraphQL offers enough over REST to be a total replacement. Especially now that the vast majority of clients are mobile, IoT, etc, the benefits of GraphQL make outlier cases rare. This is natural, the GraphQL authors had the benefit of hindsight. I'm not disparaging roy's work, it's a stepping stone. But REST as a design pattern was rarely implemented as he envisioned it. When it was done correctly, you end up with much of the same benefits as GraphQL.
The problem with REST is largely the people who look at it blindly as "thing that makes the CRUD go" instead of as a methodology of how to effectively use HTTP verbs and designing URIs that make sense.
So I guess my question is, why would I use GraphQL over, say, the Swagger tool suite? Swagger and the OpenAPI spec defines a way of doing REST that best fits both what Roy Fielding meant for REST but also fits IDE and tool automation systems.
There are HUGE benefits for our client developers with GraphQL. Like being able to select as much or as little as a particular view/component/whatever requires and no more. GraphQL from a front end or mobile POV makes your api more like a data store that it can interact with and query for it's needs, which makes app UI work much nicer.
There are also a ton of maintenance benefits, like for example if you add a field in GraphQL that's perfectly fine to not change the version because that break any existing calls, which is not always true with REST.
> There are HUGE benefits for our client developers with GraphQL. Like being able to select as much or as little as a particular view/component/whatever requires and no more.
That's not a unique benefit of GraphQL. Any HTTP based API can do this, regardless of how it's designed.
Some specifications even have it baked in (See: jsonapi.org).
> GraphQL from a front end or mobile POV makes your api more like a data store that it can interact with and query for it's needs, which makes app UI work much nicer.
Again, not unique to GraphQL.
> There are also a ton of maintenance benefits, like for example if you add a field in GraphQL that's perfectly fine to not change the version because that break any existing calls, which is not always true with REST.
> There are also a ton of maintenance benefits, like for example if you add a field in GraphQL that's perfectly fine to not change the version because that break any existing calls, which is not always true with REST.
Assuming you are using some from of Semantic Versioning, adding a field to a REST API should never break existing clients. Did you mean "removing" a field?
Yep, best decision. Both from a back-end experience (caching, performance, type safety) and front-end experience (flexible querying, great documentation, tracing, etc.)
There are stacks that can give you delicious sharing here. Clojure/clojurescript with Lacinia[0] for example could lead to something pretty terrific, as Clojure DB access is all immutable structs instead of activerecord-style stuff.
graphql-tag [1] is very close to automatic typing for TypeScript. It lets you import a `x.gql` file (or whatever suffix) that contains query text directly, and translates the contained queries into named input/output types and parsed query documents based on your schema.
It's great but it's not quite perfect for me: I'd prefer if it produced a function that accepts your query executor and inputs, and returns an observable of the result, and it doesn't work very smoothly with angular (especially 5+).
We have, so far, only made a GraphQL endpoint for internal use. It has been awesome for quickly finding things in a medium-complexity database schema (30 or so tables, bunch of different relationships). It has become my preferred way to quickly find things in the database.
That being said, there are cases where a join between ad hoc subqueries is the best way, and GraphQL doesn't really offer a way to do that (though I don't see why it wouldn't be possible). E.g. arbitrarily combining two GraphQL queries that return lists where some field in one is equal to some field in another.
But in terms of replacing REST, where you have to do all of that anyway, it is far and away the better option (for ad hoc querying, at least).
> a join between ad hoc subqueries is the best way, and GraphQL doesn't really offer a way to do that
I think you're supposed to create a "virtual" field on the left-hand object that represents a collection of the right-hand type of objects. The field can be parameterized if your join needs extra information. If you want pagination, the virtual field returns an intermediary object describing the cursor (sort order, offset).
Not someone who's moved to GraphQL, but still curious how people do load testing and such with GraphQL APIs. Do you log which queries are made, and then plan around that?
We decided against it. We’re in a java backend and GraphQL in Java with ORM is considerably problematic when trying to create efficient resolvers. We simply ran into one hurdle after another and we were finding ourselves in diminishing returns.
The concept is great, and if you write custom SQL queries for each resolver (if necessary), properly caching things that can be cached, and use the first class citizen programming language (JavaScript), then it seems GraphQL works wonderfully.
Trying to fit it into an existing ORM paradigm with respect to complex sub-collections, lazy loading, and efficient database querying, it just didn’t work out for us.
I think we will in time find someone cracking the code and creating a "requests" type library for graphql interaction. Either that or some graphql++ language will make things better. Maybe automatic/declarative DB integration? The concept of graphql is light years ahead of REST, but right now it basically requires server maintainers to implement half-baked query processors and solve problems that have been soloved since the 70s.
It's not impossible in Java but it does require a strong grasp of graphql-java's execution model and the DataFetchingEnvironment and associated classes.
We accomplish something similar to what you desire when querying our time series database via GraphQL.
The big difference between Java and Javascript when it comes to GraphQL is the amount of noise, tutorials and examples on the Javascript side far outweigh other options right now.
Javascript may be the "happy" path for now but I do hope that we see continued investment in Java/Scala/Ruby/Python/.NET etc as those implementations have the opportunity to be better architected and more performant that the reference JS implementation. The reference implementation uses a very simplistic execution model which for now has been copied almost verbatim into other languages but there is great potential for a proper query planner and optimisation layer at the GraphQL layer.
Disclaimer: I work at MDG on Apollo Engine (the backend of which is Kotlin utilising graphql-java).
Do you have a kotlin graphql library you'd recommend. I just started working on Kotlin with GraphQLJava. I saw graphql-kotlin, but that appears to have been updated like a year ago. I've been using graphql-spqr. Mixing kotlin and java in my projects, to get around the annotation bug.
I do agree on the noise and lack of tutorials. I'm getting ready to present on a GraphQL option. We don't want to use javascript. The tutorials for java are a bit cumbersome.
Agreed, there is a ton of potential for query planning an optimization.
These last months, I've been working non-stop in a blazing-fast GraphQL engine that beats the rest by an order of magnitude - https://graphql-quiver.com/
No. It cold have been that Relay the JS graphql implementation we used was too heavy handed, but our team never fully grokked what was going on. It wound up introducing a bunch of friction into our workflow, and we ultimately wound up removing it.
I had hoped that GraphQL would come along with a solution for 'live queries' - alas that seems to still be on the drawing board. Really looking forward to when 'send me a list, and any changes to that list, and merge them together' is a problem I don't have to put any thought into solving.
I'd like to add that correctly designed resolvers allow you:
- to control very easily who can fetch what where it's fetched (permissions)
- to fetch nested data when you need it without writing serializers
- to help your frontend team find what they are looking for without asking the backend team everytime
- mutations are a huge plus when it comes to standardization of your API too
FYI we're using it in production over a django backend (which comes with some drawbacks, since subscriptions == pushed updates are not perfectly implemented) with our react/apollo apps (web and native) and in my opinion the overhead lies surprisingly more in the frontend side (writing data connectors is longer, but way more explicit, than using rest queries returning json)than on the backend (where you just declare resolvers, a thing you don't even need to do in nodejs) and handle permissions.
One important thing to note: performance-wise, both in front-end when used with apollo, and in backend (you need to handle nested queries smartly) a good implementation of a REST api would probably be faster / lighter, but it should be largely enough for any web-app / web-service used by human beings ;)
Graphql and apollo add some overhead to your queries, both in your client and your API. And since you're still performing a POST query with each graphql query it's kinda logical to see that pure / well designed REST can outperformed graphql (if you know exactly what you want to return you don't have to run through the graphql schema / node / resolver to get the value your looking for)
>to control very easily who can fetch what where it's fetched (permissions)
This is a piece of GraphQL I haven't been able to get my head around. Could you elaborate or point me to a good explanation of how this is implemented? Everything I found when I looked into GraphQL previously was something like "you control access to individual resources in your business layer" but never explained how.
In order for GraphQL to return a result when you ask for field “foo”, you need to define a resolver function for that field. Whatever that function returns will be returned to the client.
Inside that function you can write any code you’d like, including permissions code.
as sgdesign said, you can write your own resolver function (which allows you to retrieve a particular field deep in the nested graph of graphql). It's very easy to create decorators to handle the usual permission cased on the field level.
Could you all tell about your stack, too ? Do we have to use NodeJS in order to get GraphQL working properly ? I'm aware of the libraries available for other languages, but NodeJS seems to be the only platform with proper support. I wonder if there is any Go developers building servers with GraphQL.
Is it common yet for public-facing APIs to be implemented with GraphQL? Is it feasible if you're trying to make it accessible and easy to use for casual developers?
GraphQL is great for the frontend, but moving to GraphQL involves both people and tech issues. Common mistakes made when using new technologies are made all over again.
* Watch out for bad implementation of the GraphQL API (this will definitely result in bad performance).
* Design the GraphQL schema that you want the user to see/perceive. Not every object or field in your database needs to be exposed via the API the way it is.
My workplace is currently moving a huge monolith into a bunch of manageable components. Each of these components has its own GraphQL endpoint. Using schema-stitching, these are being stitched together into one endpoint for API users.
As a result of our codebase, we've tried GraphQL in:
* Ruby (graphql-ruby) - WATCHOUT Relay arguments for connection fields are not exposed to the library user. So basically you have to implement your own Relay-compliant stuff if you need access to the pagination arguments from Relay. Also, documentation is broken.
* Python (graphene) - We've had no issues so far. We worked around it.
* Node.js (Apollo GraphQL) - OH MY BUTTERFLIES. So far, this is the ONLY library I have come across that is polished and has plenty of documentation.
* Elixir (Absinthe) - My coworker worked on this part. He did not complain. So I'm assuming he had no issues.
The "Learn * in a day" joke applies to GraphQL. As simple as GraphQL looks for the client-side, it is beast of a job to build a GraphQL backend that is optimized for production.
Servers-side implementation of GraphQL is not very well documented apart from hello-worldly examples. Most of the knowledge found online is about client-side usage.
Due to poor documentation/examples provided, ramping up people with GraphQL is hard. Most first iterations I've had to review were slower than our REST APIs because of unoptimized code. Sitting down for a few minutes solves that problem.
To ramp up people at work place, I ended up having to do this:
* Ask people to use the GitHub v4 API to checkout GraphQL.
* Make them build a GraphQL server for a blog app.
* Dive straight into whatever feature/API they would build.
* Review their work a few dozen times and show them optimization tricks.
My most valuable lesson: When in doubt, dig into the source of these libraries.
181 comments
[ 3.5 ms ] story [ 53.1 ms ] threadThe main disappointment is that input types are not nearly as expressive as output types.
How does it mutate then? SQL can mutate, I’m not sure why this would be any different. Basically, like SQL’s UPDATE, and INSERT, GQL can have “methods” associated with parts of the schema.
For a new product, yes (so far).
REST semantics are a distraction. The best possible outcome of REST is when developers are encouraged to consider the concept of "idempotency" when they stumble upon the technical definition of the "PUT" verb. Everything else is line noise.
GraphQL has a schema with types. It makes it very straightforward and approachable for all developers to reason about what an API should deliver up-front, and also easy to reason about what is and is not a breaking change. Automatic validation of queries against the schema also saves massive amounts of time in writing validation logic.
There are still things that could be better with GraphQL. The query language is... interesting. The whole thing is still very client-server asymmetric -- look at a client query syntax versus the schema syntax you'll use on the server side for three seconds and you'll immediately and viscerally know what I mean -- and that strikes me as disappointing in this age. It's still very easy for developers to fall into mental quicksand which causes them to make many individual requests even when GraphQL would let them batch things up into one. And so on.
But overall: yes, working on a GraphQL stack is an awesome experience compared to going it alone with REST and JSON and crossed fingers.
It's always weird to see this type of thing on HN. How anyone can call the way the web works "line noise" is baffling to me.
A good summary
I don't think it is either of. I use both. In the same API. The two are largely compatible.
All REST APIs can be modeled in RPC style APIs and that's no different with GraphQL.
I've done APIs where I have a GraphQL facade in front of REST and REST Facades infront of GraphQL by having all my REST endpoints be two lines
1. Graph QL query
2. Format result as REST
That first like maps to a graphQL query and the second one can be standardized for all your REST endpoints.
I tend to like REST in-front of GraphQL better since it allows for some performance optimizations when you know ahead of time all the data you need to grab.
And since GraphQL can be mapped to classes you could also just skip the GraphQL query compile and use the classes directly from your REST with only a few more lines of code.
Overall I like GraphQL a lot because it allows the frontend to make less round trips to the server and makes it easier to exclude data you don't want (which helps when data is large). Json:API tries to solve some of this with includes, related, and fields but it doesn't quite allow as much expressiveness as GraphQL.
Out of curiosity, how do you secure your public-facing APIs and how do you authenticate/rate-limit users?
I don't centrally track rates unless a signature comes close to 1/N the limit where N is the number of nodes. At which point I will talk to the other nodes Peer to Peer.
Can still be abused but works pretty well most of the time. It also doesn't work if you have a number of nodes that is approximating your rate limit because if you do, you hit 1/N on request #1.
For that reason I tend to choose pretty lenient rate limits (call it one request a second with bursts in a 5 minute window)
For write I use OAuth2 with bearer tokens being a JWT token with a short expiry. I only need to maintain a blacklist of invalidated tokens for the length of the expiry. Rate limiting would work the same way as reads.
I love how flexible it is for client developers and because the great client side libraries it helps to eliminate a ton of boiler plate code on the client side.
My biggest complaint has been "lost" exceptions and caching.
Because it's possible for an exception to be thrown server side on one field while the other ones succeed I've been plagued with hard to monitor/find errors. I ended up writing a shim to parse the response in an attempt to get more insight into #errors / fields (this has also been really helpful for monitoring slow queries in new relic since all requests go to the same endpoint which breaks a ton of APM monitoring).
My other issue has been around caching, in apollo there are ways to say "don't use the cache for this request", but it's not to give an object a cache ttl. My app allows users to search for events that are happening near them right now, and I've run into several issues where apollo decided that an event from yesterday should be added to a result. It happened frequently enough even with queries that included times as an argument that I ended up basically implementing a "middleware" between what apollo gives back and the component, which felt really ugly.
for the error policy, you basically control the behavior (for each client instance or each request) when a request is considered failed. none, ignore and all. [1]
fetch policy allows you immense control over caching. this all depends on what you're doing but in some instances it can even make sense to never cache any requests, depending on how you application is structured. the docs are hard to google for this, but here's a link for you [2]
[1] https://www.apollographql.com/docs/react/features/error-hand...
[2] https://www.apollographql.com/docs/react/api/react-apollo.ht...
It's just really annoying that I have a ton of queries that return lists of objects, where each object has an easily known expiration time, and there's no way to say, "cache this result but remove the elements that have expired". I can't even say, "cache this list until X time", which would be very easy in a RESTful environment. I know there are extensions to support caching but none of them are universal yet. I'm hopeful that the community will land on an answer for object level cache expiration.
This is quite annoying because the server never throws a 500 error so the normal logging doens't kick in.
The productivity gains from having a client-server interface that is dead simple to reason about more than made up for the initial investment cost. We can refactor API schemas without worrying about breaking existing client code. We also saw performance gains from saving on network round trips.
There are some quirks (error handling), performance issues (e.g. fixing n+1 queries) and DOS concerns, but again, it isn't all that bad.
(we're using rails/graphql-ruby on backend | react/relay on frontend)
The frontend developers see the biggest improvements, they have one endpoint to worry about and using a library like Apollo makes things really nice.
Overall, I think the improvements are worth it, especially when working on internal APIs.
if you have db schemas on the backend if using orm, get ready to duplicate them again for graphql.
and on the frontend, get prepared to write out every songle fields you need from the backend. i can imagine it may be brutal for those who have a lot of changes in their schemas.
my conclusion is that, since im a fullstack who does both frontend and backend, i feel myself getting a bit more fatigued than when i was doing rest style api. i find myself wanting rest time to time, esp at times i dont feel like writing out all the fields i need back that i cant remember off top of my head.
Wouldn’t you need to do this in some form anyway (since those fields would be displayed or used in some way)?
I would consider this a weakness of ORMs, not of GraphQL.
As a frontend dev, I had a positive experience with one service because the backend was far more willing to add new query options. The much publicized "only get what you ask for" part was largely irrelevant.
I am, however, unsettled at the prospect is losing all the built in network and browser caching for idempotent calls (mostly I'm unsettled because no one else seems to seriously consider the issue - it may end up too small to matter, but I dont trust that anyone else here has honestly evaluated it).
Another poster mentioned the issue with partial errors, which sounds like something else that will not get the upfront attention it deserves, while not being an immediate dealbreaker. Add in to that how to manage deprecation of particular query statements as they can no longer be distinguished as distinct endpoints.
My other concern is how much magic frontend libraries provide. This magic looks great if your app is nothing more than input/output over CRUD calls, but sounds very brittle if your app has client side logic (and while perhaps a webapp should ideally avoid that, other services can also be clients.)
So far I have concerns but not concrete problems, I just worry that we wont be able to confirm the severity until we've already invested and committed, particularly when our initial adopters are so enthusiastic. At the same time I don't want to be the guy unwilling to change and adopt new things.
There is an advantage to making technology decisions behind-the-curve, choosing mature, "battle-tested" technology, even if it means overlooking some known warts, and missing out on what's "hot". We can call this being a "late-adopter". I am most interested in N-years-later perspectives where N is around 3 or more.
We were mid-way through our project before realizing GraphQL might be a better fit for our use case so we paused for a week to play around with it and see if we could stand up something inside of our project that made sense.
GraphQL felt very "plug and play" to us. Aside from having to re-work some validation to fit into GraphQL's idea of mutations, we were mostly able to drop our existing models and logic directly in and see it working right away.
Having built very well defined REST APIs (and SOAP before that) for years, the flexibility that GraphQL offers made me feel a bit "uneasy" at first but I have come around to appreciating how much freedom it gives the front-end to only request the data they need.
I'm usually the type to shy away from flashy new doodads and stick with what I know is safe+reliable, especially in an enterprise environment, but as the project continues I'm feeling more and more confident in our choice. I suppose only time will tell though.
We’ve also found that on boarding our new hires is much simpler. There’s a lot of misinformation about REST, and we were having to retrain people, and when they wanted to see our schema we would then have to teach them swagger as well. With GraphQL we just send them to the official docs with our schema with is our single source of truth for the API and they come back a day later ready to go. Generally GraphQL being more standardized and centrally managed has been great from a training perspective.
I mean, you could have also just done this with what you had.
You could just take your GraphQL backend and implement those specialized REST calls, sure, but then why not expose it?
... OData ...
It's a thing.
There's no such thing.
> you have to name all such combinations in advance.
No you don't.
> Possibly build custom code for each.
As much as any other API.
The burden of dictating specs is just shifted around, and it seems the workload on the server side is bigger with h GraphQL (wider range of cases to handle).
Am I missing something ?
> REST necessitates multiple queries
This is a self imposed limitation at best
You still have to do the data mapping, fetching everything from DB in a reasonable way, and make sure it all makes sense performance wise.
All of that will be needed for any API, but it seems to me GraphQL adds the uncertainty on how much data will be exchanged (lots of small queries ? a few big queries ?), what can be optimized, how will cache behave etc.
I remember a study on te github API on how some types of queries would make it crawl excessively. It fear it becomes a nightmare to try to cover for all the cases that can go wrong.
I don't know what your use case is, but it sounds like you should just try it, I can only say that for us (multiple FE experiences, pushing logic to backend), it's been very good. If you have a different usecase, ymmv.
It was this study: http://olafhartig.de/files/HartigPerez_WWW2018_Preprint.pdf
Overall it acknowledges GraphQL's advantages, while warning that the data retrieval part shouldn't be done naively.
An excerp
> We note that this issue is somehow acknowledged by the Github GraphQL interface and, as a safety measure to avoid queries that might turn out to be too resource-intensive, it introduces a few syntactic restrictions [7]. As one such restriction, Github imposes a maximum level of nesting for queries that it accepts for execution. However, even with this restriction (and other syntactic restric- tions imposed by the Github GraphQL interface [7]), Github fails to avoid all queries that hit some resource limits when executed
Says who?
> Also REST necessitates multiple HTTP queries to fetch multiple resources.
Again, says who?
There was this long pause and then we both just started laughing.
File under: shit that doesn't happen any more because nobody plays single-player games side-by-side, late at night any longer.
PC police might be on to terms like this nowadays, but by using the term I understood them to mean:
- A less loved resource - A potentially ugly resource - A resource that causes trouble
I don't want this to come off as a personal attack (and I apologize if it does), but your comment contains absolutely no information whatsoever regarding a specific situation/use-case, nothing from which the rest of us can formulate our own opinions on the REST/GraphQL discussion.
>it solved a lot of the administrative and philosophical headaches
>considerably reduced the number of connections
>considerably reduced wasted data
>made our client code so much simpler through easily grokked queries
I feel that grandparent does contain information which might be valuable for adoption.
In the end I would guess you can end up in a similar place with a standard fetch-json design if you just ignore ReST dogma and focus on getting the API into a shape that fits the need.
Not saying ReST dogma is necessarily wrong, or bad, just that it’s easy to get lost in design when focusing more on learning others design than understanding the actual problem you’re trying to solve.
This sounds a little over-the-top. There are certainly cases where REST would be the better recommendation over GraphQL. I have no idea what your specific requirements were but if building a REST API was a 'monumental effort' then GraphQL was probably a good choice for you. That does not mean that in all cases GraphQL > REST.
So I guess my question is, why would I use GraphQL over, say, the Swagger tool suite? Swagger and the OpenAPI spec defines a way of doing REST that best fits both what Roy Fielding meant for REST but also fits IDE and tool automation systems.
There are also a ton of maintenance benefits, like for example if you add a field in GraphQL that's perfectly fine to not change the version because that break any existing calls, which is not always true with REST.
That's not a unique benefit of GraphQL. Any HTTP based API can do this, regardless of how it's designed.
Some specifications even have it baked in (See: jsonapi.org).
> GraphQL from a front end or mobile POV makes your api more like a data store that it can interact with and query for it's needs, which makes app UI work much nicer.
Again, not unique to GraphQL.
> There are also a ton of maintenance benefits, like for example if you add a field in GraphQL that's perfectly fine to not change the version because that break any existing calls, which is not always true with REST.
Again...
Assuming you are using some from of Semantic Versioning, adding a field to a REST API should never break existing clients. Did you mean "removing" a field?
1. TypeScript
2. Document database
3. GraphQL
I know there are things that do two of these. I want all three.
Sometimes 1 and 3 (see http://avant.engineering/graphql-and-typescript/)
[0]: https://github.com/walmartlabs/lacinia
It's great but it's not quite perfect for me: I'd prefer if it produced a function that accepts your query executor and inputs, and returns an observable of the result, and it doesn't work very smoothly with angular (especially 5+).
[1]: https://github.com/apollographql/graphql-tag
That being said, there are cases where a join between ad hoc subqueries is the best way, and GraphQL doesn't really offer a way to do that (though I don't see why it wouldn't be possible). E.g. arbitrarily combining two GraphQL queries that return lists where some field in one is equal to some field in another.
But in terms of replacing REST, where you have to do all of that anyway, it is far and away the better option (for ad hoc querying, at least).
I think you're supposed to create a "virtual" field on the left-hand object that represents a collection of the right-hand type of objects. The field can be parameterized if your join needs extra information. If you want pagination, the virtual field returns an intermediary object describing the cursor (sort order, offset).
The concept is great, and if you write custom SQL queries for each resolver (if necessary), properly caching things that can be cached, and use the first class citizen programming language (JavaScript), then it seems GraphQL works wonderfully.
Trying to fit it into an existing ORM paradigm with respect to complex sub-collections, lazy loading, and efficient database querying, it just didn’t work out for us.
The big difference between Java and Javascript when it comes to GraphQL is the amount of noise, tutorials and examples on the Javascript side far outweigh other options right now.
Javascript may be the "happy" path for now but I do hope that we see continued investment in Java/Scala/Ruby/Python/.NET etc as those implementations have the opportunity to be better architected and more performant that the reference JS implementation. The reference implementation uses a very simplistic execution model which for now has been copied almost verbatim into other languages but there is great potential for a proper query planner and optimisation layer at the GraphQL layer.
Disclaimer: I work at MDG on Apollo Engine (the backend of which is Kotlin utilising graphql-java).
I do agree on the noise and lack of tutorials. I'm getting ready to present on a GraphQL option. We don't want to use javascript. The tutorials for java are a bit cumbersome.
Btw I'm really liking apollo.
These last months, I've been working non-stop in a blazing-fast GraphQL engine that beats the rest by an order of magnitude - https://graphql-quiver.com/
Hopefully, it'll be standardized soon.
For writing React Apps GraphQL is wonderful!
FYI we're using it in production over a django backend (which comes with some drawbacks, since subscriptions == pushed updates are not perfectly implemented) with our react/apollo apps (web and native) and in my opinion the overhead lies surprisingly more in the frontend side (writing data connectors is longer, but way more explicit, than using rest queries returning json)than on the backend (where you just declare resolvers, a thing you don't even need to do in nodejs) and handle permissions.
This is a piece of GraphQL I haven't been able to get my head around. Could you elaborate or point me to a good explanation of how this is implemented? Everything I found when I looked into GraphQL previously was something like "you control access to individual resources in your business layer" but never explained how.
Inside that function you can write any code you’d like, including permissions code.
* Watch out for bad implementation of the GraphQL API (this will definitely result in bad performance).
* Design the GraphQL schema that you want the user to see/perceive. Not every object or field in your database needs to be exposed via the API the way it is.
My workplace is currently moving a huge monolith into a bunch of manageable components. Each of these components has its own GraphQL endpoint. Using schema-stitching, these are being stitched together into one endpoint for API users.
As a result of our codebase, we've tried GraphQL in:
* Ruby (graphql-ruby) - WATCHOUT Relay arguments for connection fields are not exposed to the library user. So basically you have to implement your own Relay-compliant stuff if you need access to the pagination arguments from Relay. Also, documentation is broken.
* Python (graphene) - We've had no issues so far. We worked around it.
* Node.js (Apollo GraphQL) - OH MY BUTTERFLIES. So far, this is the ONLY library I have come across that is polished and has plenty of documentation.
* Elixir (Absinthe) - My coworker worked on this part. He did not complain. So I'm assuming he had no issues.
The "Learn * in a day" joke applies to GraphQL. As simple as GraphQL looks for the client-side, it is beast of a job to build a GraphQL backend that is optimized for production.
Servers-side implementation of GraphQL is not very well documented apart from hello-worldly examples. Most of the knowledge found online is about client-side usage.
Due to poor documentation/examples provided, ramping up people with GraphQL is hard. Most first iterations I've had to review were slower than our REST APIs because of unoptimized code. Sitting down for a few minutes solves that problem.
To ramp up people at work place, I ended up having to do this:
* Ask people to use the GitHub v4 API to checkout GraphQL.
* Make them build a GraphQL server for a blog app.
* Dive straight into whatever feature/API they would build.
* Review their work a few dozen times and show them optimization tricks.
My most valuable lesson: When in doubt, dig into the source of these libraries.