Ask HN: Were you happy moving your API from REST to GraphQL? - glenscott1
======
Androider
As a consumer of APIs I vastly prefer REST APIs.

In my opinion, GraphQL moves too much of the burden to the user of the API. It
makes most sense if the data is highly dynamic, you have a mobile app and
every call is expensive, or (and this seems more common) the backend and
frontend teams don't like to talk to each other. As a user, I just want to GET
/foo, with a good old API token I pasted from your dev docs, and move on to
the next thing. I don't want to spend time figuring out your database schema.
Or perhaps I've just yet to see single good public GraphQL API. I just
recently had look at the Github GraphQL API and it's non-existent docs (no, I
don't want introspect your data models at runtime), noped the hell out of
that, and got the REST integration for the bit I needed done in an hour.

~~~
CGamesPlay
Why do you think it makes the most sense if “the backend and frontend teams
don't like to talk to each other”, given that your biggest complaint seems to
be “I don't want to spend time figuring out your database schema“? Aren’t you
the frontend guy in this scenario, and not wanting/able to talk to the backend
guys (the people who designed the database schema)?

~~~
StavrosK
He (the hypothetical he) doesn't want to talk to them to get them to add the
endpoint he needs, so he'd prefer to just get the schema directly and query
for whatever.

~~~
tormeh
Note that this means the back end team has to keep the schema backwards
compatible forever. Having everyone have direct access to the schema (speaking
from SQL experience) is bad. This is the start of a slow moving disaster train
that you can't stop.

~~~
alexchamberlain
I disagree; the GraphQL schema should be your point of stability, whereby
anything in front or behind can change. That being said, ofc, you'll need to
deprecate something at some point and that is fine, it might just take a
couple of weeks. See @deprecated decorator examples

~~~
tomnipotent
> the GraphQL schema should be your point of stability, whereby anything in
> front or behind can change

This is the bit of abstraction I see most developers fail to understand when
evaluating GraphQL.

------
ilovecaching
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.

~~~
dugword
What is a red haired resource?

~~~
phailhaus
Think "red-headed stepchild". The weird ones.

~~~
numbsafari
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.

------
heavenlyhash
Yes. (Mostly.)

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.

~~~
krainboltgreene
> Everything else is line noise.

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.

~~~
jerf
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.)

~~~
krainboltgreene
Most of the REST understanding is basically "how do distributed caches work?".

------
haney
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.

~~~
arnorhs
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]

[1] [https://www.apollographql.com/docs/react/features/error-
hand...](https://www.apollographql.com/docs/react/features/error-
handling.html#policies)

[2] [https://www.apollographql.com/docs/react/api/react-
apollo.ht...](https://www.apollographql.com/docs/react/api/react-
apollo.html#graphql-config-options-fetchPolicy)

~~~
haney
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.

------
ergothus
My company has been flirting with 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.

~~~
jwoah12
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.

~~~
sequoia
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.

------
ulkesh
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.

~~~
jpgvm
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).

~~~
soulnothing
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.

Btw I'm really liking apollo.

------
valw
We migrated most of our backend (written in Clojure) from REST to GraphQL
(actually a homemade alternative to GraphQL, but not relevant to this
discussion).

It went well, it greatly simplified both our backend and frontend code. The
backend code got simpler and more stable because it no longer had to deal with
"data packaging". The frontend code became more transparent, because you can
now easily read what data gets exchanged, and more decoupled, because
different components can independently require the data they care about. One
of the biggest benefits has been the degree of independence to evolve both the
client and server.

We haven't had the performance issues some people have mentioned (N+1 query
etc.), because of the server-side design of our homemade GraphQL engine - in
which data resolvers are batching and asynchronous by default, unlike most
backend libs which approach this problem more naively. Will open-source that
soon.

The biggest limitations I see to GraphQL are:

\- it doesn't really have a story for caching. I have some ideas for
addressing that, but it hasn't been a problem for us really.

\- it repeated the SQL mistake of exposing a query language based on text, not
data structures. Now we have to write queries as templates instead of
assembling them programmatically. This hurts both application developers and
library authors.

\- it doesn't really have a story for structured writes.

~~~
UncleEntity
> it repeated the SQL mistake of exposing a query language based on text, not
> data structures. Now we have to write queries as templates instead of
> assembling them programmatically.

