
A REST View of GraphQL - wawhal
https://hasura.io/blog/rest-view-of-graphql
======
katet
I'm resistant to GraphQL, although I take the caveat that I was also initially
resistant to JSX and CSS-in-JS and my thinking has since evolved.

My two main annoyances are a) GraphQL could be thought of as a custom media
type that almost "slots in" to the REST model by defining a request content-
type and a response content-type with almost entirely optional fields, and b)
the incessant idea that REST has to replicate the n+1 query problem.

For a) "it's strongly typed" has never struck me as much of an argument. It's
appealing if you're already lacking a strong definition of your data model,
but GraphQL doesn't inherently fix that, it just forces you to confront
something you could fix within your existing architecture anyway.

For b), it seems that people tend to map something like /users to `SELECT *
FROM users`, and 12 months later, complain that it's retuning too much data,
and they have to make N queries to /groups/memberOf.

Am I alone in thinking the obvious solutions are to i) add a comma-separated,
dot-notation `?fields=` param to reduce unnecessary data transfer, ii) add an
endpoint/content-type switch for `usersWithGroups` and iii) realise this is a
problem with your data model, not your API architecture?

As an additional c), my other concern is GraphQL touts "one query language for
all your data", but tends to skip over the N+1 problem when _implementing_ the
queries to disparate data sources. If your existing queries are bolted into
`foreach (input) { do query }` then GraphQl isn't going to give you any speed
up, it's just going to give you slightly more simplicity to an already-slow
backend.

Granted, I work with "legacy" (i.e. old but functional) code, and I secretly
like the idea that adopting GraphQL would force us to fix our query layer, but
why can't we fix it within the REST model?

(I happen to be about to sleep, but I am genuinely interested in waking up to
see what HN thinks)

~~~
seanlaff
Many outlets gloss over the n+1 query problem, but I find it to be a _major_
shortcoming of the gql spec. Sure there are solutions, but they are not very
ergonomic. In one of our products we found simple requests blowing out to 100s
of downstream calls to the legacy REST APIs. The pain in optimizing the GQL
resolving layer negated almost any benefit of the framework as a whole.

Im happy GQL brought api-contract-type-saftey to a wider audience, but it is
similarly solved with swagger/OpenApi/protobuf/et al.

Folks may be interested in dgraph, which exposes a gql api and is not victim
to the n+1 problem since it is actually a graph behind the scenes.

~~~
tomnipotent
> gloss over the n+1 query problem, but I find it to be a major shortcoming of
> the gql spec.

Why would an implementation detail like n+1 be part of the spec?

~~~
cryptonector
The n+1 query problem arises from having an API that doesn't let you express
the full query that you want so the server can send you back all the data in
one go instead of N+1 goes. The n+1 query problem arises naturally from bad
API design. That's a spec problem.

~~~
bdcravens
Unless I'm missing something in the conversation, this is exactly what GQL is
designed to solve.

------
mumblemumble
I'm becoming somewhat suspicious of _both_ REST and GraphQL for APIs. Not in
the sense of thinking that they're bad or antipatterns or anything so
hyperbolic as that, but in that they make some fundamental assumptions about
how APIs are going to work that I don't think we should ever just take for
granted.

On the REST side, it's the assumption that the API is for state _transfers_.
Transfer is a heavy word there. You're not just assuming that the service is
stateful, and you're not just assuming that clients can ask for state changes.
You're assuming that the dominant model for effectuating those state changes
is that the client determines what the new state should look like, and
transfers a representation of that state to the server.

And then, on the GraphQL side, you're assuming that the service is basically
just a big database. Perhaps one with lots and lots and lots of behavior that,
from a high level, looks a lot like triggers. But still, a database.

Both these assumptions may work well for a whole lot of applications. If
CRUD's your ticket, then both can serve you well. But choosing either might
force you to make some compromises if you were instead hoping to do come up
with, for example, a more domain-driven design.

~~~
philwelch
What is commonly referred to as “REST” isn’t actually REST, and trying to cram
that round peg into that square hole is a hobgoblin of little minds IMO. In
practice, “REST” can be simplified to RPC over HTTP using JSON as a wire
format. Or you can use gRPC and get strong typing _and_ explicit RPC semantics
instead.

~~~
mumblemumble
It's not just using JSON as a wire format, it's overloading HTTP verbs and
status codes as part of your protocol.

HTTP verbs and status codes map fairly cleanly to CRUD and, more generally,
the "state transfer" paradigm. For generic RPC, though? Tends to get quite a
bit messier.

~~~
philwelch
While that’s true in the general case, there’s some rules of thumb that get
you most of the way there. Use GET for read-only, side-effect-free operations
and POST for everything else. Return 2xx for success, 4xx for “client error”,
and 5xx for “server error”. Use Swagger to document payload formats and
expected response codes. Getting too much farther beyond that is a slippery
slope that leads straight to the REST hobgoblin, who is a mere distraction
from the dragons a service owner actually needs to battle.

------
beders
One consideration I rarely see mentioned when discussing REST vs. TechDuJour
is:

    
    
        who are your users?
    

If you develop an API for your front-end team, use the fastest, most efficient
protocol. Use something that you can change quickly. Optimize for speed in all
regards.

If you develop an API for other users and they expect that API to be around
for a while and gradually grow, then you need to think about how much pain are
you going to subject your users to when your API changes.

GraphQL: You will not get your domain model right on the first attempt. So you
will need to change your "Graph". Your "Graph" might change substantially. How
do you deal with that?

REST: Same thing: There are well-known standards how to grow and evolve a true
RESTful API. Yet, you may still mess with your users, declare a /v2/ endpoint
and discontinue /v1/

~~~
gautambt
Not a general solution, but with Hasura, one approach we have seen is to use
Postgres views to keep the old graph around as your data model changes.

In general API evolution is tricky and perfect decoupling between API clients
and servers not possible (the article talks about this). What one can aim for
is a combination of:

1) Adding new query parameters should not break clients 2) Adding new fields
to the responses should not break clients 3) Adding new serialization formats
(for newer clients) should not break existing clients

#1 & #2 is roughly what you get with GraphQL optional fields.

Phil Sturgeon has good articles on API Versioning[1] and Evolvability[2] for
REST API's

