but beginner to mid level developers are lead down the path of USE GRAPHQL especially on youtube... and this is just unfair and wrong.
The good:
- It makes working with describing the data you want easy
- It can save you bandwidth. Get what you ask for and no more
- It makes documentation for data consumers easy
- It can make subscription easier for you to use
- Can let you federate API calls
The bad
- It is actually a pain to use, depending on the backend you are using you'll have to manage
two or more type systems if there are no code first generates in your language
- It doesn't support map/tables/dictionaries. This is actually huge. I get that there might be
some pattern where you don't want to allow this but for the majority of situations working with json api's you'll end up with a {[key: string] : T} somewhere
- No clear path for Api versioning you'll end up with MyQueryV1.01 MyQueryV1.02 MyQueryV1.03
Don't use Graphql unless you're managing a solution/problem set that facebook intended graphql for
Invest your time in a simpler solution then running to GraphQL first
thanks for reading my ted talk
please any senior dev's drop your wise words so that any new dev's can avoid tarpits
The more fine-grained nature of boring REST calls makes it more easy to control client impact on the system.
If you want to see the kind of work you actually need to put in to make a graphql API, look at Shopify. They have rate limits based on quantity of data returned. Cursors and pagination. The schema is a huge ugly mess with extra layers that never show up in the pretty examples of GraphQL on the internet.
Note that even if you use graphql for a private api to your web client, folks will reverse engineer it and use it for their own purposes. There are no private apis on the web.
I'm not a fan of graphql for anything that the public could see. It's somewhat akin to exposing a SQL interface; it opens up too many avenues of trouble. Keep public communication channels as dumb as possible.
We also have user roles, which, if you’re an admin, you can run raw queries of whatever you want, but basic users are locked to the persisted query options.
It’s pretty cool, definitely adds complexity to our builds/permissions, but it works. We rolled our own, but I think Apollo GraphQL supports this out of the box now.
Not saying people should use GraphQL for everything though. It’s kind of overkill for a lot of apps.
I worked with a team that was going down a similar path. At some point it felt like they were reinventing REST on top of GraphQL with a strict set of predefined queries and result shapes.
They hadn't gone too deep into GraphQL tooling so we just switched to REST and implemented those predefined queries. Had a separate, developer-only GraphQL endpoint for prototyping things for a while, but the production stuff was easier to just build out as plain old REST.
I was later involved in productising said research into an API gateway (called DataPower) offered by IBM. We implemented our GraphQL static analysis in a quite flexible and performant way (all of GraphQL's query validation and the static analysis are implemented in C++). The required configuration for the static analysis can be provided using GraphQL schema directives (cf. https://ibm.github.io/graphql-specs/cost-spec.html). Unfortunately, DataPower is quite inaccessible to the common developer.
I find that persisted queries are a very interesting approach to also solve this issue. They still grant developers the full flexibility to define queries during development, but then require providers to validate and vet queries only once before persisting them (instead of validating and vetting queries on every request). This has huge benefits for runtime performance, of course.
Deleted Comment
[0]
A very simple convention for including nested resources in a JSON API: https://www.jsonapi.net/usage/reading/including-relationship...
A totally cool but kinda over the top library that exposes a REST API over your database with a very GraphQLesque query string syntax that supports recursively nested resource inclusion, filtering, etc.: https://postgrest.org/en/stable/api.html#nested-embedding
It gives you all the benefits of GraphQL during development while in production you’re only dealing with JSON-RPC
How is this a GraphQL specific problem?
Can you give an example?
query dos { allDogs(onlyFree: false, limit: 1000000) { id veterinary { id dogs { id veterinary { id dogs { id veterinary { id dogs { .....
It's that the team maintaining the API is different from the team that needs changes to the API. Due to the scale of the organization the latter doesn't have the access or know-how to easily add fields to that API themselves, so they have to wait for the maintainers to add the work to their roadmap and get back to it in a few quarters. Relevant Krazam: https://www.youtube.com/watch?v=y8OnoxKotPQ
At a small start-up, if the GET /foo/:fooId/bar/ endpoint is missing a field baz you need, you can usually just add it yourself and move on.
Some reasons:
- Front end devs save time by.... sharing queries. So component B ends up fetching records it has no use for because its sharing GQL with component A.
- Backenders never optimise column selection. You may think you are really optimising by sending a GQL query for one column, but the backend will go ahead and collect ALL the columns and then "filter" down the data that was asked for.
- Backenders can also forget to handle denormalisation. If you query related many to many records but the GQL only asks for related ids of implementations will go ahead and do a full join instead of just returning results from the bridge table.
- Frontenders aren't even aware you can send multiple graphql GraphL requests simultaneously.
GraphQL is great, but any technology is limited by how well people can extract its value. I personally feel sometime we'd be better off with REST, or at least make sure people receive the training to use GraphQL effectively.
An unfortunate problem that really only exists with Apollo. Facebook’s graphql client, relay, does not have this issue as it requires each component to explicitly declare its data dependencies.
Making scalable, well performing queries work is nontrivial, particularly with the current ecosystem of GraphQL libraries. The main workaround for this provided appears to be directly mapping GraphQL to an ORM.
But more and more, I think Backend For Frontends solve this issue in a much better way. And of course that idea isn’t new and Yahoo for instance had that kind of architecture.
Frontend teams get to adjust by themselves a simple interface to their needs, and backend teams can provide more info through internal APIs with less restrictions than if it was directly exposed to the outside.
So what you can do is some sort of generative graphql thingie when doing your initial iteration, with the client hitting whatever is convenient (in that situation you'd just expose the entire backend unprotected).
Once the needs have gelled out you strip it out and replace the graphql queries by bespoke API endpoints.
The other part about team dependence is very true but it also shows a lack of knowledge/thinking/care by whoever formed the teams. It seemed for a while Amazon had things right both in terms of boundaries of teams and in terms of forcing people to use APIs- not sure what they do these days.
Backend developers describe the data model, expose it via graphql. Front end developers, often ones who never met those backend developers, can see the data model and just use it. They can change what they're querying on the fly, get more or less as they see fit.
It lets everyone move faster.
But as a backend developer, I actually fucking hate it, myself.
You should probably be comfortable enough to work with both ends of the spectrum, but specialization allows you to do a much deeper dive into complex subjects.
A backend engineer probably has a much deeper understanding of every little nuance of their prefered database. A great backend engineer can make sure that you're getting near-optimal performance from every important query.
A frontend engineer probably knows about various UX techniques along with how to avoid unecessary reflows and repaints. A great frontend engineer can implement a UI toolkit as well as advanced techniques such as windowing.
The separation of front/backend has always been mildly entertaining to me and I’ve worked on both teams. Btw, if you ever want to cause a political mess, just submit a PR to add a new API endpoint to the backend team that “doesn’t have the time” to work on it. Woah boy, they will get mighty pissed. As a backend engineer these days, it would be a blessing to get free work from another team… I don’t know why they were so pissed that one time.
If your API looks like this...
where each platform has its own subtly different UI structure, the ability for frontend teams to get basically an arbitrary JSON structure of their choosing starts looking worth the extra work on the backend.You might not encounter this problem at any point that's fine - there are other ways to avoid it, like having a cross-platform codebase. I have "hand-rolled" similar solutions to the GraphQL field selection before, and I would use the GraphQL protocol if I were to do it again today.
People specialize in different things. A great React developer may not be a great Java developer, and vice-versa
FFBs and GraphQL is a way to tightly couple to a backend system and then have that backend system loosely coupled.
I guess its all 6 of one, half-dozen of the other, but I usually prefer to just handle things client side. You can maybe get less data transfer optimization but that's down the road from the fast development stage, anyway.
Has this been addressed? I don't see how you can decouple the back-end data from front-end queries without that.
``` const SAMPLE_JOIN_QUERY = gql` query ($main_data_id: String!) { mainData( main_data_id: $main_data_id) { id main_data_field_1 main_data_field_2 main_data_field_3 related_data{ related_data_field_1 related_data_field_2 related_data_field_3 } } } `; ```
Segmentation makes some sense but the industry is lacking end to end thinking as you point out.
Until I understood the point, the organizational decoupling. Then it clicked why it's great.
GraphQL is a way to describe not only your API but also the entities and relationships in it. This enables certain useful things for client heavy applications, like cache normalization. If you look at clients like URQL they enable high quality features in your app that are otherwise extremely difficult.
You can also do this with JSONAPI but the GraphQL ecosystem is more developed.
Setting up GraphQL to minimize its rough edges is incredibly difficult. I've currently landed on a combination of Pothos + Genql + URQL to enable me to do everything in typescript instead of untyped strings.
It takes very high skill to use GraphQL well. Few teams get there because they don't have the upfront time to do all the research.
But if you pull it off it can be an incredibly productive system that is friendly to iteration and refactoring. I can send you some content we've produced on this if you're interested.
That said, if I'm not working on a client heavy app, I'd just use a less featureful RPC framework.
This isn’t that though; the first sentence starts “GraphQL is great, but” and then the post lists first “the good” and then “the bad.” Even the provocative headline hedges with “kinda.”
I wish there was more of this sort of balanced discussion on HN. There is a tendency among devs at least in public toward trying to get others to use the tech they use and are excited about, which is understandable, but everything involves trade offs and it would be nice to hear more of those up front (as opposed to one day “mongo is the bomb” and the next “actually mongo is terrible to back to postgres for everything).
while the discussion can be balanced the real world outcome is normally binary: use it or drop it.
i will not start investing huge amounts of time to learn graphql if it has very specific use cases for specific environments. so i naturally look for red flags and objectively negative experiences to see if those might be the roadblocks i would run into 2 months down the line.
imagine a PM coming in all happy "i know nothing about graphql besides the hype but i think it's a great fit for our next project". where will balanced discussion take you there?
It is perfectly fine to start with an early implementation that treats GraphQL as mostly an RPC, with only resolvers for Query & Mutation types. You still benefit from GraphQL's type-safety, batching and code-generation.
Once you have more familiarity with dataloaders, query complexity etc. update your output objects to have links to other output objects building the graph model.
The issue is that too many people get fascinated with GraphQL early, then build deep & complex topologies and expose it in inefficient and potentially insecure way.
On the flip side, you should also be careful of anyone who says some technology is 100% good always. It's far more common to see people talking up the advantages of some trendy new technology without ever mentioning the downsides. All technologies have tradeoffs.
THIS 100%.
> It takes very high skill to use GraphQL well. But if you pull it off it can be an incredibly productive system that is friendly to integration and refactoring.
I could not agree more. It's like any other piece of tech: once you internalize the mental model and are able to translate those abstractions in your language of choice everything clicks. And then it's hard to imagine going back to something more "primitive" (i.e. what's conventionally called "REST").
After building "RESTful" APIs for years I can confidently say GraphQL (with a decent implementation) is a step up across almost every possible dimension (performance aside because of the additional parsing).
While this is true, I think the ultimate assesment of a technology is how easy is it for someone skilled at doing similar work to internalize the model and abstractions.
A tech stack can become really successful only if this is easy and relatively quick, otherwise, it will meet a lot of resistance. Partly because it's hard to master, but partly because so many people will be misusing it (which makes an even bigger annoyance for someone who's trying to get to a proper mental model).
As such, I've come to appreciate only models that majority of developers can easily get right on the first go: or rather, models which are hard to get wrong.
Completely agreed. Without knowing the team experience, greenfield project or not or in general more information about the task at hand, how can anyone say GraphQL is good or not?
One thing I've noticed among some people who've failed to move up in their career is that they carry these extreme opinions due to a proper understanding or a bad experience. Right tool for the job and all that.
Have you never used MongoDB?
So what does this mean?
You're saying that in the universe we live in there is absolutely nothing that is 100% bad always. Everything is good for something? There is no concept of bad or obsolete things because it's all good for something?
Let's restrict this to programming languages and frameworks and apis.
Are you saying that in the universe of ALL programming languages, ALL frameworks and all APIs, None of them are at all bad and they are all good for something?
I don't agree with this sentiment at all. In fact I think it's a sign of two possibilities:
1. that the person saying it is highly biased and unable to detect things that are genuinely bad.
2. The person saying it is just being temporarily illogical, there are clearly things in the programming world that are bad. He knows this but is so biased that he's incapable of processing this concept while promoting his favorite language/api/framework.
Scenario 2 is the most likely scenario here. Not saying graphQL is bad. But to love graphQL so much as to say Nothing in the universe is actually bad?
Let's be real, I am not against graphQL. However you cannot actually say that people against graphQL have invalid opinions because there is nothing in the programming universe that is definitively bad. This argument does not make any sense at all.
For example:
1) “Haskell is bad because it’s too theoretical” 2) “Haskell is bad in corporate environments, as its roots in mathematical and academia make it harder for people to get productive with it compared to something like Java or C#”
The difference is clear. In my opinion it’s best if people who care about what they’re saying avoids #1, and instead frames their criticism like in #2.
Note: those examples don’t reflect my actual opinion on Haskell, it’s just something I came up with while writing this.
Default hostility to new concepts and frameworks can save a lot of time, energy and mistakes in software but sometimes for some use cases the new (variation of an old) solution can be superior.
We use it as the API we expose for our React and mobile clients and it's just, so good. I'd never want to consume it for a non-FE client but it's night and day versus stitching the results of multiple API calls together using some godawful chunk of mess like Redux.
We have a C# backend and Typescript frontend. We write our backend resolvers of the form `public async Task<SomeResultType> GetSomeNamedField(TypedParams pq)` and it just works, Apollo generates type safe client code and we define the schema in a single place. We still write backend code to implement each resolver method, exactly how we did in a normal API but... that's just the same.
I wonder how bad other backend devx must be for all these people to hate it, it seems more like a language specific implementation flaw than a genuine problem.
What I've noticed is people get their first taste of a type safe api and automatic client creation via GraphQL and don't understand that exists without it.
I mean, yes, you can technically write any project in C if you're smart and dedicated enough, but data scientists still use Python because it's easier to work with for the things they need to do. The fact that GraphQL is inherently safe, while REST is inherently not, is why people like GraphQL. OpenAPI is hardly the standard in Rest APIs.
- Makes caching more challenging since there are now more possible permutations of the data depending on what query the client uses. A hacker could just spam your server's memory with cache entries by crafting many variations of queries.
- Makes access control a lot more complicated, slower and error-prone since the query needs to be analyzed in order to determine which resources are involved in any specific query in order for the server to decide whether to allow or block access to a resource. It's not like in REST where the request tells you exactly and precisely what resource the client wants to access.
- Adds overhead on the server side. It requires additional resources to process a query rather than just fetching resources by ID or fetching simple lists of resources. A lot of work may need to happen behind the scenes to fulfill a query and GraphQL hides this from the developer; this can lead to inefficient queries being used. I have a similar complaint about database ORMs which generate complex queries behind the scenes; this makes it difficult to identify performance issues in the underlying queries (since these are often completely hidden from the developer). Hiding necessary complexity is not a good idea... Maybe worse than adding unnecessary complexity.
You could use something like https://stellate.co/.
> - Makes access control a lot more complicated, slower and error-prone since the query needs to be analyzed in order to determine which resources are involved in any specific query in order for the server to decide whether to allow or block access to a resource.
Hasura and Postgraphile can do this - in the case of Postgraphile it obviously requires Postgres.
> It's not like in REST where the request tells you exactly and precisely what resource the client wants to access.
It can be. You can have a query that does `getObject(id: $id): Object`.
> Adds overhead on the server side.
Yep it pulls a heap of complexity around data fetching, synchronisation, and data modelling from the client to the server.
As it requires both the client and server to come to some agreement about a shared data model, it can appear as more work up front. But it enables a decoupling of the client and server such that the client can make requests for new use cases with the existing shared data model.
> No clear path for Api versioning
GraphQL came about as a way for mobile clients to call backend services. At Facebook, once a version (of th emobile app) was released, it was essentially out there forever. Some people would simply never upgrade until they absolutely had to.
So the point of GraphQL is that you want to get away from thinking about versioning your API and cleanly upgrading because you probably can't. You can do versions but you don't have clean divisions. You'll mark a given field as "since v2.1". And fields that you ahve added can basically never be removed. The best you can do is make them return null or an error.
So if you want to do versions it probably means you have control over the server and the client such that you can deploy them almost simultaneously. If so, GraphQL isn't really designed for your use case. If not, get out of the mindset that client and server versions can move in lockstep.
I will say I think GraphQL made one mistake and that's baking in string values into the API. You can't change a field name without breaking your API. Same with enum values.
Protocol buffers (including gRPC) instead went for numbering. The name is just a convenience for reading the IDL and data definitions and for code generation but it doesn't translate to the wire format at all.
This can have downsides too but they're fairly minimal. For example, if you accidentally renumber your enums by inserting a new value in the middle, the whole thing can break (side note: always explicitly number your enum values in protobuf! That should've been the only way to do it).
Another issue is that fragments seem like a good idea for code reuse but they can get really out of hand. It's so much easier just to add a field to an existing fragment. If that fragment is used in a bunch of places you may find yourself regenerating a ton of code. You will never be able to remove that field from the fragment once added.
Disclaimer: Ex-Facebooker.
This nails it. For distributed apps where a client might never be updated, you can't really change your schema if you want to guarantee that your app works for everyone. You can build in a mechanism to prompt users to update to a later version, though, and that can be very effective.
1. Remove all uses from the frontend. 2. Deploy. 3. A day later, delete it from the schema.
If deleting it causes relay compiler errors, go back to step 1.
(The less lazy way to do it would be to actually pull some stats about how long-lived frontend bundles are)
Not being able to delete fields only really applies if you have a huge number of clients that you can’t easily force to update on a whim. Plenty of folks just have web clients.
My company doesn’t have this, but I’d love to get per-field usage stats about our schema.
* Autogenerated documentation
* Autogenerated wrappers for scripting languages
* Autogenerated validator for requests and responses
For a REST API, you can get most of these things with swagger or stuff like that, but clearly it's an afterthought. If you have a schema, it's all much more natural and elegant.
But the most important thing you get with GraphQL is batching. For our use case (a decompilation pipeline) if you make 10 requests one after the other or 10 requests altogether it makes a huge difference in terms of performance.
If you need batching and design a REST API, for every nice endpoint you have you need to make a bulk version of the API. You're likely going to do that POST'ing a JSON. Now, once you're at that point, you're reinventing the wheel with six sides.
If your backend is in C/C++ and I suggest to make a C API for Python and use ariadne:
Don't do GraphQL in C/C++.Doesn't HTTP/2 make this mostly obsolete? One of its big features is request multiplexing.
Regarding the auto-generated code bit, are auto-generated GraphQL clients a thing? It seems like it would be doable, but I haven't found any (at least for the languages I'm using).
HTTP/2 helps with the network layer, but your backend will still handle requests one-by-one. Depending on what you need to do, this might make a hell of a difference.
> Regarding the auto-generated code bit, are auto-generated GraphQL clients a thing? It seems like it would be doable, but I haven't found any (at least for the languages I'm using).
There's this:
But yeah, on a second look I expected to find more. Anyway, having a standard way to do things instead of relying on one specific piece coupled to some language (swagger), it's certainly better. On the other hand REST APIs have a much longer history, so I guess it's normal for them to have more tools.