Hacker News new | ask | show | jobs
SwiftGraphQL – A GraphQL client that lets you forget about GraphQL (github.com)
97 points by maticzav 1949 days ago
12 comments

Another week, another submission that hopefully edges more people towards realizing that they've just created an under-standardized, under-powered SQL-with-braackets that forces you to bring your own query optimizer, and eschews the advancements of Swagger/OpenAPI, JSONSchema, HAL, JSON-LD and the flexibility of HATEOAS.

All for a little bit of a velocity gain from declarative syntax and horizontal/vertical filtering.

This code is probably very useful to the people who made it and those in the GraphQL+Swift ecosystem, but we were already here (and just starting to get drastically better) with OpenAPI -- it's not like all the effort is only going in one direction but GraphQL really feels like a less-than-optimal branch.

The final piece of the puzzle for me will be when someone starts to replace the dynamic properties of the more advanced REST-ful techniques (API discovery, link following, etc) in GraphQL. Then the circle will be complete -- we'll have rebuilt XML (in the "linked data" respect anyway, not so much the accidental complexity side) and it's related standards twice in under ~20 years.

I don’t really think of GraphQL as a data querying language like SQL.

I think of it as a domain querying language.

SQL is meant to allow you to write queries to your data model which are:

- arbitrary, and

- efficient

I don’t think of GraphQL that way. I think of it as the place where you encode your set of valid domain actions (i.e. not arbitrary). And I don’t think the consumers of the GraphQL API should think about efficiency. They should just specify what data they need and then the backend is responsible for figuring out how to query the data model efficiently.

In other words, I don’t really see any overlap between GraphQL and SQL in terms of the role they play in a stack.

One helpful thing this distinction allows, is type inference. You can trivially write a type generator that gives you the type signature of a GraphQL query in any language. This is precisely because of its limitations. That allows you to automate the validation of your frontend and backend speaking the same language.

You can’t easily infer the return types of arbitrary SQL queries. To me, that highlights the different purposes of the languages.

> And I don’t think the consumers of the GraphQL API should think about efficiency. They should just specify what data they need and then the backend is responsible for figuring out how to query the data model efficiently.

That is the point of the SQL language. It's declarative. You define what you want your data to look like and the query planner handles the actual fetching of the information in the most efficient way it can. Obviously it's not perfect and you still have to have someone who knows what they're doing to define schemas that make sense and indexes where appropriate, but that is a separate job from defining what data is needed.

Nitpick: it isn’t SQL that lets you define what you want your data to look like, but DDL (https://en.wikipedia.org/wiki/Data_definition_language)

SQL (https://en.wikipedia.org/wiki/SQL) as the name implies, is just for querying.

I don’t see huge benefits for GraphQL. It’s a query language without a good query planner, so APIs will be limited in the kind of queries they support. In that sense, it’s similar to restricting callers to a fixed set of stored procedures instead of full SQL.

That’s a viable idea, but it can also easily be implemented in REST or using a JDBC connection.

IMO, the main benefit of GraphQL is that it allows the caller to specify what fields it wants to see returned. That means the implementation doesn’t have to send information the caller doesn’t need, decreasing bandwidth, and also doesn’t have to provide a zillion endpoints (give me only the address of user ‘foo’, give me address and telephone number of user ‘foo!’, give me address and birthday of user ‘foo’, etc.) that have to be maintained at the caller’s whim (“we also need the user’s hair color”). That, however, doesn’t need a full query language. REST could easily be extended to support it.

Yes, you could also allow fairly free form GraphQL queries, but if you do, you need a query planner (and, with it, the statistics and metadata that help the query planner perform), or end up with a rat’s nest of special cases that has to be updated for every new type of query.

The great thing about GraphQL is that it's declarative and you have to write your own actual logic to define how the fetching of information works! It only does half the work SQL does! Everyone should switch to GraphQL ASAP!
When your backend is sql how can you even do this efficiently? Databases require indexes. If you can query anything then there are performance bombs all over the place. It's different if you're querying elastic I guess.
> If you can query anything [...]

The answer is simple: You can't. GraphQL _in general_ doesn't allow arbitrary queries. It allows arbitrary output field selection. But the filters are very explicit. It's more "pre-aggregation of request waterfalls and masking of outputs" than "querying a database".

Doesn't stop people from exposing their SQL databases directly from GraphQL by generating a "free-for-all" schema. And when they do - yep, that's definitely a performance bomb and not a good use of GraphQL.

> The answer is simple: You can't. GraphQL _in general_ doesn't allow arbitrary queries.

It really does. Surely, it somewhat limits the data that you get from it by defining a schema. But the moment you allow any nesting/connections between data in that schema, hello n+1 problem.

And then every discussion of this problem on HN or elsewhere exposes the ugly truth: almost everyone uses GraphQL as a REST endpoint in production by limiting the actual queries you can run and curbing nesting.

The n+1 problem has solutions though. The most well-known solutions may not suit your architecture, but please can we stop pretending they don't exist?

GraphQL has been public since June 2015, and there's been at least one solution to the n+1 problem (Dataloader) since September 2015. If you were using pure REST endpoints (just resources, no nesting/traversal) this is the exact problem you'd be punting over to the client to solve -- all that GraphQL is doing here is moving it back onto the server. The actual amount of work is the same, you just get faster response times.

Most implementations of GraphQL I've seen in different languages provide some variation on the Dataloader pattern. I'll fully concede it can be a hassle to set it up correctly, but it works.

I never fully solved this problem, so don’t trust me, but I can tell you what I learned...

I think for one thing you can’t really rely on joins for query efficiency, because as you say there are too many combinations so it’s impossible to optimize everything.

Instead you have to try to query each data type separately. So you get a query for users. You do an SQL call and gather up a bunch of requests for offices, and then you do a single request to your office backend.

I think the best case is something like n SQL queries per request, where n is the depth of the tree you are querying (users->office->address is depth 3).

That means you’re doing all your queries after the first one by ID (not by arbitrary columns). So you have to have some way to “pre-join” your tables. You can do this either by optimistically joining your data to everything around it (query the node plus all of its edges) or you need to store your edges in your data model (which I have to assume is what FB does).

In the end your resolvers need to be using some standardized way of grabbing objects by is (or edge), something like https://github.com/graphql/dataloader

Whether it’s possible to do this efficiently I don’t know. At my last job we messed it up, and then we started applying a strategy like I described above, but then I switched jobs.

Would love to hear from others who have dealt with the same challenges.

So SQL is not a database :). It is a data access DSL that is implemented by databases. SQL being untyped I dont think is true - the table schemas are types (albeit basic product/record types). Inferring the type of a result is quite reasonable if you start with the schemas. SQl suffers from a UX problem for sure.
If we consider GraphQL to be a domain querying language, what have we gained over REST? You are free to model endpoints in REST according to your domain (and deal with complexity behind the facade), and I'd argue that REST can offer an even more ergonomic DSL interface if you just write whatever you want (s-expressions, let's say) and pass them to some POST endpoint that reads your DSL and parses it. If the idea of writing the DSL and POSTing it, parsing it, and doing the very specific logic you want sounds wrong to you, it seems like GraphQL should also similarly wrong. If it sounds good to you, then is GraphQL far enough?

> I don’t think of GraphQL that way. I think of it as the place where you encode your set of valid domain actions (i.e. not arbitrary). And I don’t think the consumers of the GraphQL API should think about efficiency. They should just specify what data they need and then the backend is responsible for figuring out how to query the data model efficiently.

This is how SQL works, so there is some overlap there. Optimizing SQL queries is might be a performance-seeking operation, but SQL is declarative, and it is left largely to the query optimizer to make your queries run fast. You can help the query optimizer make the query run fast, but that's all you can do -- and I can guarantee you that doing query optimization has not gone away due to GraphQL, you've just pushed the problem somewhere else, or you're forgetting the bits of your API that you've modeled awkwardly in order to avoid performance degradation/difficult-to-write resolvers.

But I think we're a bit off-track here -- GraphQL and REST is at a different level of abstraction than SQL. My point is that we've taken a step back from what we had already with REST rather than that people should be using SQL on the front-end. I think GraphQL is doomed to attempt to reach expressive parity with SQL but that's another conversation all-together.

> One helpful thing this distinction allows, is type inference. You can trivially write a type generator that gives you the type signature of a GraphQL query in any language. This is precisely because of its limitations. That allows you to automate the validation of your frontend and backend speaking the same language. > > You can’t easily infer the return types of arbitrary SQL queries. To me, that highlights the different purposes of the languages.

Most sufficiently ORMs can also give you this, and in other languages there are libraries that will compile-time-check the arbitrary SQL queries you write and won't compile if they're invalid. What you need to have that kind of thing work is sufficient type-checking power (Typescript offers this) and sufficiently rich metadata (there are some examples in the haskell[0] and rust[1] worlds). It wasn't necessary to throw away REST to get these kinds of benefits. I've been quite happy with TypeORM for example, and it would form a good base for this kind of effort -- I don't know a library that's already doing it, but this actually isn't as hard as you think, especially for the simple case.

I'd argue that there is no difference (without too much evidence, to be fair, as I am not an expert in inner working of GraphQL) in the difficulty or parsing and validating a GraphQL query for the simple case (i.e. the actual subset of SQL that GraphQL represents) than actual SQL.

[0]: https://hackage.haskell.org/package/postgresql-typed-0.6.1.2...

[1]: https://github.com/launchbadge/sqlx

> If we consider GraphQL to be a domain querying language, what have we gained over REST?

Part of the value is in standardization. Yes, you can get most of the benefits of GraphQL by creating your own layer over REST, but then you've just written a badly specified, bug-ridden version of GraphQL. The latter has enough momentum that there now exist tons of tools for working with it, which obviously wouldn't be true for anything you build yourself.

> Most sufficiently ORMs can also give you this, and in other languages there are libraries that will compile-time-check the arbitrary SQL queries you write and won't compile if they're invalid.

You're missing the point here: GraphQL gives you type safety between the server and client. This has nothing to do with ORMs or your database. What this means is that, when building your web (or Android, or iOS, or refrigerator, or whatever) frontend, you can guarantee the type of every part of your query before even executing it. This is a powerful guarantee, and paired with something like GraphiQL[0], it allows for a level of exploratory programming that isn't currently possible with REST.

[0]: https://graphql.org/swapi-graphql

> Part of the value is in standardization. Yes, you can get most of the benefits of GraphQL by creating your own layer over REST, but then you've just written a badly specified, bug-ridden version of GraphQL. The latter has enough momentum that there now exist tons of tools for working with it, which obviously wouldn't be true for anything you build yourself.

Right, and you could have done this standardization somewhere else right -- GraphQL is a NIH version of what could have existed on top of well-considered existing standards.

> You're missing the point here: GraphQL gives you type safety between the server and client. This has nothing to do with ORMs or your database. What this means is that, when building your web (or Android, or iOS, or refrigerator, or whatever) frontend, you can guarantee the type of every part of your query before even executing it. This is a powerful guarantee, and paired with something like GraphiQL[0], it allows for a level of exploratory programming that isn't currently possible with REST.

I was responding to the point the person made in particular, I'm aware of the mismatch in tiers, but their question was specifically about being able to infer types from SQL queries. They were comparing SQL to GraphQL. There is nothing stopping you from using compile-time-checking on the client side, if you use something like TypeScript, which is why the rest of the surrounding example was given.

This also is related to the database, because the original point was that people go GraphQL -> Resolver -> DB, rather than HTTP -> HTTP Endpoint -> DB, and because they have chosen GraphQL, they must now write efficient, general resolvers that are essentially hand-built query optimizers whereas with REST you can build with higher granularity and usually higher, easier-to-achieve efficiency.

You can guarantee every part of your query with REST as well, if what you mean is you can avoid writing an invalid query -- Typescript + generated OpenAPI client libraries do this very well -- it's not unique to GraphQL.

> Right, and you could have done this standardization somewhere else right -- GraphQL is a NIH version of what could have existed on top of well-considered existing standards.

Maybe, but I think building GraphQL on top of REST would have produced something much more convoluted and verbose. As an example, see the OData standard[0], which, at least from the client's perspective, is unnecessarily complex compared to GraphQL. There may be cleaner ways to structure this, but I'm not aware of any such attempts, and I doubt you'd get a result as easy to use and understand as GraphQL.

> This also is related to the database, because the original point was that people go GraphQL -> Resolver -> DB, rather than HTTP -> HTTP Endpoint -> DB, and because they have chosen GraphQL, they must now write efficient, general resolvers that are essentially hand-built query optimizers whereas with REST you can build with higher granularity and usually higher, easier-to-achieve efficiency.

That's fair, but as you pointed out earlier, you're just shifting complexity around in any case. REST is simple because it's so granular, which is great when all of your data needs are met by that granularity. As soon as you have more complex data requirements, you end up either making ad hoc endpoints or evolving your API into a giant monstrosity so that you can handle the more general cases. GraphQL significantly simplifies this implementation on both the client side and the API side. Yes, the tradeoff is that now you need to optimize your data access manually, but as others have said, there are now tools for dealing with this issue—and it's not like you don't gain anything from it.

For a simple but concrete example, if I need to fetch data from ten different entity types in order to render a page in my web app, I can do so in a single GraphQL query and handle caching, etc in one pass, as opposed to needing ten different REST calls and having to consolidate them by hand. On top of the maintainability benefits of this approach, the productivity gains are huge.

[0]: https://www.odata.org/

I've found GraphQL to greatly improve the developer experience when building web apps. As a front-end developer you can easily get a full view of the data and relationships. Tools like GraphiQL make exploring APIs a pleasure. And regardless of what you need to present to the user on screen, you can quickly build a request that perfectly matches the data you need. There is also the nice addition of strict typing and there are libraries that automatically generate TypeScript types for you from the schema and/or your operations.
I do agree that GraphQL has improved developer experience, or at the very least improved the perceived experience (which is essentially the same as actually improving the experience). I cannot deny it's popularity, and that comes from hype along with usefulness (perceived or actual).

> Tools like GraphiQL make exploring APIs a pleasure.

This is an innovation of the developers of GraphiQL, not of GraphQL itself. It's possible to build IDE support similar ot that of GraphiQL, with the rich metadata and schema data that is available by design in OpenAPI + JSONSchema + JSON-LD + HATEOAS land. The problem is that no one did/was excited enough to, the slog from Swagger2 to OpenAPI3 might have sapped the enthusiasm of the community just enough (or the emergence of GraphQL), but it's not that the tools isn't possible with other approaches.

> There is also the nice addition of strict typing and there are libraries that automatically generate TypeScript types for you from the schema and/or your operations.

This was already present with OpenAPI and related tools, so I personally don't put this as something that GraphQL brought about.

I don't want to piece together 4 different technologies to get the same thing.

And it's not even the same thing. You keep mentioning HATEOAS but that doesn't accomplish the same things as graphql at all. With HATEOAS I need to send out multiple requests to collect the data I need. With graphql I can send out one request to retrieve exactly the data I need. I can also combine multiple requests into a single request. GraphQL also only retrieves the fields you need by default. This is something you'd need to build manually with REST.

And yes, reducing the number of server requests does matter when you're trying to optimize for the largest market possible. Including people on slow mobile network connections where every request adds significant overhead.

> I don't want to piece together 4 different technologies to get the same thing.

> And it's not even the same thing. You keep mentioning HATEOAS but that doesn't accomplish the same things as graphql at all. With HATEOAS I need to send out multiple requests to collect the data I need. With graphql I can send out one request to retrieve exactly the data I need. I can also combine multiple requests into a single request. GraphQL also only retrieves the fields you need by default. This is something you'd need to build manually with REST.

All of this is reasonable, but my point was that we've abandoned a more flexible method, that had composable functionality and agreed-upon standards for GraphQL. You gained some pipelining, and some vertical filtering, but threw out a lot with the bathwater.

GraphQL does give you a way to do these things, and this is why it is popular (or at least a good reason why), but it is missing the wider possibilities of the other ecosystem. As people start to try and abstract over it they will be abstracting over a less robust, considered, standardized base.

> And yes, reducing the number of server requests does matter when you're trying to optimize for the largest market possible. Including people on slow mobile network connections where every request adds significant overhead.

Reducing the number of server requests does indeed matter -- I did not mean to propose it doesn't, reducing request was somewhat solved before now with the backend-for-frontend approach. There are lots of approaches to help people on slow mobile network connections, but the ultimate one is to server-render and trim as much as possible -- I'm not sure GraphQL is much better at this than REST with efficient endpoint choice.

> You gained some pipelining, and some vertical filtering, but threw out a lot with the bathwater.

What are we missing that actually matters in practice? And yes, if you minimize the problems that graphql was built to solve it seems like a worse solution.

> As people start to try and abstract over it they will be abstracting over a less robust, considered, standardized base.

Facebook, a company who's apps serve billions of people came up with graphql to solve real problems. Saying it isn't well considered is asinine. As for standardization, last time I checked GraphQL has a spec and the GraphQL Foundation is a member of the Linux Foundation.

Again, what problems are you talking about that graphql doesn't solve? I mean actual, practical problems.

> reducing request was somewhat solved before now with the backend-for-frontend approach.

So now I need to write a backend for each use-case. That sounds better. Or I need to make my endpoints extra configurable which starts to approach graphql territory.

> the ultimate one is to server-render and trim as much as possible

Again, we're now entering the "why graphql was invented" territory. Sure I could add these to my REST endpoints.. OR I could write one graphql endpoint and get all of these.

Also it can potentially reduce the client side logic needed to stitch said 4 requests together.

This can be a big complexity/bug preventer for multi client Apps (web, mobile, desktop).

To what extent are you just pushing complexity to the back-end developers?

> Tools like GraphiQL make exploring APIs a pleasure.

No argument there. Is there something similar for traditional REST? For some reason, I thought the point of HATEOS was to make that kind of exploration possible.

GraphQL cannot ever be explored in the same way HATEOAS can because it is missing the linking part (and other related technology like JSON-LD). That said, GraphQL does offer introspection[0] which is not a bad start but lacks the breadth an depth of the hyperlink based approaches.

[0]: https://graphql.org/learn/introspection/

I 100% agree with your statement. I also realize you are not championing HATEOAS here necessarily.

That said, I am curious if you have found this "linking" aspect of HATEOAS useful for actual implementations? I have been doing integration work with a system that strictly adheres to "REST level 3" and "HATEOAS" principles for the past few years, and I myself have found the "explore-ability" of the API super handy. That said, the self-documenting nature only goes so far, and in the end I'm not sure the internal linking stuff is preferable to robust documentation.

I'm not trying to be down on this necessarily, I actually generally push back on the adoption of GraphQL as the answer to every problem.

> That said, I am curious if you have found this "linking" aspect of HATEOAS useful for actual implementations? I have been doing integration work with a system that strictly adheres to "REST level 3" and "HATEOAS" principles for the past few years, and I myself have found the "exploitability" of the API super handy. That said, the self-documenting nature only goes so far, and in the end I'm not sure the internal linking stuff is preferable to robust documentation.

You're right, this is a reasonable question and the answer is uncomfortable. I personally find it useful when paired with OpenAPI -- generally by using annotations on controllers and models, but it is indeed rare to have usecases that fit the linking functionality well enough to be significantly better than what you would get from just good documentation.

The "killer app" of this space for me personally is a Django Admin[0][1] (or React-Admin[2]) clone that is 100% client-side automated. I don't have a demo yet, but once I do it'll be up on HN.

> I'm not trying to be down on this necessarily, I actually generally push back on the adoption of GraphQL as the answer to every problem.

Please, feel free to push back, that's what discussion is for, and ideas that can't stand up to push back probably shouldn't be adopted.

[0]: https://docs.djangoproject.com/en/3.1/ref/contrib/admin/#

[1]: https://djangobook.com/mdj2-django-admin/

[2]: https://github.com/marmelab/react-admin

I would like a backend developer perspective on the same.

I haven't done any GraphQL stuff myself, but the "I can get whatever data I need" aspect feels like a huge potential headache for backend devs. Won't be a problem at prototype scale, but once you have a significant client count, how do you deal with unpredictable data access patterns that can't be optimized ahead of time?

Generally speaking, it's not more difficult than creating a REST API controller. Rather than mapping your service code to a controller, you map it to a (GraphQL) resolver. It feels extremely similar.

There are different things to look out for; like handling n+1 (https://shopify.engineering/solving-the-n-1-problem-for-grap...) queries, but nothing that I can say is too difficult.

It is more difficult. With REST you know ahead of time which data you need, and you can optimise it as much as you can. With GraphQL at any given point in time you have no idea what the request is. Dataloaders solve it to some extent, but not much.
Of course, you are building something that is much more powerful. If you intend every possible GraphQL operation to perform perfectly, it'll take more development effort. Though if you optimize for only the most likely cases, the effort is not much greater.
Inevitably you do get a map of your data flow. GraphQL can be a huge help here, because you must have resolvers for the queries. It forces you to think ahead of time about how you're going to resolve getting the data to fulfill the API "contract" if you will. You can optimize that. GraphQL is great for describing your APIs in a type safe(ish) way where you get great decoupling by design.

I also will say that since a query can use multiple resolvers, that's where I have found it really shines. The model does implicitly work best when you have async systems over synchronous ones for more complex queries (multithreaded/multiprocess)

that's my anecdote, as someone who is currently and actively building and maintaining GraphQL backend services.

Its true you can get the same with any API design pattern, really, I will say, however GraphQL has specifications for all this, and I think that's what makes it more powerful

Another nice thing, is no versioning. I can just use the `@deprecated` built in directive, and when the usage of a deprecated part of an API gets consistently (for a specified period of time) down to 0, I can just remove it entirely.

OpenAPI and the like don't have a descriptive way to notify users of an API of this, you, for better or worse, have to version your API, which often ends up in situations where you always have an old version sticking around for a very long time.

Like all technologies though, it can (and does) have its issues. It adds a certain amount of complexity to your applications (more so for the client, IMO, even though exploring APIs is a huge upside with tools like GraphiQL)

I don't have especially strong feelings either way, but the majority of this is possible with OpenAPI as well.
The main advantage I’ve found with GraphQL is the normalized cache in client libraries like Apollo or Relay. It allows components to just ask for the data and not worry about how it’s fetched/stored/updated. The secondary benefit is that _some_ (not all) of the data plumbing can be moved from the frontend code to the backend, which makes for faster apps. Beyond that, GraphQL is more of a hinderance than a help... its type system in particular is brain dead and easily the worst part of the entire experience (seriously, why _is_ there a difference between inputs and types? Why can’t you define input unions, or maps, or recursive structures?)

Is there any equivalent for the latter with swagger? Yes, you can do everything in there with custom redux middlewares or sagas/observables, but it’s more glue code you have to write and maintain.

> The main advantage I’ve found with GraphQL is the normalized cache in client libraries like Apollo or Relay. It allows components to just ask for the data and not worry about how it’s fetched/stored/updated. The secondary benefit is that _some_ (not all) of the data plumbing can be moved from the frontend code to the backend, which makes for faster apps.

Is this something you couldn't achieve with the idiomatic rules on HTTP request types, and serialization of HTTP requests parameters? It really depends on where you're trying to do the caching and what kind of caching you're trying to do.

A lot of work has gone into HTTP headers, method semantics, and other details in order to facilitate caching. The "backend for frontend" pattern has been very popular as of late in order to try and shift the plumbing load, exposing endpoints that are catered to certain clients to boost efficiency -- would that be good enough for a corollary in OpenAPI land?

The backend for frontend pattern is exactly why I got sold on GraphQL. We had a pile of relatively low value server code that could be replaced a GraphQL resolver and the client got all of the advantages of that pattern. The move to GraphQL genuinely freed up a lot of our time to work on more important problems. This was on a smallish team so that time mattered.
It looks like you've picked the right tool for the job in that case, and I can't argue with that -- but the submission is for tooling that people have created in Swift for a problem that was already relatively solved by OpenAPI bindings for Swift.

Would you mind going into what that low value server code was doing? Was it simply aggregating results of multiple requests? It's quite possible it wasn't that hard to solve with slightly more intelligent (but not a completely separate paradigm) code to start with. However all-in-all I'm not out to argue that GraphQL doesn't improve velocity. I'm saying that the tooling that it has built in (pipelining, horizontal/vertical filtering, etc) could have been available from REST, and gained all the other benefits without a dramatic paradigm shift but no one seems to have bothered, and instead we're finding ourselves rebuilding bits that were already available/worked out in OpenAPI land for a few features that weren't too far away/hard to implement there.

FWIW this was ~2015ish, I'm not sure what the state of OpenAPI was at the time.

> Was it simply aggregating results of multiple requests?

Pretty much. The company I was at was an early proponent of microservices so we had to have a service that operated as our entry point to all of it. Thats easy enough, but layering on versioning of the APIs for native apps on different platforms added complexity that definitely didn't seem worth dealing with in our at the time REST paradigm. We did have frameworks that generated clients for different platforms against that API so I'm not even talking about the boilerplate of sending and parsing JSON.

There is no different paradigm. Both GraphQL and "REST" as it's usually implemented are RPC protocols. GraphQL just doesn't pretend it is not.
If you do a survey of front end data fetching frameworks, they basically land in two categories:

- API-agnostic: react-query, rtk-query, swr

- Declarative queries (e.g. GraphQL): apollo-client, relay, urql

A major difference to notice is that the API-agnostic libraries do not handle normalizing the data before caching it. Instead, they cache the data based on some key related to the request. So you can potentially fetch and cache two different versions of the (semantically) same information, leading to UI incoherence. The various API-agnostic libraries have ways of solving this by explicitly creating relationships between different requests so that you can manually say, "when I fetch with this key, also trigger a re-fetch of any components subscribed to these other cache keys." This is coarse, but for many cases "good enough" in contexts where you don't have full control over the API you are fetching data from.

In order to leverage a normalized cache, the layer between the cache and network needs to intimately understand what data is returned by which request so that it can support things like stale-while-revalidating, re-rendering on refetch of the same data from another part of the page, etc. Describing all of the data that could possibly be returned by an endpoint is tedious and error prone, as APIs can be dynamic in what they return and backend changes could easily lead to breaking any assumptions the frontend might make about an opaque endpoint.

Now if you have more control over how a backend behaves and buy-in on solving this problem full stack, you can start to build some of these assumptions into both layers. For instance, you could require all endpoints to be fully documented via swagger, and the front end could use the swagger JSON doc to map endpoints to data potentially returned by a response. You would also need a pattern to key each request with what entity (type + ID) it is responding data with before it completes; HATEOAS provides a standard of relating URIs to entities and would solve this problem.

So you can see that this normalized caching problem can be solved without GraphQL, as long as the backend and frontend can agree on a set of standards and requirements such as REST + HATEOAS + Swagger. Personally, if someone is passionate about solving this problem, I would recommend GraphQL, but it is up to each team to decide on what solutions meet their requirements.

If you just want the syntax and caching, you might try React Query. Haven't used it myself but it looks like it's Apollo-inspired.
Does OpenAPI have a way for the client to whitelist fields? I see that as a major selling point for GraphQL.

Without it, you end up having to create tailored endpoints for each use-case vs. for example a single “user” endpoint/vertex that supports the complete buffet of fields for all use-cases in one convenient place.

I can't say that it should have that feature -- I'd say that is outside the purview of OpenAPI itself, but it could definitely be built in in a repeatable and scalable way pretty simply. I can tell you that tools like PostgREST have had this for a long time[0].

[0]: https://postgrest.org/en/v7.0.0/api.html#vertical-filtering-...

The one place where I've found GraphQL to be potentially useful is back office. This is usually the place where you need a lot of very different data in one place, and in ways that are completely different from customer-facing apps or sites. And back office usually doesn't get as much love.

So usually you have backoffice devs scrambling to retrieve data in weird ways from existing APIs. And things like "does this inventory item come from a provider with an active contract, and who else is on that contract" become ... weird and unwieldy. This is where GraphQL with it's ad-hoc queries definitely helps. And since the volume of queries in back office is low, you don't worry too much about the performance of some of the queries.

I wouldn't use it for anything else though.

Anecdata:

Just last month it took me about half an hour to implement an "omni search" functionality in GraphQL that takes string as input, coalesces results from three different backend APIs and return back a nice view to fuzzy-ish search for three different entities in our backend. Frontend couldn't be happier.

Does OpenAPI support multiple kinds of data in a single HTTP request? I couldn’t find anything about that in the docs.
AFAIK there is not a standardized way to do this but there's no reason it can't -- you are free to define your own Content-Type or use framed binary, or whatever else. If you already have schemas on either side (or code to do dynamic discovery), and a way to pack/unpack you can send different kinds of data across.

This is less ideal than GraphQL in this case, since GraphQL has done this hard work and standardized it/created the conforming reference clients/servers already.

> replace the dynamic properties of the more advanced REST-ful techniques (API discovery, link following, etc) in GraphQL

Isn't this exactly what GraphQL does? I may be missing something

100% agree. People also need to remember that GraphQL was originally written for server side javascript, and now it’s being ported to other languages(for what reason???).

You can create your own global json schema and build a ratchet version of GraphQL using proven orms in about 20 minutes using an unpersisted “filtering” field.

If you want automatic access to your data, bite the bullet and do something cool like implement Apache Dremio.

GraphQL was released as an specification with a node example implementation. It wasn't "written for server side javascript".
Ok, so it was software released with it’s first implementation written in node.

And now have “Apollo”, which is a server that runs inside a v8 engine(node).

It seems to me that the javascript crowd are the ones pushing this forward and seems to me that it was written with javascript as a first class citizen.

Hard pass

Re: Conways law at Facebook

I was at Facebook when GraphQL was invented, maintaining a backend storage service where a core assumption was that storage should be reorganized based on access patterns and that predicates should be pushed down to storage where they can be executed more efficiently.

GraphQL was hard to push predicates down, because you don't know which of the edges were written in PHP.

My response was fquery[1], which is like what's being discussed here but with python as the source language instead of swift and amenable to preserving the largest possible query structure for backend optimizers, including SQL optimizers.

It has some early demos converting a GraphQL/fquery into SQL where possible. It should be possible to add enough metadata to fquery to identify if an edge is non-trivial (calls into another microservice) or trivial (can be optimized to a storage backend or SQL).

[1] https://github.com/adsharma/fquery

There's also:

- Relay-swift: A port of Relay to Swift - https://relay-tools.github.io/Relay.swift/docs/

- Graphaello: Inspired by Relay, but deviates a bit more from the patterns than Relay-swift - https://github.com/nerdsupremacist/Graphaello

Thank you for adding the links!

The main difference between these clients and SwiftGraphQL is that SwiftGraphQL tries to abstract away GraphQL in favour of Swift language feature.

`relay-swift`, for example, relies on query strings which doesn't bring type-safety to your code;

`graphaello` is indeed very similar and I've tried using it before creating SwiftGraphQL. One of the goals of SwiftGraphQL was to let you easily separate the model from your queries. That's why we let you do complex logic in the selection itself. Otherwise, you'd have to first create a utility struct and then translate it into a model-type. I think that's the main difference between graphaello and SwiftGraphQL

Thanks again for sharing the links!

Relay.swift doesn't bring type-safety to your queries but it does use the relay-compiler which will fail if anything is wrong (at least helpful!) and you still get type safety for results as well as automatic conformance to Identifiable & custom scalar type substitutions.

Haven't checked out SwiftGraphQL much, but Relay.swift is definitely the best swift based GQL I have used to date.

This is really cool! I love seeing GraphQL back in its roots as a way of improving the developer experience for native iOS apps.

From what I understand, this project tries to solve one clear pain point that isn't solved elsewhere: Swift developers can use GraphQL in Swift without writing GraphQL directly. Being able to create idiomatic operations through Swift is nifty to see.

Somewhat interestingly, it seems like to solve other problems, @maticzav is independently following similar paths that the original developers of GraphQL in Objective-C followed. Some of the highlights:

- Using code generation to make access patterns more type safe.

- Creating a centralized set of Type Models, that map 1:1 with the schema the app accesses.

- Mostly separating the GraphQL operations (in this case, as written in Swift) from the models a component interacts with: the components just see that they have a Schema-based Type Model.

I'd personally think about using the query-creation API to produce query (and fragment, once those are supported) specific models for consumption. The problems of both over and under fetching may expose themselves when more than a couple interactions are operating with different views over the same types. I've talked about why Facebook no longer recommends Type Models before: https://www.youtube.com/watch?v=Vo8nqjiKI3A

It's really encouraging to see the recent explosion of ideas for "how to do GraphQL": I'm not sure what sort of synthesis these myriad projects will create for the broader community.

I wondered when the GraphQL "ORMs" would start appearing!
I love code generation from GraphQL. Elm-graphql is a great example of this and works incredibly well, to the point where it sold me on GraphQL entirely.
SwiftGraphQL was actually inspired by Elm GraphQL! Dillon - the creator of Elm GraphQL - even helped me understand a couple of concepts he used in that library that we also use in SwiftGraphQL.
What's with the GraphQL luddism on HN? I'm as much opposed to adding more incidental complexity to the frontend as the next guy, but GraphQL has objective purpose and makes a lot of things much simpler than they would be without it.

Learning new things and doing things better than they were done a year before is an essential part of being a professional software engineer, it's what makes this field hard and that's why we're paid so much. It's what makes us able to tackle so much added complexity of the world, new use cases, new platforms and paradigm shifts over the years. To me, it's also what makes it so challenging and rewarding.

It’s dismissive to call it luddism. I am a big anti-GraphQL voice but in the specific cases where I tend to work: on small cross functional, often full stack dev teams. It’s a layer of formal promises about the API that I find extremely unnecessary & unproductive for small teams that I can see the appeal for at a huge corp like Facebook where frontend devs probably don’t write much or any backend code.

The problem usually isn’t the library itself and that’s true of GraohQL. It’s the cargo culting of GraphQL & other new tech that might be unnecessary or overengineering for your specific use case.

> I'm as much opposed to adding more incidental complexity to the frontend as the next guy, but GraphQL has objective purpose and makes a lot of things much simpler

By moving all that complexity to the backend. It's not luddism to call this out.

> Learning new things and doing things better than they were done a year before is an essential part of being a professional software engineer

Yeah, no. It's not "better than they were done a year ago". It's just dumping all the complexity in somebody else's lap, reimplements a bunch of things from scratch, poorly, and calls it progress.

So a bunch of people on HN are now arguing that GraphQL should disappear?

GraphQL is a genuinely objectively useful technology in places that have a frontend-backend split (including non-web frontends). It doesn’t require building specific APIs for specific pages for speed concerns. It allows backends to add fields non-destructively (RESTful JSON does work at the cost of a bigger network payload).

GraphQL provides the right tools for the right problem, and has created an ecosystem around it. (How should I reliably compute a SQL query cost? How should I control data access policy in SQL? How should I return the SQL result in a easily-parsable format?)

I see a lot of hatred in the comments towards GraphQL. Is someone forcing you to use it against your will?

I've been using it for more than a year with TypeScript types generation and couldn't be happier. All of my interactions with the server are properly typed and haven't had a single bug related to server/client missmatches.

There are a bunch of elitists on here who get off on hating popular things.

I find it amusing that some of the comments are basically "Why use graphql when I can combine these 5 other technologies to do the same thing?"

It's not graphql that's the issue. it's another tool.

It's the fanboys, and more the people selling tooling. There's a guy who (was?) over at graphqleditor.com that was posting a whole bunch of articles, at least one of one said it was a mistake not to convert all your shit to graphql immediately.

> Is someone forcing you to use it against your will?

I mean, kind of?

My problem with GraphQL isn't necessarily GraphQL itself, but with the sprawl of things creeping further and further into client-side code.

As companies are finding GraphQL to "unlock greater developer productivity", it's becoming more and more expected to have this in our toolkit as "front-end people".

There's been a few blog posts recently that I relate to. I feel like I'm at a point in my career where I could "knuckle-down and get good" but I don't actually want to get good at more and more endless technologies. I'd rather be able to define my niche specialization and thrive within that space.

[1]: https://bradfrost.com/blog/post/front-of-the-front-end-and-b...

[2]: https://www.trysmudford.com/blog/i-think-im-a-design-enginee...

[3]: https://notes.baldurbjarnason.com/2021/02/20/the-layers-of.h...

Wouldn't it be better to generate those structs from API schema?
SwiftGraphQL also generates API structs from the schema.

Maybe you are referring to generating the model from the queries. The problem we had with that approach was that it's hard to reuse the generated structures in your application model. You can read more about the idea here:

https://github.com/maticzav/swift-graphql#what-are-the-pitfa...

I have the same opinion. The big problem I had with generating graphql api from code, was that the result graphql schema was badly done. It's hard to design API that way. I made similar module for typescript just to realize, that I don't want to build graphql endpoints this way.

that module: https://github.com/captain-refactor/graphql-compose-typescri...

You mean something like https://github.com/banjun/WSDL2Swift ?
I <3 GQL but this just sounds like "Forget the GraphQL DSL to learn our DSL"
Can we just forget about GraphQL completely instead?
I have, but I also don't work in an organization that has separate and large front-end and back-end teams. GraphQL looks less like an objectively useful technology and more of a realization of Conway's Law in response to Facebook's organization.
As a Mobile Dev/Frontend Dev GraphQL is a massive win to work with. No more requesting/building end points to satisfy the screen you are building. Adding fields is non-destructive. Controlling the shape of the data returned (to an extent, you still have to return it in the nested layers the schema is designed towards). I know a ton of backend or full stack devs that don't think that GraphQL is worth it but very FEW UI devs that agree. It's really nice to build UI's against. I've tried SOAP, REST, HATEOAS, Swagger/OpenAPI, and protobuffers. Protobuffers are the only one with as good a developer experience IMO. GraphQL is OBJECTIVELY useful it might not be useful to you apps though and that's ok.
Objectively was probably the wrong word, maybe "generally" would be more accurate. I was looking to contrast GraphQL with something like REST which is an incredibly powerful generic mental model, where GraphQL seems more specifically tuned to solve front end developer's issues.
Great point. GraphQL looks like overkill for small projects but at the right size it probably makes perfect sense.
"Conway's law is an adage stating that organizations design systems which mirror their own communication structure"

So if GP is correct and we take them literally then you shouldn't only have the right size, but also a structure that's close to Facebook's...

Oh come on! My company just forced me to learn it for a better part of a year. We can’t be done with it, it’s not fair.

I was told this was the new hotness, and I can’t be lied to. Plus, many job descriptions were asking for Graphql about 2 years ago, so what gives? Is life not fair? I was told it was fair this time around.