[1] [https://apisyouwonthate.com/blog/api-versioning-has-no-
right...](https://apisyouwonthate.com/blog/api-versioning-has-no-right-way)
[2] [https://phil.tech/2018/api-evolution-for-rest-http-
apis/](https://phil.tech/2018/api-evolution-for-rest-http-apis/)

~~~
beders
"perfect decoupling between API clients and servers not possible "

Well, the ultimate REST client: the browser, comes pretty close to that. It
doesn't care if you are rendering an app to manage your bank account or a blog
or Hacker News.

------
lpellis
I've used GraphQL and Hasura extensively for my project
([https://pagewatch.dev](https://pagewatch.dev)) and it has been a huge
timesaver to get a realtime service up and running. BUT, I'm still using REST
for mutations (The POST/PUT part really). At least for my use case I find that
almost every time you are modifying data there is some other component also
involved (eg starting a background task), so it might as well be a REST server
endpoint. (Also I find the mutations language of GraphQL is really the
weakest/hardest to really understand part)

~~~
xiaomai
Mutations don't have the really clear advantages that queries do (compared to
their REST counterparts), but the one thing that I think does make them
worthwhile is that you get the cache updates/re-renders based on the mutation
result (instead of needing to re-fetch data or whatever to get your UI to
update).

~~~
lpellis
True, but then I'm using the subscriptions model that Hasura provides, so in
my case the UI update is actually automatic, its just initiated by Postgres
triggers instead of cache (so a bit slower, but still fast enough)

~~~
nicoburns
How have you found the performance / resource usage of widespread usage of
Hasura subscriptions. We're using them in a few key places, but have been
reluctant to rely on them too widely because it seems that they are actually
based on the polling the query every second.

~~~
lpellis
Traffic for my service is too low to say for sure yet, but the hasura docs
seems to indicate that it could be quite scalable:
[https://github.com/hasura/graphql-
engine/blob/master/archite...](https://github.com/hasura/graphql-
engine/blob/master/architecture/live-queries.md)

------
recursivedoubts
Great article.

REST with JSON has always been a category error: JSON is not a hypertext and
thus, as the author says, violates the most important and distinct aspect of
the REST architecture.

I have written quite a bit about this:

[http://intercoolerjs.org/2016/01/18/rescuing-
rest.html](http://intercoolerjs.org/2016/01/18/rescuing-rest.html)

[http://intercoolerjs.org/2016/03/15/hypertext-
hypotext.html](http://intercoolerjs.org/2016/03/15/hypertext-hypotext.html)

[https://threadreaderapp.com/thread/1276556432385531906.html](https://threadreaderapp.com/thread/1276556432385531906.html)

------
coding123
My main qualm about REST is the number of inputs for doing something: Path
variables, query variables, POST input, headers and for shits and giggles the
Http METHOD. To top it off, because people want "beautiful" REST APIs everyone
has a playground to do these kinds of things differently. And boy are they
done very differently from company to company. And that leads to massive
opinionated people. Finally, REST is tied to HTTP too tightly. It can't be
independent of it, ever. I know a lot of people believe that's a good thing,
in that there are metrics, logs, and a variety of data that assists
architecturally. But it has only reached that status because we're sitting at
15 years of REST toolchains.

I'm not saying GraphQL is the long term answer, but personally I'd rather be
in a project using GraphQL (and hopefully not backed by REST at all)

~~~
treve
This is partly because REST is not a standard like GraphQL, and you can't
really treat them as being equivalent.

If you want a closer comparison, I think it's better to look at standards like
OData, JSON:API,or even just for example [Microsoft REST API
guidelines]([https://github.com/microsoft/api-
guidelines](https://github.com/microsoft/api-guidelines)).

REST by itself is a pretty general description of a type of architecture that
isn't even tied to HTTP. Even HN by most definitions is a REST service that
primarily uses `text/html` as it's format.

------
ralmidani
We should resist attempts to turn technology choices into religious devotions.
Here's an example of a project that brings some of the most significant
benefits of GraphQL to an established, mature framework for building REST
APIs:

[https://github.com/yezyilomo/django-
restql](https://github.com/yezyilomo/django-restql)

It's tempting to think your new paradigm/framework/whatever is so
groundbreaking, so purely beneficial, that it warrants asking people to
demolish everything and start over. Those kinds of breakthroughs have happened
and will continue to happen, but the signal/noise ratio, especially in the
world of Web Development, is incredibly low.

~~~
gautambt
(Author here) Couldn't agree more on not turning technology choices into
religious devotions.

It is of course completely possible for you to build a query language from
grounds up. django-restql seems to be doing this. Sparse fieldsets and Netflix
Falcor other alternatives I've heard of. GraphQL however has good tooling and
if you do see the need for a query language on top of your APIs using it is a
good choice IMO.

GraphQL does not necessarily mean you have to throw away your existing backend
and rebuild from scratch either. It's perfectly fine to use GraphQL as an
additional API endpoint alongside existing APIs. A model we are seeing evolve
with Hasura is to use Hasura for all the reads and delegate writes via the
Actions framework either to a serverless function or another HTTP service.

~~~
ralmidani
Thank you for writing a nuanced, non-dogmatic article, and for your thoughtful
response here!

I should have clarified that I am not criticizing your article. Rather, I am
criticizing some zealotry that has emerged in the community promoting GraphQL
as the end-all solution.

I have been - at different times and in no particular order - ambivalent,
intrigued, fascinated, and skeptical in regards to GraphQL. I need to learn
more and do something hands-on with it, of course.

It seems some of the biggest benefits of GraphQL are 1) accommodating client-
side needs that the server-side developers did not anticipate and 2) avoiding
over-fetching and under-fetching. Is that fair?

If so, it seems many would be served well by "retrofitting" their REST API
with the ability to accept dynamic field requests and respond accordingly, as
is done with django-restql.

As for tooling, REST is served well in that area with things like OpenAPI and
Postman, although it is not clear (to me) how well they can adapt to non-
standard GraphQL-like querying capabilities "tacked on".

------
ksri
I have been working on an idea to leverage SQL + REST APIs instead of GraphQL
to solve the similar problems, and I would love to get some feedback on it.

GraphQL is great during development, but in production you often use
"persisted queries" to prevent abuse. Persisted queries are also a way to use
HTTP GET instead of POST, and thereby leverage HTTP caching. As such, if you
swap out graphql and use sql during the development phase, you perhaps can get
similar benefits.

My solution
([https://github.com/hashedin/squealy](https://github.com/hashedin/squealy))
uses SQL queries to generate the API response. Squealy uses a template
language for the sql queries, so you can directly embed where clause from the
API parameters. The library internally binds the parameters, and is free from
SQL injection.

Handling many-to-many relation, or many one-to-many relations is done in-
memory after fetching data from the relational database. This provides the
same flexibility as GraphQL, but of course requires you to know SQL.

Here is an example that builds various StackOverflow APIs using just a
YAML+SQL based DSL - [https://github.com/hashedin/squealy/blob/master/squealy-
app/...](https://github.com/hashedin/squealy/blob/master/squealy-app/squealy-
home/dba.se.com.yml)

Squealy is still work in progress, so don't use it in production. But I would
love to get some feedback!

~~~
gautambt
This looks really cool! Particularly for the embedded analytics use case.

Do you have an example of how this would work on the front end with
relationships. For example if I want to fetch posts and their comments how
would the front code look like?

~~~
ksri
Yes, following relationships is a key feature of Squealy. Here is an example
for a recent-questions API -
[https://github.com/hashedin/squealy/blob/master/squealy-
app/...](https://github.com/hashedin/squealy/blob/master/squealy-app/squealy-
home/dba.se.com.yml).

In short, with 1 GET API call that uses 3 SQL queries, you are getting a list
of questions, related answers and related comments.

You should parse that example as follows - 1\. The first SQL query fetches all
the questions, filtered by API parameters 2\. The second SQL query fetches all
comments for the questions selected in the first query. See the `WHERE
c.postid in {{ questions.id | inclause }}` part - questions.id is coming from
the output of the first query 3\. The output of the first and second query is
merged together on the basis of the questionid that is present in both the
query output. 4\. Similar approach is used for all the answers

------
agustif
Im right now building my backend on GraphQL and TypeScript.

Great DX.

GraphQL Modules + TypeGraphQL, Apollo Server, TypeORM (pg for prod and sqlite3
for dev/test)

Works pretty nicely auto-generating both graphql
fields/querys/mutations/schema and entities/models from database from a single
source of turth. I made a template from type-graphql's graphql-modules example
to work as a separate codebase, if someone is interested I could switch it
from private to public and share the link here

~~~
rattray
Wow, I hadn't seen before how you can mix model and gql code with TypeORM and
TypeGraphQL before. Looks really convenient, especially with an auto-
generator. Have you ran into footguns?

Did you try postgraphile? Any thoughts?

Curious to see how you string it all together...

~~~
agustif
Hey haven't tried postgraphile, but have tried Prisma/Hasura which seem to be
on the same SaaS-GraphQL space. They're all valid products, but my stack is
100% fully open source, and there's no PRO to buy for any of the options.

I based it off the creator of TypeGraphQL GQL-Modules+TypeGraphQL v1 example:
[https://github.com/MichalLytek/type-
graphql/tree/master/exam...](https://github.com/MichalLytek/type-
graphql/tree/master/examples/graphql-modules)

And a LogRocket's blogpost about TypeORM+TypeGraphQL:
[https://blog.logrocket.com/how-build-graphql-api-
typegraphql...](https://blog.logrocket.com/how-build-graphql-api-typegraphql-
typeorm/)

I need to add typeorm/models to my template before sharing, but as an example
here's a model which is also a type, using both @ObjectType() & @Field()
(type-graphql and @BaseEntity() & @Column() (typeorm)class decorators.

```user.model.ts import { Field, ID, Int, ObjectType, } from 'type-graphql';
import { BaseEntity, Column, Entity, PrimaryGeneratedColumn, } from 'typeorm';

    
    
      @Entity()
      @ObjectType()
      export default class User extends BaseEntity {
    
        @Field(() => ID)
        @PrimaryGeneratedColumn()
        id?: typeof ID;
    
        @Field()
        @Column()
        name: string;
    
        @Field()
        @Column()
        email: string;
    
        @Field(type => Int)
        @Column()
        age: number;
    
    
      }

```

and this is what type-graphql auto-generates for a user schema.

```user.schema.ts

# !!! THIS FILE WAS GENERATED BY TYPE-GRAPHQL !!!

# !!! DO NOT MODIFY THIS FILE BY YOURSELF !!!

type Document { author: User! authorId: ID! }

type Notification { author: User! authorId: ID! }

type Query { users: [User!]! }

type User { age: Int! email: String! id: ID! name: String! } ```

~~~
rattray
Nice, thanks!

Fwiw, postgraphile is open source and can be plugged into any express app. But
I don't think it provides an orm layer or equivalent, so I can see the
advantage of this approach too!

~~~
agustif
Sorry, my bad, I briefly checked their homepage and saw a pro button
somewhere:
[https://www.graphile.org/postgraphile/pricing/](https://www.graphile.org/postgraphile/pricing/)

Although it's a totally acceptable monetization strategy for any OSS to offer
cloud+enterprise support, for my personal projects at least I prefer to choose
projects which are more personal/community driven than commercial to put it
simply.

But yeah I basically like TypeORM generally also gonna use typeorm-seeding on
the mix to stress test the app.

~~~
BenjieGillam
_< checks the income from the pro plugin versus that from sponsorship>_ I can
definitely confirm that we're significantly more personal/community driven
than commercial.

------
0xBE5A
Thanks for this article! I'm currently writing my Bachelor thesis, designing a
new API for an existing architecture is part of my project. I've been
considering going with GraphQL instead of just overhauling the current REST
API and this is a pretty good starting point.

------
stunt
Use Graphql if you have multiple teams that don't own their back-end, and you
have multiple clients (Web, Mobile, SPA, Desktop...) consuming your data, and
your front-end always has to consume multiple APIs and resources, and you
don't count every milliseconds.

------
honkycat
I love GraphQL because it is a standard people can agree on, if nothing else.

It is a very long list of decisions your team does not have to make. How to
handle mutations and queries, how to represent your domain objects, all of
this can be decided through referencing the spec and best practice.

Throw in the fact that it REQUIRES you to define a strict schema that has
validation, and I am sold. The tooling is great, you get great documentation
out of the box, the architecture is good enough, it is totally win-win in my
book.

I feel like with REST you have to reinvent the wheel over and over again, and
the lack of standards leaves the burden on the team, who may not be senior
level engineers.. ( If I have to write another validation library I am going
to flip out. )

------
aogaili
GraphQL == Modern SOAP

------
gengstrand
Having written
[https://glennengstrand.info/software/architecture/microservi...](https://glennengstrand.info/software/architecture/microservice/graphql)
which is a blog entitled "GraphQL vs REST" I must admit that I was initially
on guard with this blog. In then end, they did compare and contrast GraphQL
with REST. I don't wish to go over this article point-by-point but their main
arguments against REST seems to me to be this...

1\. too many endpoints

2\. too much data retrieval

3\. too much coupling between clients and servers

The blog does not discuss when to choose REST over GraphQL since that would be
in conflict of interest with those who hold Hasura equity.

Technically, GraphQL does decrease the amount of endpoints to one but at the
cost of increasing client-side complexity because now client devs have to
write what is essentially a query. To do so, they have to understand the
backend schema. I would argue that this is not the greatest in terms of clear
separation of concerns. I would also argue that this means that there would be
even more coupling between client and server.

I won't cover the n+1 point since others here have already done so.

------
theonething
GraphQL with Apollo on the front-end provides very nice front-end global state
and cache management, but at the cost of increased complexity. For example,
fetching data updates the global state so that any page accessing that data is
updated automatically.

Are there any lighter weight RESTful JS client state/cache management
solutions out there people can recommend?

~~~
zerubeus
No there's not, and your argument of data updating page automatically is not
applicable if you are using react for example you can pass the right data to
the right component, and this is the point of Graphql, if you have your data
at the root component, you are not getting the point.

------
ericls
I think REST works if you need to fetch data but when you want to query data,
I prefer a well defined language instead of hacking my http headers into a
query language that I need to define, implement and maintain.

------
superfreek
Check out [https://open-rpc.org/](https://open-rpc.org/) if you haven't seen
it. Brings GraphQL-like tooling to JSON-RPC.

------
rswail
The primary difference here is that REST is an actual architectural style with
constraints.

GraphQL isn't. It's a data query mechanism expressed in JSON.

------
the_arun
GraphQL makes sense if it is consumed by UI(frontend). But REST still the best
for server side consumption. That is one application interacting with another
application in the backend. I have seen people interacting with GraphQL for
server side as well - but it is over-engineering and increases complexity.
IMHO GraphQL is for humans, REST is for machines.

------
k__
I like what AWS built on top od GraphQL.

AppSync + Amplify DataStore is pretty nice tech!

