[HN Gopher] GraphQL vs. REST APIs: a complete guide
___________________________________________________________________
GraphQL vs. REST APIs: a complete guide
Author : makaimc
Score : 63 points
Date : 2023-03-03 20:09 UTC (2 hours ago)
(HTM) web link (www.airplane.dev)
(TXT) w3m dump (www.airplane.dev)
| chrsjxn wrote:
| The article talks about how GraphQL is "flexible" a lot, but I
| kind of wish they'd spend more words talking about why that
| matters.
|
| Eg, if you're working on a new product, the odds are very good
| that your front ends will change pretty rapidly. At the very
| least, we're way more likely to A/B test application features
| than we are API schemas, regardless of what methodology or
| technology our APIs are using.
|
| Because that's why I would pick GraphQL. It's a choice that
| reduces the barrier to rapid iteration in the clients, but it
| does add backend and infra work to support it.
| blagie wrote:
| I don't like GraphQL due to the complexity. It's not JSON or
| YAML, and requires a lot of custom stuff on both ends.
|
| I'd like something like GraphQL, but built on standard data
| formats.
| braindead_in wrote:
| REST is basically a subset of GraphQL.
| eterps wrote:
| From a caching perspective REST is a superset IMHO.
| TurningCanadian wrote:
| There's a lot to caching that REST gets wrong. It thinks in
| terms of URLs being cacheable, but that's very limiting.
| GraphQL caches at the level of the objects in the response.
| Almost every REST API will return multiple objects from one
| URL. With GraphQL, newer data coming in from query2 can
| update components showing data from query1 if they both
| reference the same object even if query2 is a different URL.
| REST just doesn't have those smarts. Yes, a HTTP DELETE
| request will clear the cache for a particular URL, and
| there's no equivalent in GraphQL, (that I know of) but I
| don't think I've ever been able to take advantage of that in
| real life.
|
| At the network level, GraphQL can automatically set cache
| headers depending on the content. REST doesn't know what
| you're sending, so it's up to you to know that when you start
| sending mixed data (to save clients a roundtrip), the cache
| header may be impacted.
| https://www.apollographql.com/docs/apollo-
| server/performance...
|
| On the client-side, caching with GraphQL is far ahead of
| dealing with a REST API. It knows more about what data it has
| in cache so it's better able to automatically avoid network
| requests. Further, a cache-and-network fetch policy is just
| another parameter for your query and the plumbing for that is
| handled transparently.
| denysonique wrote:
| For JavaScript based projects TeleFunc[1] can make development
| way simpler by 'removing' the need for an API.
|
| [1]: https://telefunc.com/
| recursivedoubts wrote:
| imma let u finish, but a hypermedia is a necessary constraint for
| an API to be RESTful...
|
| edit: more usefully, you need to be really careful w/ your
| GraphQL end points because they are being access in an untrusted
| computing environment:
|
| https://intercoolerjs.org/2016/02/17/api-churn-vs-security.h...
|
| my understanding is that facebook whitelists their graphql
| queries but, last I looked, I didn't see security getting much
| attention around it...
| jensneuse wrote:
| Here's how you do it:
|
| - REST/Hypermedia when you're actually building a website (not
| app) and your "site" is a state machine
|
| - OpenAPI when you expose and API to 3rd parties
|
| - Isomorphic TypeScript APIs when you're using TS on both backend
| and frontend [0]
|
| - GraphQL when the frontend needs to talk to an API layer
| provided by different teams
|
| - OpenAPI when one backend talks to another backend
|
| - gRPC might be an option, but most teams don't need it
|
| [0]:
| https://wundergraph.com/blog/isomorphic_typescript_apis_end_...
| [deleted]
| timr wrote:
| Simplify that to:
|
| - REST by default
|
| - everything else might be an option, but you need to justify
| it with specific reasons.
|
| Also, having a JS-driven front end or multiple teams is not an
| automatic justification for the complexity of GraphQL.
|
| GraphQL is a _huge_ burden, for very little practical gain.
| Most companies have very small number of examples of conflict
| areas where queries need to be optimized, and for the most
| part, these can be resolved through smarter front-end
| engineering (like not throwing React at CRUD websites).
|
| It's amazing how we managed to build large-scale websites with
| essentially all modern functionality without all of this stuff
| for years and years, and only since 2012 or so have these tools
| become "necessary" (and I'm being generous with 2012...it's
| more recent than that).
| chiefalchemist wrote:
| I haven't used it a lot but one of the benefits of GraphQL
| that caught my eye is you get to specify what you want
| returned. So, for example, instead of 20 product objects (all
| available properties) you can get 20 products with name and
| price.
|
| Also, as I understand it, when implemented properly, you can
| get more complex (?) data back. For example, instead of
| getting 10 orders, and then 10 more requests for the items
| for each order, you can make a single request and get both in
| a single response.
|
| I believe both concepts apply to creates / updates as well.
| timr wrote:
| > but one of the benefits of GraphQL that caught my eye is
| you get to specify what you want returned. So, for example,
| instead of 20 product objects (all available properties)
| you can get 20 products with name and price.
|
| Yes. But you have to _implement_ this (simple in this case,
| but not so simple once people go hog-wild with the GQL).
| Also, I don 't think I've ever had a situation in my career
| where loading name _and_ price is a significant burden over
| either field individually. On the other hand, it 's a huge
| burden to have to implement the back-end system that
| supports a fully orthogonal, structured query language for
| the UI.
|
| To be fully charitable to the argument you're making,
| probably the real reason people do this is because they
| want to decouple development between Team UI and Team
| Product and Team Pricing, and it's just "easier" to expose
| "web SQL" to Team UI and let them go nuts, rather than
| sitting down with them an exposing targeted endpoints that
| give them exactly what they need.
|
| ...but now you have N problems. Your web app has become an
| ad-hoc distributed query language executor, and you have to
| think about the semantics and load implications of all of
| that.
| mattmanser wrote:
| That's not an advantage, from the DB side the two queries
| are indistinguishable because they use the same indexes.
| They will take virtually the same CPU to complete.
|
| If your user has authorization to access this extra data,
| the actual cost of sending those extra fields properties
| over the wire is ridiculously trivial.
|
| Think a kilobyte or two, if not a few bytes.
|
| Any justification you think you have for just sending the
| name + price is utter bullshit. You would save vastly more
| in bandwidth by not sending whatever dumb graphql code you
| wrote as part of your front-end build.
|
| That is, unless you are Facebook or Google and have already
| optimized the hell out of your front-end libraries.
|
| Which I guarantee you aren't and haven't done.
| jensneuse wrote:
| I more or less agree, but recent advances in tooling has
| changed this. E.g we've built a GraphQL to JSON RPC compiler
| [0], so we're hiding GraphQL behind a JSON RPC wall which
| also enables powerful code generation. We're using this
| successfully to build our own cloud [1] using our own tooling
| and I quite like it.
|
| Shameless plug, I'd love to get feedback if you have the time
| to try it out.
|
| [0]: https://docs.wundergraph.com/docs/features/graphql-to-
| json-r...
|
| [1]: https://cloud.wundergraph.com
| timr wrote:
| I mean...ok, but...wow. You built a _compiler??_ For
| writing a _web app?_ And you 're not Facebook?
|
| Look, maybe this is totally appropriate for your
| application domain. I don't know. But this kind of "power"
| is immensely complex. We have to be honest about the costs.
|
| I have to keep reminding people that essentially _all
| functionality of the modern web existed prior to 2012._
| IceDane wrote:
| How is GQL a "huge burden"? Would you care to elaborate?
| timr wrote:
| I could write a book on this, but just a few:
|
| * your teams will now spend a big portion of their time
| thinking about GQL primitives and mapping and syntax (oh
| my) and otherwise caring for and feeding this beast.
|
| * you still haven't solved the underlying problem -- you
| still have to figure out why your GQL requests are
| hammering the back-end(s...let's not forget that a lot of
| this stuff came from poor decision-making re:
| microservices!), only now it's indirected and harder to
| optimize.
|
| * ...oops, you forgot to implement all the corner cases of
| your GQL schema! Go back to 1 and start over.
|
| Say what you will about REST, but the syntax is dead
| simple, it takes about 15 minutes to learn, and the
| semantics are crystal clear. Whatever complexity remains is
| actual complexity in your problem or org structure, and you
| should _probably_ just fix that instead of trying to find
| magical tech beans to abstract the problem away.
| IceDane wrote:
| > * your teams will now spend a big portion of their time
| thinking about GQL primitives and mapping and syntax (oh
| my) and otherwise caring for and feeding this beast.
|
| What exactly do you mean by this? My team spends exactly
| zero time "thinking about GQL primitives and mapping and
| syntax"? What programmers have a problem understanding
| GQL syntax? I have explained GQL and set people to work
| in a 30 minute session. I've even had non-technical
| people write automated tests for APIs. If they can't
| write the queries themselves, they can simply use any of
| the great query builders(like apollo studio or what have
| you), where they can quite literally explore the entire
| schema, with documentation, and point-and-click their way
| through building any query.
|
| > * you still haven't solved the underlying problem --
| you still have to figure out why your GQL requests are
| hammering the back-end(s...let's not forget that a lot of
| this stuff came from poor decision-making re:
| microservices!), only now it's indirected and harder to
| optimize.
|
| How is this really any easier with RESTish APIs? In the
| end, this boils down to how you are doing observability.
| If you don't do any observability, you are shit out of
| luck whether you use GQL or REST. With GQL, you can quite
| literally automatically instrument your entire schema and
| get detailed tracing information for your entire graph. I
| have sentry set up to trace all our requests from our
| frontend, to our GQL gateway, to the subgraphs, to other
| services they call out to and even time taken doing
| database queries. It was a few lines of code.
|
| > * ...oops, you forgot to implement all the corner cases
| of your GQL schema! Go back to 1 and start over.
|
| Corner cases? If you have some underlying data you need
| to expose, the difficulty of exposing this data in the
| most appropriate manner comes down to the complexity of
| your data, and whether you use GQL or REST to expose it
| doesn't really change it. With GQL, types and relations
| are at least "native" - they are the source of truth.
| With REST and something like OpenAPI, you'll constantly
| be fighting limitations and have to trawl through
| hundreds of endpoints, some of which might be doing extra
| stuff for the sake of ease of consumers, etc. Feel free
| to elaborate on what sort of corner cases you have in
| mind. This sort of vague hand-waving isn't really useful.
| dmitriid wrote:
| GQL, in no particular order:
|
| - GQL allows unbounded arbitrary queries. The awkward
| workarounds turn it into REST with none of REST semantics
|
| - default query method (POST) cannot be cached by literally
| anything in the infrastructure because POST is not
| cacheable by definition. The awkward workarounds require
| you to parse and look up fields in both request and
| response. Both of them arbitrarily large.
|
| - instead of delegating requests to optimized queries (db
| or services) you now collect all that data manually, in-
| memory, on the server with little to no insight into what
| the data is, and how to optimize its retrieval
|
| - default types doesn't provide useful primitives like
| dates
|
| - you now have to keep up with evolution of every single
| microservices you depend on
|
| There's more that I've forgotten.
|
| It's really good for building internal tools that usually
| have different requirements than what existing APIs provide
| you
| flashgordon wrote:
| One thing Id suggest - "gRPC might be an option but most teams
| dont need it" - needs a revisit. As a backend-dev (who does
| front end when needed - and that too by slapping NextJS on an
| API) I have found starting from a grpc set of services and
| generating http/openapi specs from it to be much for
| maintainable and understandable than starting with the OpenAPI
| spec and working "inwards". Apart from a (mostly) single source
| of truth for my interface intent - I also get a system that is
| amenable to scalability concerns than most of the time when I
| started working inwards. I might be in the minority as most
| folks who build services come from a product background?
| jensneuse wrote:
| If we compare gRPC to OpenAPI, we get the following. gRPC
| will be faster at the tradeoff of complexity. You need more
| tooling, you cannot easily inspect binary traffic, you cannot
| simply call gRPC from the web, you need a grpc web proxy,
| proxies and API gateways are more complex for gRPC than for
| an OpenAPI/REST-ish API, and the list goes on. I can put my
| protobuf in a registry, but the same applies to OpenAPI. So
| what really is the difference? And do we really need the gRPC
| level of performance with this hefty price of complexity? I
| doubt it. Most of the time, your database will be much slower
| than what gRPC might give you in performance compared to
| OpenAPI.
|
| Sorry if I'm pushing back on this. It's not against you. I've
| just seen way too many devs and teams who created gRPC
| "micro" services and all they needed was one boring well
| designed OpenAPI monolith with good architecture.
|
| gRPC is great if you really really have the problems it tries
| to solve. I believe most companies have a much bigger problem
| than performance, the inability to design APIs. You cannot
| solve bad API design by using a faster tool. Fix your API
| design, OpenAPI is great.
| random3 wrote:
| Here's a bunch of random points (this deserves a full blog
| post)
|
| - it's not about performance
|
| - OpenAPI needs and has tooling (it just doesn't work) -
| think about documentation, client/server code and evolution
| support for forward/backward compatibility, type safety,
| etc.
|
| - you can build monoliths and microservices with both
|
| - gRPC / protobuf gives you a pragmatic separation of
| concerns (and typing among other things)
|
| - gRPC allows exposing REST/OpenAPI with defualt tooling
| and it works
|
| - there's an extensive set of best practices that combine
| the best of both worlds - just read https://google.aip.dev/
|
| - if the workd prefers GraphQL, you're out of luck
|
| - gRPC / protobuf help you focus on the actual contract and
| make everything else (that's 90% of time) a non-problem.
|
| ---
|
| Disclaimer: I'm in the grpc (and protobuf) camp and have
| built APIs with REST, Thrift and gRPC/Protobuf for more
| than 15 years (gRPC mostly last 5 years) As an
| infrastructure startup we have to both expose and consume
| both REST and gRPC.
|
| If you build APIs and decide to handle the above manually -
| you must feel productive doing work that compilers and code
| automation tools have been invented for. However tooling
| should automate it for you.
| flashgordon wrote:
| Pushback is always good. I am not buying the argument (from
| having done large scale systems in both) that OpenAPI is
| significantly more productive than grpc - especially when
| building SaaS/control plane services. I do agree tooling is
| "prettier" for OpenAPI but that is artifact of needing that
| level of tooling for a spec that to me never felt as
| expressive to begin with (have to be careful not to get
| into Yaml vs syntax wars her). On the contrary
| reading/modifying/consuming grpc specs have never needed a
| custom UI. OpenAPI is way too tied in the hip with http
| (doesnt need to be) and a lot of things evolved that way.
| Grpc never had this problem. As you may have pointed out it
| needs an extra grpc-gateway plugin to generate a http
| gateway (which I actually is neat)
|
| +1 on the terrible state of grpc cli tooling (unless you
| are already working at a faang).
|
| -1 on Web proxy - As mentioned before I actually find that
| seperating a http "transaltion" gateway from your core biz
| logic is a win in my mind.
|
| +1 On _way too many_ microservices. IMO whether you use
| GRPC or OA, you can build monoliths or way too many
| microservices. I have not felt GRPC explicitly enforced
| that. What I _did_ get from grpc is the logical seperation
| with grpc (you can still bundle multiple services in a
| single binary vs as seperate microservices) if you want.
| With grpc (nay proto spec) building a service becomes a
| logical exercise over how do i structure URLs vs what verbs
| to use etc.
|
| PS: On a completely diff note I actually like your approach
| to isomorphic types. My switching to the grpc side was
| largely motivated by this single source of truth from
| whence all layer specific types came forth from!
| lazyasciiart wrote:
| Why does OpenAPI appear to be an alternative to REST in your
| list?
| jensneuse wrote:
| I understand REST APIs more like Hypermedia APIs, where you
| go to the landing page, it contains links, you follow them,
| you leverage content types, etc... So by definition, a REST
| API has no specification, it's an API that the agent can
| explore.
|
| In contrast, an OpenAPI is a REST-ish API with an OpenAPI
| specification. It's not as dynamic as REST, it's not
| Hypermedia, it's much more "JSON over HTTP" but also not
| exactly RPC.
| shagie wrote:
| Building on this...
|
| Look at https://api.github.com/users/octocat
|
| Or the OpenID Connect and /.well-known/openid-configuration
| https://openid.net/specs/openid-connect-discovery-1_0.html
|
| And while I might be invoking scotsmen, very few things
| look like https://www.ics.uci.edu/~fielding/pubs/dissertati
| on/rest_arc... and so are best described as "REST like" or
| "RESTish".
| senda wrote:
| Should graphql ever be used to just cover all the basis of
| system integration?
| meowtimemania wrote:
| The huge thing I love with graphql (and this probably works
| with OpenAPI as well) is run time mock generation. It makes
| writing tests a breeze and semi enjoyable.
|
| example: https://www.freecodecamp.org/news/a-new-approach-to-
| mocking-...
| ElijahLynn wrote:
| Article could be improved by mentioning that the smaller rest
| requests will have a much higher cache hit ratio when used with
| HTTP/2.
| gtramont wrote:
| I take not mentioning hypermedia in a post discussing REST as a
| huge red flag. The author mentions Roy Fielding's dissertation,
| but apparenly they didn't read it thoroughly.
|
| Furthermore, I believe that a huge confusion comes from not
| understanding what a "resource" is: it is not a database table*;
| it is not your domain model*; it is a _representation of state_.
| Like this very orange page you're looking at. This whole page is
| the resource identified by
| https://news.ycombinator.com/item?id=35014395. Just like the
| stylesheet for this website is a resource identified by
| https://news.ycombinator.com/news.css.
|
| * It may be, if that's the _representation_ you want.
| ynab4 wrote:
| [dead]
| twodave wrote:
| I like GraphQL because it allows me to describe my API like a
| domain rather than just a collection of resources. REST is
| difficult to map to a true domain model because domains aren't
| just collections of resources. They have nuance. And with GraphQL
| your API matches your domain, so there's no limit to what your
| application can accomplish. For example, adding another feature
| to your front-end no longer requires going back to your API to
| add a tailored endpoint nearly as often. At worst you're adding a
| property somewhere that is now available to all your use cases.
| GraphQL embraces mutations in a way that REST frankly can't
| without being glorified RPC, and it doesn't have the same
| perverse incentives such as re-using an endpoint because it
| exists even though it may be suboptimal.
|
| So, in my opinion, unless your application is very
| resource/entity-intensive (and you don't mind a little RPC-style
| bloat) then GraphQL is often a better choice than REST. And if
| you actually have a rich domain to model (this is the case even
| for many small applications), then GraphQL is often a better
| choice than RPC.
| gofreddygo wrote:
| I love graphql. It allowed me to scrape a whole bunch of
| websites with almost no changes to my scraper.
| berkle4455 wrote:
| graphql is a data exfiltration engine, it's lovely
| WirelessGigabit wrote:
| I don't like that GraphQL is called GraphQL.
|
| Its output cannot represent a graph. Its output is finite.
|
| Consider an API that queries people. You query a married person
| and include their spouse. And then you include the spouse's
| spouse, and so on.
|
| GraphQL will render as many levels as you request without
| deduplication.
|
| JSONAPI will do this much better, you'll get 2 entities in
| 'data', and they'll refer to each other in their relationships
| block.
|
| Not that I like JSONAPI. Having built larger system with it there
| is no universal way of supporting pagination in the includes
| section which makes it a binary proposition about includes. You
| get ALL the ones you request, or none.
| foota wrote:
| It's a query language for graphs, not a language for
| transferring graph data.
| IceDane wrote:
| There seem to be a lot of people pushing back on GraphQL who
| often don't seem to understand what it really is, or what it can
| do. They often seem to think that it's super complicated to build
| and use, and that REST(-ish) APIs are somehow magically simpler
| and easier.
|
| Are RESTish APIs simple to build? I mean, yeah. You can have a
| server running serving an endpoint in like a minute in most
| programming languages. But FWIW, this also applies to GQL. Take a
| gander at any GQL resolver tutorial. But is that really what
| makes it simple?
|
| When you build APIs, they aren't made to exist in isolation.
| They're made to be consumed. Ideally, they should be easy to
| consume, which can mean a lot of things.. but "it's easy to send
| an HTTP request" is not one of those things.
|
| They're easy to consume if they are documented and come with
| schemas. They are easy to consume if there is tooling to generate
| fully typed clients for them. Arguably, OpenAPI schemas could fit
| this description, but in my experience, OAPI support is really
| varied, both on the server and for clients. Generated clients
| tend to be _lots_ of code and incredibly clunky. Support server-
| side is heavily reliant on the server libraries being capable of
| exposing schemas in some way. In some languages this is trivial,
| but in e.g. javascript or typescript, you will need some way to
| expose your types. Just having typescript interfaces isn 't
| enough(without extra tooling or reflection).
|
| GraphQL is typed by definition. The schema _is_ the API, and the
| types, and the documentation. We have great tooling to generate
| code in any language, and code-first resolver libraries(like the
| excellent pothos-graphql.dev) make building your schema along
| with your resolvers an absolute joy.
|
| Then there's things like the N+1 problem. RESTish APIs are sort
| of "procedural". Each endpoint is usually a resource, and if you
| want to fetch a resource and its related resources, you will
| often have to fetch it and them separately. You can also embed
| them in the resource, or you can resort to all sorts of not-very-
| standardized methods of conditionally expanding relationships to
| do it, which is already just sort of doing what GQL does, except
| much worse(and is I think not supported in OpenAPI at all?). In
| GQL, you can also run into N+1, but modern libraries make this
| super easy to solve. Either they can tightly integrate with
| something like the underlying ORM, or you can write dataloaders
| for your _types_ , so that every time a specific resource is
| requested en-masse, it is always loaded efficiently. Not so much
| for REST, unless you apply very careful engineering and design.
|
| GraphQL just makes all these things such a breeze. There are some
| things you need to think about, of course. Query complexity is
| one thing; you don't want someone to bring down your server using
| 30-level nested query. Thankfully, people have been using GQL for
| years at this point and most of these problems are solved, and
| many of them incredibly neatly.
| [deleted]
| coolgoose wrote:
| Well, seems somebody doesn't care about jsonapi/openapi and the
| rest of the family.
|
| Sparse field sets / compound documents are nothing new and I'd
| argue its easy to overlook that there's no magic in the backend
| for graphql either.
| zoover2020 wrote:
| I think OP didn't make the distinction between RESt and RESTful
| APIs. A pity IG you'd ask me
| doctoboggan wrote:
| I've been writing flask apps for a while (using sqlalchemy as my
| ORM) and find myself repeating code all the time when I create
| GET and POST end points for all my models.
|
| Is there a better, more automatic way to generate GET and POST
| endpoints automatically when I create a new model?
| revskill wrote:
| Just like OOP vs FP. REST is OOP (you start with resource),
| Graphql deals with function (query and mutation).
| yamtaddle wrote:
| I'm not following how shifting the resource definition from
| server-side to client-side makes it any more "FP" than REST.
| k__ wrote:
| Where does tRPC, where you start with types, fit in?
| revskill wrote:
| Yeah, it would be like dynamic type vs static type.
| satvikpendem wrote:
| GraphQL is extremely useful, if only to have strong type
| validation between disparate languages, via code generation. It
| can be a universal typed schema of your data against which you
| can use whatever server and client combo you want. It's like tRPC
| but you're not forced to use only TypeScript.
|
| I also have to plug this video [0], since many people think
| GraphQL somehow is a competitor to SQL and that it goes between
| the server and the database; it does not and has not ever been
| intended to be a replacement for a database query language and in
| fact should never be used there at all. It is only for
| client/server communication, not server/database communication.
|
| [0] https://www.youtube.com/watch?v=ZfccwYUD8H0
| [deleted]
| hbrn wrote:
| I really hate these bland, barely actionable advices with no
| examples, created for SEO purposes.
|
| Nobody knows how to measure the "complexity" and "evolvability"
| of the API and where exactly is the threshold that justifies
| going from REST to GraphQL.
|
| So here's my opinionated alternative:
|
| Use REST everywhere, unless you can justify the exception.
|
| A good exception is when you don't know the audience and use
| cases for your API. E.g. if you have hundreds of different apps
| using the same API and you have no idea _how_ they are going to
| use it. You know who does it? Facebook.
|
| If you're just dogfooding an API for your website, you don't need
| GraphQL. If you need one service to talk to another, you don't
| need GraphQL.
___________________________________________________________________
(page generated 2023-03-03 23:00 UTC)