We're looking at adopting GraphQL and for writing a CRUD app it seems insane. Being able to project out individual fields seems like a niche benefit for bandwidth constrained devices. Instead of doing joins in an RDBMS you write a dataloader which merges select queries. The queries themselves seem like a lot of repetition in the client codebase, plus the complexity of the server-side implementation.
Am I alone in thinking this is a ridiculous solution to replace traditional REST endpoints?
>Am I alone in thinking this is a ridiculous solution to replace traditional REST endpoints?
You're not alone. I went down the GraphQL path a year and a half ago. I was telling everyone it was going to be the future, then I got tired. GraphQL requires a lot of configuration and setup to get working right. The decent implementations of GraphQL are all proprietary solutions like Apollo. When you feel like you're spending half your time setting up a simple backend and API, it's a red flag.
Despite efforts made to improve GraphQL, things like caching are still a nightmare are in comparison to the out-of-the-box browser caching you get with a traditional REST endpoint (because GraphQL implementations all use POST by default). No plugin I tried for Apollo gave me proper caching, I even tried to hack something together at one point.
The smaller payloads are definitely great and being able to query for specific pieces of data is fantastic, but it's a lot of work and it's not perfect. I found using it can make a simple app incredibly complex, then you have to maintain the schemas, implementing data loaders requires some work to get done right. There is a reason a lot of backend developers push back against the suggestion of using GraphQL.
Don't get me started on things like authentication, file uploads and protecting your server from being DDoSed or driving up your cloud computing bill by someone creating expensive queries. There are solutions to these things, but they require more configuration and work to get right. The fact out-of-the-box someone can create a GraphQL server and essentially make themselves vulnerable to a big AWS bill or have their app brought to its knees trying to fulfill an intentionally complicated query is kind of concerning, these things should be default settings.
I went back to REST about six months ago and never looked back.
You're not alone. I recently took over an Elixir application that uses Apollo/GraphQL. To say the least, making a simple change requires traversing and updating a bunch of code in several areas. For example, if I want to add a single field in an endpoint: Update Apollo, update the GraphQL schema, update the resolvers, update types, update the schema. Makes me wonder what the advantage is. Would just love to go back to a basic REST implementation. Elixir's routing pipeline handles that so well.
Interesting. We're using apollo-server on top of an existing REST api and to add a single field our process is:
- update the graphql schema
- implement any resolvers
and we're done. More things happen in the background, but a developer doesn't have to do anything. It's all auto generated when the file is saved or a build happens.
I'm lukewarm on GraphQL myself, but good tooling can definitely go a long way here. https://hotchocolate.io/, in the Dotnet ecosystem, is one of the better versions of handling some of those longer tail items out of the box.
Rigging it up to EFCore is a pretty magical experience. Because projections are built into the language with LINQ, the two paradigms can be wired together in a pretty delightful way.
I set up GraphQL with express-graphql on the backend and then I just use fetch on the frontend. I didn't feel the need to use Apollo. It felt fairly simple.
I just define the schemas in Javascript, which works fine.
But we also use standard HTTP POST + path based routing for some things. Like file uploads.
>Don't get me started on things like authentication, file uploads and protecting your server from being DDoSed or driving up your cloud computing bill by someone creating expensive queries.
These are API Management requirements, and they require a different treatment from the traditional approach, just granting access and checking rate limits is not enough. One approach is to statically analyze the query and determine how it will affect your backend, and how much data it intends to retrieve. Products are starting to come into the market, recently IBM API Connect had this announcement about it: https://community.ibm.com/community/user/imwuc/blogs/rob-the...
I’m a huge fan of GraphQL but your comment about proprietary triggered a memory.
When searching for answers on how to do things like pagination, the answer I often got was “Oh just use this proprietary thing” and that is NOT a solution.
I’ll concede that using GraphQL in a great way requires FAR more setup than REST but the benefits are worth it, to me.
> can create a GraphQL server and essentially ... have their app brought to its knees trying to fulfill an intentionally complicated query is kind of concerning
I've seen this denial of service attack against SQL/Relational databases as well, and I imagine if it triggers more read replicas, that a large bill could be caused as well
Have you looked at Hasura (hasura.io)? Allows you to carefully expose your database as an API, while allowing you to build serverless endpoints for validation, business logic and side effects. Bakes in authorization as a first class concern. There are some other similar alternatives that do much the same.
Think it's a mistake to consider GraphQL as a drop-in replacement for REST, writing a vanilla GraphQL server is indeed quite arduous as there is a lot of important concerns like auth that you don't get out the box.
But if you're just wanting to expose your database in a controlled and secure manner, with a smattering of business logic, think some of the technologies that have evolved around GraphQL like Hasura and PostGraphile can make it a joy to use.
Think the wonder is that the schema definition language/schema introspection wasn't just tacked on at the end (unlike REST w/ Swagger and OpenAPI) so all these tools have developed around the tech. There is also a bit less of an object relational mismatch than in REST.
I recommend to watch the documentation about the facebook people that invented GraphQL [1].
Listen careful to which problems they solved with graphql, then think about the problems you have to solve for your application. Most of the time GraphQL is not worth its tradeoffs.
I think it's mainly useful in a (complex) public API.
I haven't actually used it yet, but am considering it, despite the complexity it introduces, since it promises to improve some of our pain points:
1. The client requesting specific fields enables the provider to track which fields are used. This enables fine grained deprecation notices. In my experience I rarely want to replace complete endpoints, but it often turns out that specific fields are either badly named, or don't really make sense anymore.
2. The ability to get data about related objects simplifies the client, but increases complexity on the server. Since there are many different clients (in our case every customer writes their own integration), this is often a worthwhile trade-off. For example when getting an order, the same API call could return needed product or customer data.
For internal APIs with moderate team sizes, I'd define endpoints specifically for each consumer, instead of REST or GraphQL.
Although I haven't used it personally, I can see it being very useful for APIs where the "objects" involved contain many fields/relations. Rather than coming up with a limited set of filter/query parameters, you can take advantage of a query language with tooling.
That being said, one of the things that irks me about most* GraphQL implementations is that they seem to do joining entirely server-side. This makes sense if you have to join data across multiple services, but if you're only dealing with a single data back end (like a database) then you can't take advantage of JOINs.
If anyone knows otherwise, feel free to correct me. As I said, I don't have any practical experiences with GraphQL.
*I'm aware there are one or two GraphQL libraries that support JOINs, but most do not.
While it's true that REST has no concept of joins, when retrieving designing an API using REST, one often has to decide whether to return data related to an object as part of a query for the object, or to force the client to make secondary lookups.
Regarding GraphQL, one of its big selling points is that you can query not only for specific fields, but fields in nested data as well.
Lets take two possibly equivalent queries, modeled on the data discussed in the GraphQL tutorial[0]:
# REST Call
GET /hero?primary=true
# GraphQL Query
{
hero {
name
friends {
name
}
}
}
Ideally, these queries would result in the following SQL query when one wants to also get the primary hero's friends:
SELECT
heroes.name,
(
SELECT heroes_inner.name
FROM heroes AS heroes_inner, friendships
WHERE friendships.left = heroes.name AND
friendships.right = heros_inner.name
)
FROM heroes
WHERE name = ? AND primary = true;
(This query might not be exact, but it should get the meaning across.)
Of course, this presumes that the REST query selects friends names as part of the request, and that the client doesn't have to manually perform a join/secondary lookup to retrieve additional data. If it doesn't, then you might have to perform additional REST calls to get all the friends of the primary hero.
The benefit of selecting specific fields is easily achieved in REST, see how PostgREST does it for an example of passing a select parameter listing the fields to include or exclude.
The negative side effects of selecting specific fields include limited caching - in most cases it makes sense to return full records from the server for further filtering in the client, with the added benefit of free caching for GET requests provided by the browser. I find that gzipping JSON works so well in practice that it's rarely worth selecting specific fields. Using a binary protocol as an alternative to JSON would be more advantageous imho.
I use GraphQL as my main solution to build APIs these days and I have worked with GraphQL for almost 4 years.
I agree with you that "being able to project out individual fields seems like a niche benefit" and I almost never use it to let anyone ask for anything. I rely on GraphQL mostly for its schema in order to have a coherent view of my API at all time. I can thus easily validate my frontend queries during continuous integration and I know the structure and type of the result that I will obtain from my queries.
When I refactor my API, I can evaluate the impact quite easily since my build will tell me about invalid queries in my frontend and unused fields too (since I am building my API for known clients, unused stuff has no place in my API). It brings me the same security net during changes to my API as TypeScript does.
Since I'm not building my API for unknown clients which could ask for anything but instead for specific clients that I can control, I am still doing most of my joins in my datastore. I am relying on a Java implementation of GraphQL and I don't feel any GraphQL-specific complexity on the backend, it may be different with other implementations of GraphQL. In Java, with a minimal amount of annotations, most of my schema is created automatically from my data classes.
> Am I alone in thinking this is a ridiculous solution to replace traditional REST endpoints?
Consider implementing GraphQL over a REST-like API if you tick at least one box of:
- Your API has multiple consumers, not just one front-end.
- Your backend has a multiple, possibly heterogeneous providers, for example a set of different APIs.
- You need to decrease the frontend and backend coordination.
- You want to offload complexity or expressivity to the consumer.
---
An example of when not to use it IMO:
We ruled out GraphQL in a current/new project very early on, even though good libraries, tooling and knowledge was all there.
- The coordination is very high and unbureaucratic (small team of full-stack developers).
- single backend, single frontend
- We are very comfortable with SQL and don't need something to patch over an ORM or other scaffolding.
- We are iterating over a specification => the functionality is clear => we can choose where complexity resides. => we decided to keep the frontend simple and optimize on the backend.
Not saying it's not still ridiculous for your use case, but if you're using Apollo as your GraphQL server, you can still do your joins without data loaders. The 4th argument passed to your resolvers [0] allows you to check if children properties have been requested and then you can use joins to "pre fetch" those without data loaders. Haven't done it myself yet but someone told me about it on HN a while back.
In my last job we considered it was well (2.5-3 years ago I think), and decided it wasn't worth implementing the GraphQL server part for just a limited set of clients that could basically use a small set of REST endpoints. We were building a video streaming app exclusively for the Belgian market, so bandwidth was not a concern.
GraphQL shines when you have a big(ish) data model with a high variety of queries you want to run on the client. It's also cool if you get it for free with your tech stack, I think. But if you have to implement a complex GraphQL server stack yourself to work with existing data sources it's definitely not always worth it.
It totally depends on your use case. Indeed, the best perk, as you've pointed out, is the ability to reduce the quantity of data that runs over the wire. If well-configured, then GQL certainly makes network usage heavy mobile apps much faster. This was the main impetus behind why Facebook decided to build it.
If you're willing to add massive technical overhead to solve this, then GraphQL may be worth a shot.
But if you’re the only consumer of the api then it doesn’t help reduce data, unless your UI is configured to show different amounts of data.
It also doesn’t make network requests faster. I would argue it’s slower when returning the same data between a rest api and graphql. The difference is you don’t do unnecessary joins when you don’t need data. (Since most graphql apis are in front of a relational database anyway)
The idea is that you can select the exact data fields you need for your UI. In a traditional REST-like response, say for a User model, you may receive all data (within authorization limits) about the user in the response when all you needed was the first_name field. With GraphQL you would just receive first_name without the rest of the unneeded fields, thus reducing the amount of data sent.
If you’re the only consumer of your api then why are you exposing more data than you need? I’ve never seen an internal rest api that was 100% restful. It was restLike.
So if you have consumers of your api then allowing them to pull only what they need makes sense. But for an api where you are the only consumer, it makes no sense.
If you have more than one developer working on different features, it’s inevitable they’re going to need different data. Unless you have a tight feedback loop between frontend and backend devs, you’re going to end up with pending unresolved issues requesting they add another field to be returned on a specific, custom “rest-like” endpoint. If you instead put the onus on the frontend to allow arbitrary field requests (of course within limits, typed and auth’d), this is no longer an issue. Of course the api has to have a schema defined, so there could be a request for a new field to be added there. But if all your endpoint returns is what we need NOW, then you will inevitably have to add more data to the endpoints later with new features. This isn’t of course the only benefit of GraphQL, but it’s certainly a nice convenience for those having to make those requests.
This! So many native/web apps have APIs which are only consumed by that app and are over architected chasing "REST". Just make an endpoint for the data you're fetching and move on!
There are so many apps that go from function to rest to function.
> Am I alone in thinking this is a ridiculous solution to replace traditional REST endpoints?
I've used GraphQL on a couple projects I've worked on and I still don't understand all of the hype. Thankfully I've never had to set it up from the ground up but even as an end user I don't truly understand how I'm benefitting from it.
You can use graphql just like you use REST, you can only use top level fields and graphql becomes just a way to express arguments and types in a standard way.
You are not alone. All my evidence is anecdotal, but in the last year, I sat in at least two meetings with younger devs proposing to use and older devs cautioning to use GraphQL.
I'm sure it has its uses (API with multiple frontend clients, which are changing fast), but for the classical CRUD-App, where Backend-Changes/additional routes are not super costly, I do not see the appeal.
I concur. If you’re building an api that people can consume it makes sense because the consumer can pull only what they want. Other than that I think it’s pointless.
I'm working on a project right now that's applying RDF metadata schemas to some pop culture data, and while it's not GraphQL, the idea of random queries being generated is really interesting. Our output is aimed as researchers in certain domains, and while we have researchers onboard developing use-cases, the idea that some new ones could be imagined by viewing randomized queries sounds possible.
Hey! I helped write the GraphQL query generator! Thank you so much for highlighting our library! This was a very pleasant surprise in the morning. I think your article does a very good job at summarizing our library, its benefits, and its uses. I would love to know about your experience using our library. In any case, this was super cool!
What is the current 'leading' library for creating a Java based GraphQL endpoint? We are getting limited asks to move that direction, and it seems like the 'modern' bits are all node.js based. We will see if a variable payload is something our internal folks will bit on.
Am I alone in thinking this is a ridiculous solution to replace traditional REST endpoints?