Out of curiosity couldn't you just treat queries as a composable AST and
"compile" the query text from that?

~~~
valw
> Out of curiosity couldn't you just treat queries as a composable AST and
> "compile" the query text from that?

You could write such a wrapper, but it won't be standard, which means that
there will never be a robust library ecosystem and set of practices that
arises from that. If GraphQL was to evolve, you also wouldn't be sure your
wrapper can express all of GraphQL. Finally, this would add new practical
hurdles, like a new dependency, additional runtime cost of compilation,
obscured source mapping, etc.

Meanwhile, because GraphQL is just a text-based DSL, most people don't have a
clear idea of the _information model_ of GraphQL queries - you have to read
the spec to get this idea. If we are to build a robust ecosystem on top of
GraphQL, this information model should be evident in the API.

All these problems are present, and very damaging, in SQL.

------
throwaway2016a
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.

~~~
supahfly_remix
> I tend to write publicly facing APIs so this conversation is colored a
> little by that

Out of curiosity, how do you secure your public-facing APIs and how do you
authenticate/rate-limit users?

~~~
throwaway2016a
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.

~~~
supahfly_remix
Great info -- thanks!

------
OldSchoolJohnny
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.

~~~
HEHENE
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.

~~~
KaoruAoiShiho
What about caching though?

~~~
tobyhinloopen
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)

------
BerislavLopac
These are taken from some of the other comments in this thread:

    
    
        * As a consumer of APIs I vastly prefer REST APIs.
        * Highly recommend GraphQL to anyone.
        * I *love* how flexible it is for client developers.
        * As a manager/business owner, I like GraphQL.
        * How I _wish_ I could nope the hell out of our GraphQL dependency
        * Unnecessary complexity over simple rest calls with no benefits.
        * REST semantics are a distraction
        * my experience is just ok.
    

What I see here is many different reactions from different people, presumably
with different experiences and use cases on their hands. And that's perfectly
OK -- REST, GraphQL, XML-RPC, heck even SOAP are just tools, and use whichever
works best for your particular situation.

Just because it worked for me doesn't mean it will work great for everyone
else; and if it sucks for me doesn't mean it won't be a life-saver for someone
else. Those are just tools; use them as you find fit.

------
t_fatus
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.

~~~
kej
>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_.

~~~
sgdesign
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.

------
SingAlong
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.

------
jaequery
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.

~~~
spinningarrow
> 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)?

~~~
jaequery
well, it won't be just a simple GET /user/1 anymore. it will be like: user {
id name role status age sex address group { id name } etc etc }

~~~
spinningarrow
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.

------
syvex
We've just started to dabble in GraphQL, and like many others we've seen mixed
results.

On the upside, we can construct complex queries than eliminate many
consecutive RPCs that you'd end up with in a traditional REST API. At scale
this should work wonderfully, greatly reducing the client/server latency for
our realtime app.

On the downside, the tooling is still far behind. This is somewhat due to
GraphQL being a younger technology so you have to give it some time. OTOH, I
feel like you can get things off the ground with REST more quickly. Problems
with GraphQL tend to be harder to reconcile due to the debug tooling handicap.

Some of our engineers take a little time ramping up to GraphQL due to its
complex nature. This is probably a good thing in the long run though, since it
stresses the importance of keeping RPCs to a minimum and eliminates having to
sync or batch consecutive RPCs.

Overall I still think it's a win. The tooling should improve over time, and
hopefully it will be a first-class citizen in IDEs and libraries soon. Until
then, you've got to be prepared to muscle though it.

------
schrockn
Nick Schrock here, one of the GraphQL co-creators. I agree with a lot of the
criticism in terms of the difficulty of implementing GraphQL backends. I think
there's a big opportunity for folks to build vertically integrated toolkits
that deal with N+1 issues, integrate DataLoader natively and so forth. Good
versions of these would deal with a lot of issues described here in greenfield
GraphQL backends. I talked about this at the GraphQL Europe keynote last month
([https://www.youtube.com/watch?v=zMa8rfXI6MM](https://www.youtube.com/watch?v=zMa8rfXI6MM)).

Current greenfield implements are typically stacked on ORMs like Django and
RoR, and the impedance mismatch is real. Personally I abide by the dictum that
ORMS are "Vietnam of computer programming" and should be avoided at all costs
for anything that will grow beyond a small app. GraphQL was not originally
implemented on top of an ORM, but instead an object model built on key-value +
edge store internal to Facebook.

In terms of other criticisms in this thread:

1) Exceptions: The default behavior in graphql-js (mimicked in other language
implementations) of swallowing native exceptions by default was probably a
mistake in hindsight. Whenever I've played with GraphQL using different
toolsets the first thing I change is to add a wrapper function which checks
for errors and then rethrows the initial exception that caused the GraphQL
error for use in testing and CI/CD contexts.

2\. Caching: Personally I've always been confused about the concern with
leveraging HTTP-level caching. While a clever hack, with any real app with any
sort of even mildly dynamic behavior you don't want to do this. Staleness will
be interpreted, rightly, as bugs by your users. If you want to replicate the
behavior the most straightforward way would be to use persisted queries
(described here [https://blog.apollographql.com/persisted-graphql-queries-
wit...](https://blog.apollographql.com/persisted-graphql-queries-with-apollo-
client-119fd7e6bba5)) combined with HTTP GETs. With persisted queries you can
encode the entire request in the query string, which should get you the HTTP-
level caching you want.

3\. Docs: Quite confused about this one. While particular implementations of
GraphQL can be problematic the documentation of the core language (which I am
not responsible for) is superb. See [http://graphql.org/](http://graphql.org/)
and [https://www.howtographql.com/](https://www.howtographql.com/).

~~~
chacham15
My largest criticism of GraphQL is that it doesnt go far enough. That is to
say that I want my components to declare their data dependencies, but not all
data comes from a server. Some data is computed, other data comes from
different servers, and some other data is locally generated. For example,
facebook has some user information that I want to add to my User object; in my
case, theres no reason for the component to know that its data is actually
coming from multiple sources but I have no simple way of coding that.

Another issue: there currently are a lot of servers that are REST and it would
be really nice if there were ways of incorporating them in the GraphQL schema.
One of the most useful features to add here would be ways of linking separate
REST objects to each other in the GraphQL schema. This would help adoption
quite a bit.

~~~
schrockn
I'd check out Apollo for these use cases. They allow a client GraphQL schema
to be sourced from a bunch of different places, including (I believe) local-
only state, REST APIs, and others. See
[https://www.apollographql.com/docs/link/links/rest.html](https://www.apollographql.com/docs/link/links/rest.html)

------
IBCNU
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.

~~~
minor3rd
Sounds like you had a few problems.

------
013a
It makes many things easier and many things harder. The lack of really good
backend libraries/frameworks outside of NodeJS is the most concerning thing.

Also; debugging and monitoring GraphQL APIs _sucks_. Considerations:

\- Any subfield of a query can throw an error, but the rest of the fields can
succeed, because GraphQL frameworks are allowed to run each field resolver
asynchronously.

\- Because of this, any GraphQL query is capable of returning multiple errors.

\- Rate limiting is exceedingly difficult due to nested resolvers. I've seen
solutions which involve annotating your schemas with "cost" numbers, and only
allowing each query to run up to a maximum "cost" before failing by
dynamically adding the costs of each field they request. Traditional rate
limiting doesn't work.

\- Traditional APM platforms also don't work. Prepare to adopt Apollo Engine
and pay them $600/month on top of the money you're already paying New Relic or
Datadog.

~~~
brightball
I’ve only heard positives about Absinthe for Elixir fwiw.

~~~
013a
The three biggest frameworks are definitely Apollo (JS), Graphene (Python),
and Absinthe (Elixir).

The common thread between those is that they're all languages with weak type
systems, which is a theme in GraphQL land. Strongly typed languages tend to
have usability and safety issues with GraphQL; you end up needing codegen or
bypassing type safety to make it work.

------
xentronium
Our front end engineers were extremely happy. Me personally, as a backend
engineer, not as much, but it isn't too bad.

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)

~~~
chadmckenna
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.

------
thermodynthrway
I really wish everyone would just move to GRPC and be done with it.

GraphQL just feels too tied to the datastore on the back end to be generally
useful. REST/Swagger is hugely overcomplicated for the basic REST premise of
moving objects back and forth.

GRPC is what REST should have been. Ship objects back and forth between
multiple languages with minimum fuss.

~~~
g5095
100% agree, RPC was good enough for our forefathers ;) REST and graphQL are
both terrible (there, it had to be said).

There's no reason someone who wants an expressive query language like graphQL
provides couldn't send that query over gRPC, in which case all the benefits
are moot, you can do both. But let the rest of us just make regular RPC calls.

------
nicwolff
You don't have to "move" to reap GraphQL's benefits – you can just add a
GraphQL layer.

I'm backend Systems Architect at a big publishing company, and my current
primary project is an aggregating caching GraphQL proxy for our REST
microservices.

Our front ends were making too many calls to the REST APIs, so we went
overboard embedding related resources – and now they're getting too much
unneeded data back, and cache invalidation is a nightmare. Sounds familiar,
probably!

So we're building a GraphQL service that stitches those REST APIs together to
let the caller request exactly the fields they need, from any API's resource.
By caching individual resources, rather than nested multi-resource
serializations, we can invalidate easily by UUID on change events – so cache
TTLs can be long – and the GraphQL API's field resolvers can assemble complex
responses with a few fast Redis MGETs, which are batched by DataLoaders.

This also gives us a place to centralize business logic, rather than having
each front end service reimplement field formatting, resource transforms, &c.
Since the REST APIs remain available as the source of truth, existing services
can migrate to the GraphQL proxy at their own pace, which we hope will be an
easy sell since it's so much faster.

------
xrd
I'm really curious to hear from people dealing with massive JSON (or XML)
responses via REST. This is where REST really falls apart with complexity that
is much worse than trying to learn the complexity of GraphQL.

See: [https://brandur.org/graphql](https://brandur.org/graphql)

"In GraphQL, every contract is explicit and observable. Providers can use
something like a canonical log line to get perfect insight into the fields
that are in use for every request, and use that information to make decisions
around product development, API changes, and retirement."

You simply cannot know with a REST API what to remove if the decisions on what
to return for a request are largely made by the server side team. So, you end
up with massive, clunky and confusing responses. GraphQL forces the client
side users to understand how to use it, and because of that you get so much
more.

------
rwieruch
Yes.

I had the chance to participate in moving the client-server architecture from
REST to GraphQL when I worked for two companies as a contractor. They didn't
regret it so far. There a various advantages (and disadvantages) [0] using
GraphQL.

But these are only the direct impacts of using GraphQL. In the case of these
two applications, they had a React client application managed by a GraphQL
client library. All the state management done with Redux/MobX was reduced to a
minimum, because most of the managed state was remote data from an API. Now
the GraphQL client was able to take over, leaving only the local UI state for
Redux/MobX. Often it is even possible to remove these state management
libraries altogether.

\- [0] [https://www.robinwieruch.de/why-graphql-advantages-
disadvant...](https://www.robinwieruch.de/why-graphql-advantages-
disadvantages-alternatives)

------
d0m
Yep, best decision. Both from a back-end experience (caching, performance,
type safety) and front-end experience (flexible querying, great documentation,
tracing, etc.)

------
jensnockert
Yes, it's generally quite a bit nicer. It's not as nice as I hoped, but it's
better. The old APIs are JSONAPI-style.

The main disappointment is that input types are not nearly as expressive as
output types.

~~~
supahfly_remix
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.

~~~
the99thguy
The name is a little misleading in that regard. GraphQL has mutations that
tell the server to change data rather than just return a query.

~~~
supahfly_remix
Thanks. That helps!

------
jameslk
GraphQL really shines for querying data, but if you do a lot of writing of
data, the API starts to feel like a clumsy version of RPC. I ran into this
trying to apply GraphQL to a business use case that required lots of user
input. Designing mutations on both the client and the backend is pretty
tedious, especially when it comes to handling the response of the mutation.
For example, there's no straight forward way to handle errors like what's
commonly done with REST using HTTP error codes.

------
andrewstuart2
Who says GraphQL is not RESTful, though?

You have resources represented as a graph and you're asking for the state (in
some representation -- probably JSON, but maybe protobuf, etc), just in a more
expressive and deeper way than a simple HTTP Get with a single URL can
express.

Nothing about REST ever said that a resource locator had to be a URL, or that
a single resource can't represent a collection of resources.

That's all GraphQL does, IMO. It lets you more flexibly and expressively ask
for stat of a collection of resources.

------
misterbowfinger
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?

------
blaster151
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?

------
jonotime
Another django/graphene shop here. I'm really enjoying the transition. My one
complaint is with deep queries. If the query asks for a very nested objects,
the amount of DB fetches can become large and then you get a performance hit.
With REST you generally know the performance of your queries since the schema
is static. How do people solve the n + 1 issue here?

------
kasbah
Currently evaluating using GraphQL. I have used it for a smaller endpoint [0].
I like the server side as I feel it lets me express the purpose of the API
really well.

I have been using straight HTTP requests to query the GraphQL endpoint. Now,
wanting to do something more complex, I am disappointed in the state of
GraphQL clients. Everyone says use Apollo but it has some serious issues (e.g.
caching [1]). Relay seems over-kill/restrictive and none of the other
alternatives seem complete. I feel like maybe my life will be a bit easier if
I just stick with REST especially since I am proxying an exiting API.

[0]: [https://github.com/monostable/kitspace-
partinfo](https://github.com/monostable/kitspace-partinfo)

[1]: [https://github.com/apollographql/apollo-
client/issues/3452](https://github.com/apollographql/apollo-
client/issues/3452)

------
nailer
I'm holding off until I don't have to define types in 3 places:

1\. TypeScript

2\. Document database

3\. GraphQL

I know there are things that do two of these. I want all three.

~~~
mlevental
which two?

~~~
nailer
Usually 2 and 3.

Sometimes 1 and 3 (see [http://avant.engineering/graphql-and-
typescript/](http://avant.engineering/graphql-and-typescript/))

------
mej10
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).

~~~
CGamesPlay
> 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).

------
dnsco
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.

------
dandigangi
I just wanted to say thanks to everyone that commented! We've been exploring
if GraphQL was something worth trying out and it seems like it's worthy of a
trial on some of our lower impact applications. Great thread here.

------
bradhilton
Yes, our team has migrated to GraphQL and it has been great, both on the front
and backend.

We have a Django app on the backend and have used Django REST Framework for
our REST API. That was a great experience, but had some limitations. We've
written our new GraphQL API with the help of Graphene and it has been awesome.
Everything is very declarative and exploring the API schema couldn't be easier
using GraphiQL.

Implementing it on the frontend has been great too. Yes, you do have to
specify what fields you want, but having complete control is worth the extra
boilerplate. I'd recommend it heartily.

------
iamleppert
I really wanted to like GraphQL but ultimately decided against it. It's one of
those things that seems great in theory but when you actually start working
with it you see all the warts.

The client libraries are too complex, there's too much magic going on,
debugging is a pain, there's not a lot of native support in browsers and
mobile devices. I don't want to step into the code of a client library I
didn't write to figure out some simple query issue. It's no longer a simple
matter of just an HTTP request anymore. It's not a pragmatic choice.

------
DiabloD3
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.

~~~
jaegerpicker
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.

~~~
krainboltgreene
> 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.

Again...

------
vinayan3
Yes exception for File uploads. There isn't a spec and not all apollo clients
yet support it.

Hopefully, it'll be standardized soon.

For writing React Apps GraphQL is wonderful!

------
smt88
For a mature product, no. We closely looked at engineering time and realized
we'd never make our investment back.

For a new product, yes (so far).

------
stevefan1999
Absolutely. REST APIs are passive and GraphQL APIs are the vice versa, very
active and progressive in nature, GraphQL also comes with a simpler model to
process real time data (subscriptions). However, it is relatively hard to
scale GraphQL (especially if you had Websocket based subscriptions) while REST
can be backed by traditional HTTP proxy.

------
thomasfedb
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.

------
roadbeats
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.

~~~
t_fatus
Python (Django) support is good (appart from subscription), but not as out of
the box as NodeJS indeed

------
sbinthree
Much prefer REST assuming nested documents are aggregated by default into the
parent. If it's just an HTTP RDB client like some can be then not so much.
Less data on wire doesn't matter for server to server communication. I can see
it for APIs whose sole purpose is low bandwidth client apps.

------
yen223
Yes.

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.

------
schickling
Almost all developers/team who _actually_ tried out and used GraphQL, will say
the same thing: You never want to go back.

Most of the arguments against GraphQL that I'm reading here, seem to actually
be misconceptions (or the GraphQL ecosystem not being far enough yet).

~~~
tobyhinloopen
I disagree. Some points are really valid. It adds complexity to your system,
especially at the server. It is a costs/benefits thing, not only benefits. The
benefits are minimal for simple CRUD-like applications.

------
aclatuts
I've been building a GraphQL only product for 1.5 years now. It was also the
best scenario for graphQL because we were also rewriting an entire app from
scratch.

For some background info this app has a huge feature set, low traffic, B2B,
and at most 2 developers working on this app for about 1 year.

For the technical side I chose typescript from the back end and front end
(Angular). This mean I could use the same typings from our ORM mongoose.

Very early on I was able to pick tooling that ending up being cutting edge
compared to any other tool in any language, namely the tools where graphql-
compose, grapqhl-compose-mongoose, and graphql-code-generator. In addition
GraphQL lent itself pretty well to dependency injection on the server side.

It took about 6 months to get fully proficient, but it was completely worth it
being able to use the same types for the front end and back end. GraphQL even
made it possible to bootstrap types from mongoose into the server. A lot of
time when dealing with 3rd party services I could copy the docs and turn it
into types for the resolvers.

The biggest single benefit of it all was side stepping the middleware of
Express. I didn't realize how awful express middleware are, because you can't
really control the middleware chain very well. But the library with graphql-
compose made chaining resolvers extremely precise, which was important.

Overall I love working with GraphQL but I realize that I probably could have
done just as well with rest if the backend has decent middleware chaining i.e
not express. For performance there is lots of options that are often built in
like client caching, batched queries, whitelist queries, and persisted
queries. It worked pretty well in a PWA too.

tl;dr

pros

\- types everywhere!

\- following the logic of any resolver is usually pretty straightforward.

\- true middleware

\- learned how to make good rest frameworks in the future.

cons

\- hugely steep learning curve

------
ojr
my API uses a combination of REST and GraphQL, new api calls are written
mostly in GraphQL unless its something like a batch job, or querying,
modifying the database, Rest works better for those type of tasks in my
experience.

------
chao-
So far so good, especially on the front-end. We love the queries, the caching
downside don't bother us _too much_ , but mutations make me a little nervous
(conceptually, ecumenically, grammatically...).

On the server side, it is a mixed bag. Defining a new type system on top of
our existing one, and on top of the Avro schemas we have for inter-service
communication, it feels... a bit much. Each layer has a purpose so I can't
advocate for removal, but it does feel silly at times. Also the documentation
on pagination feels incomplete to the point of confusion, and depending on how
you search for answers, you might find blog posts that add confusion rather
than clarity.

Some additional friction came from the specific version of the Ruby server
library we jumped in at. They went _a little overboard_ in the amount of
metaprogramming used by the DSL, and I say that as someone who enjoys
metaprogramming shenanigans for fun on a Friday night! But it took a long time
to understand why adding some custom behavior, in a way that seemed utterly
necessary, was not possible (e.g. defining methods inside the DSL's type block
did not class_exec them into existence on the resulting class in any
reasonable way). They have since released a new version whose main API is
class-based, which is much more clear, enables everything I desire, and I am
eagerly awaiting next month when we get to upgrade to that and refactor.
Thanks to the maintainers for recognizing this was needed, and for doing the
heavy lifting to pull it off!

What I enjoy about GraphQL conceptually is that it dodges a certain square-
peg-round-hole issue I occasionally saw with REST, but in the same way that
leaves me nervous that we'll end up back at a land of inconsistent RPC
spaghetti. In an API where an iron-fisted "RESTful Actions Only!" rule is
enforced, many domains find _just those one or two actions_ that feel like
they are a better fit for their own unique verb, a custom-named action. The
rhetorical-and-ontological escape hatch for REST's limited verb set is to have
an abstract "resource" that only has, say, a POST option. You can only
"create" an "/recalculate_contacts" resource, but never GET, DELETE and so
forth. Or you PUT to "/contacts/recalculate", or some other silliness that
just feels too clever by half.

Those of us who were scarred by inconsistent, poorly-thought-out RPC spaghetti
over the years cling to REST because it brought peace to our nightmares via
simple rules that _almost fit_ everything, and as a bonus, really gel with
HTTP semantics. Because GraphQL's Mutations really don't specify much of
anything, I immediately assumed it would descend into a sort of API moral
decadence, but that has not borne out so far.

If anything, I am heartened to see that newer (though not necessarily
younger!) developers, who grew up in a world where REST was all they knew, do
not have this temptation to go off the deep end with action names, or to craft
RPC-esque systems with ill-considered boundaries of behavior. For the most
part they want to name things ala REST, because that's what they are used to,
except once in a while. So that is what our company goes with in terms of
mutations: Wherever possible, name it for the CRUD action it represents. Only
use a more unique/one-off verb if it is truly justified.

------
sgk284
Eh... I'm torn on it and could write at length about this, but here's my off-
the-cuff thoughts. For context, my co-founder and I are quite active in the
GraphQL community. If you've ever used apollo-cache-persist[1] or graphql-
crunch[2], we authored those libraries. Our startup, if you're curious, is a
social podcasting app written in react-native
([https://banter.fm](https://banter.fm)). We learned _a lot_ of GraphQL
lessons building it.

The tl;dr; is that graphql gives you a lot of flexibility and typed schemas
are nice, but it doesn't come for free and I miss the tooling around http.

Pros:

\- Typed schema

\- Custom queries retrieve all the data the client needs in one request

\- Really easy to implement, both server-side and client-side

\- Server-side, it's trivial to have any field resolved in any way you want
(redis, memcache, postgres, some random service)

\- Easy and arbitrary mutations. There's no pontificating over what verbs are
the proper ones to us.

\- If you use react, the community and ecosystem often assumes you're using
GraphQL, so it may make sense to use graphql just so you don't swim against
the current.

Cons:

\- The payloads can quickly become huge because there is often a ton of
duplication in a responses (depending on your query patterns). See this
example on the SWAPI demo: [https://bit.ly/2uOFZBP](https://bit.ly/2uOFZBP).
The result is 1MB of JSON, ~97% of which is data that exists somewhere else in
the response already.

\- Refactoring types is often impossible to do in a backwards-compatible way,
even if the shape of the data is the same.

\- You don't know what data you'll need in advance, so you're basically doing
all of your joins by going back and forth between the api resolver and your
data sources (this can be alleviated with persistent queries, but those come
with their own set of issues). A typical query to hydrate a response for a
user's feed in our app requests ~1,100 objects. After caching and
consolidating queries into multi-gets, it translates to about 50 distinct DB
queries.

\- Tooling: Working at the HTTP level simply has better tooling and tons of
infrastructure around caching and serving content (varnish, nginx, etc...)

We found that graphql payloads were so large that older mobile phones were
spending significant time parsing them. We created graphql-crunch to de-
duplicate responses before sending them over the wire. This led to nice perf
improvements on mobile platforms. It also gave us referential equality when
persisting the results to cache, allowing us to reduce a lot of work client
side.

If you're going to use GraphQL, embrace the javascript ecosystem. Also use
Apollo[3]. Also use DataLoader[4]. Roughly 40% of our queries get resolved for
"free" by data loader.

If I were to do it again, I'd at least prototype a REST-api with resources
designed specifically for http cache-ability (that is, break out session-
specific resources/attributes vs shared resources) and see if HTTP/2
multiplexing + nginx caching + etags results in a good client experience. But
I also mostly work on the backend while my co-founder mostly works on the
frontend, so we have different desires and constraints. Ideally, as few
requests as possible would make it to code that I wrote. With GraphQL that's
nearly impossible.

[1] [https://blog.apollographql.com/announcing-apollo-cache-
persi...](https://blog.apollographql.com/announcing-apollo-cache-persist-
cb05aec16325) [2] [https://github.com/banterfm/graphql-
crunch](https://github.com/banterfm/graphql-crunch) [3]
[https://www.apollographql.com/server](https://www.apollographql.com/server)
[4]
[https://github.com/facebook/dataloader](https://github.com/facebook/dataloader)

