Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

Its gross because it is a waste.

An engineer had to spend time to make that specific API for that page instead of the frontend consumer using what was already defined and get all the resources with one call and 0 backend engineer needed for that new page.



On the other hand, it may take that engineer less time to create a page-specific endpoint than it would be to create something more generic that might serve other purposes (that may never come to pass), which may also involve talking to other teams, checking what future plans are, etc.

And that's assuming it's a new endpoint; if there's an existing endpoint that does almost what's necessary, they may need to check in with that team about what modifications to the endpoint would be acceptable, etc.

Single-page endpoints aren't great, but often times they're acceptable because they end up being a half-day task instead of a week-long slog.


That backend engineer wrote a single SQL query that joined some tables, ensured indices were used, and always executed in <1ms.

In graphql land you'd be doing multiple SQL queries, "joining" in the API layer, and spending 50ms per API call.


The entire point of graphql servers is that they're basically ORMs (or use an underlying ORM) that turn complex nesting into a single query's worth of joins. It won't beat hand-crafted sql from an expert, but if that's your preferred approach, debates on the relative merits of different query frameworks are all academic to you anyway.


I've never seen this kind of graphql server implementation that can automatically boil down a complex nested query to sensible SQL. It sounds like the best of both worlds. Do you have links?


Symfony API Platform boils to ORM-generated SQL via Doctrine, which is verbose, but not overly clever. So the only link I could give you there would be to the Doctrine query builder docs (I won't subject you to API Platform's docs). I imagine a more sophisticated graphql dialect like what Prisma supports can generate some pretty gnarly sql, but that's ORMs for you. But exposing your data model directly through graphql is also not recommended, same with REST APIs (I can't claim the high ground, my biggest graphql project exposes models directly. The tradeoff was worth it in this case). So in the end you're writing custom controllers/resolvers anyway, and field resolvers are where graphql really starts to shine.


Typically libraries use a Dataloader + ORM to implement this which gets you pretty far, outside of that some libs like Strawberry with automatically optimize your queries for you if you return Django ORM Querysets.

Any query you were going to build and serve with Rest can be made with these two methods or even a raw dataloader and manual SQL string.


The inventors of GraphQL did not intend it to be mapped directly to a database.

"That would be one way to implement the system in a DB-centric way. However we believe that intermediate application code is pretty critical to any GraphQL implementation." [1]

"GraphQL is a client-server dance that needs server-side capabilities, not just CRUD semantics." [2]

[1] https://news.ycombinator.com/item?id=9879870

[2] https://news.ycombinator.com/item?id=14351800


The Language Libs like Strawberry implement what he is describing by intermediate application code. It doesn't map directly to a database.

GQL implementations don't map to the database but to application code.


Specifically, GQL implementations always map to a `resolve(source, args, context, info)` function (the names can be anything, the types are what matter). In that sense, you also get a standard server interface similar to wsgi/psgi/rack, but much more fine-grained (there can be a resolver for every field in the query).


What? GraphQL is purpose built to solve that in 1 Query. Not doing it in 1 query is on you not the protocol.

In practice with REST the frontend engineer didn't want to wait and tried to use the existing REST endpoints, did N+1 API HTTPS calls and then joined them client side in javascript.


> What? GraphQL is purpose built to solve that in 1 Query. Not doing it in 1 query is on you not the protocol.

1 graphql query maybe. But that translated to a dozen SQL queries.

> In practice with REST the frontend engineer didn't want to wait and tried to use the existing REST endpoints, did N+1 API HTTPS calls and then joined them client side in javascript.

The point you're missing is that for 1 graphql query the API did N+1 SQL queries, and then also joined them in JavaScript.

In the REST case the front end can switch to the efficient custom endpoint when it is implemented. In the graphql case it will never get any faster because the API has to stay generic.


A lot of graphql implementation end up moving the n+1 problem to the query resolver.


Every GQL implementation I have seen explicitly has a way to avoid n+1 queries.


Is the flexibility worth the tradeoffs? Maybe in a company where you are adding new pages all the time with deeply nested relational data needs. But I would argue this is more rare than not. And I often find that frontend engineers aren’t as familiar with database queries and the load they are putting on the system with some of the graphql queries they are making. Flexibility for frontend has its own tradeoffs and I totally understand why a frontend engineer doesn’t want to have to wait for an endpoint to be finished. But this article outlines some of the issues you encounter later as you scale your team and system.

We use a schema first design where I am at and if a frontend person needs a new endpoint because the resource-only endpoints aren’t enough then they submit a pull request to the schema repo with a design for their endpoint they need. It gets approved and boilerplate is auto generated. Yes you have to wait longer, but 90% of the time (for our software) the resource endpoints work great.


Sorry what are the tradeoffs?

I'm not sure where this narrative comes from that GraphQL immediately means that the frontend time will have no idea what they are doing and will induce load on the system.

95% of my nested graphql fields are based on foreign key indexes so its almost no additional load to the system (only 1 query per "level" of GraphQL) to query the nested objects.

I restrict GraphQL to 5 levels and now I have 5 queries per API call instead of 5 Queries over 5 API calls.

The backend team exposes the fields that they know are efficient to query. They can restrict the depth of the GraphQL, number of fields, etc.


Every page is special. Using generalized API is waste of resources. Generalized APIs are hard to use and develop. It takes a genius to create a good generalized API (say SQL) and even those generalized APIs are not usable in web context (because of authorization and DDoS issues).

It's better to think about optimizing of creation specialized APIs.


This is like, an hour per endpoint. For maybe 30 endpoints (high figure for many apps) throughout the lifespan of your application. But let's say 3 hours: you're talking about 90 hours in total, over a period of 2 or more years. It's really not that much.

And GraphQL isn't free either; you need to actually implement that. It pervades your entire stack, too – it's not something you can just "put on top of it".

I think that in many cases, perhaps even most, GraphQL is a "spend 8 hours to automate a half hour task" kind of affair. Are there cases where that's not the case? Probably. Maybe your specific use case is one of them. But for the general case? I'm entirely unconvinced.


An experience engineer knows that a change that takes hour turns to days when a team is running at scale and needs to have CI approvals etc.

Why waste any time?

> And GraphQL isn't free either; you need to actually implement that

Rest isn't free. You have to actually implement also that and end up with a more limited API.

GraphQL libs in Python are equally as complex as the FastAPI etc..


And no one will be spending days working on it, they will work on other things while waiting for code reviews and such.

> GraphQL libs in Python are equally as complex as the FastAPI etc.

You need to account for the fact that anything can query anything, whereas a more traditional REST-type API will have much more limited codepaths.

This starts with just basic database maintenance and indexing, which in many case will be significantly more complex, to all sorts of other problems. This article already enumerates them so I'm not going to repeat them here.

You can't just handwave all of that away with "oh there's a library you can use".

If you think all of that is worth it then that's fine. As with many things it's a trade-off, and a bit of a judgement call too. But please, don't pretend this complexity doesn't exist, and that the trade-off doesn't exist.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: