[HN Gopher] SwiftGraphQL - A GraphQL client that lets you forget...
___________________________________________________________________
SwiftGraphQL - A GraphQL client that lets you forget about GraphQL
Author : maticzav
Score : 91 points
Date : 2021-02-22 13:07 UTC (9 hours ago)
(HTM) web link (github.com)
(TXT) w3m dump (github.com)
| Kaze404 wrote:
| 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.
| maticzav wrote:
| 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.
| dsabanin wrote:
| 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.
| ritchiea wrote:
| 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.
| adsharma wrote:
| 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
| msoad wrote:
| Wouldn't it be better to generate those structs from API schema?
| yeneek wrote:
| 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...
| harryf wrote:
| You mean something like https://github.com/banjun/WSDL2Swift ?
| maticzav wrote:
| 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...
| [deleted]
| kva wrote:
| I <3 GQL but this just sounds like "Forget the GraphQL DSL to
| learn our DSL"
| mjmahone17 wrote:
| 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.
| jtdev wrote:
| Can we just forget about GraphQL completely instead?
| runawaybottle wrote:
| 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.
| blacktriangle wrote:
| 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.
| RyanShook wrote:
| Great point. GraphQL looks like overkill for small projects
| but at the right size it probably makes perfect sense.
| arcturus17 wrote:
| "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...
| jaegerpicker wrote:
| 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.
| blacktriangle wrote:
| 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.
| j_m_b wrote:
| I wondered when the GraphQL "ORMs" would start appearing!
| andrewingram wrote:
| 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
| maticzav wrote:
| 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!
| ericlewis wrote:
| 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.
| pcr910303 wrote:
| 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?)
| santialbo wrote:
| 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.
| tylerchilds wrote:
| > 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...
| serverholic wrote:
| 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?"
| [deleted]
| hardwaresofton wrote:
| 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.
| jkcxn wrote:
| > 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
| mikecaulley wrote:
| 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.
| criddell wrote:
| 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.
| hardwaresofton wrote:
| 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/
| shoelessone wrote:
| 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.
| hardwaresofton wrote:
| > 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
| jamil7 wrote:
| I don't have especially strong feelings either way, but the
| majority of this is possible with OpenAPI as well.
| kristaps wrote:
| 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?
| mikecaulley wrote:
| 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.
| dmitriid wrote:
| 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.
| mikecaulley wrote:
| 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.
| dmitriid wrote:
| > Though if you optimize for only the most likely cases,
| the effort is not much greater.
|
| That's why most discussions involving complexities of
| GraphQL inevitably devolve into: "in production we only
| allow a subset of queries". Because _actually_
| implementing GraphQL as it 's specified and marketed is
| quite an undertaking.
| no_wizard wrote:
| 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)
| hardwaresofton wrote:
| 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.
| serverholic wrote:
| 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.
| htormey wrote:
| 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).
| hardwaresofton wrote:
| > 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.
| serverholic wrote:
| > 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.
| Lx1oG-AWb6h_ZG0 wrote:
| 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.
| hardwaresofton wrote:
| > 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?
| lilactown wrote:
| 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.
| krschultz wrote:
| 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.
| hardwaresofton wrote:
| 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.
| magic_quotes wrote:
| 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.
| Ozzie_osman wrote:
| 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.
| rand_r wrote:
| 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.
| hardwaresofton wrote:
| 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-...
| humbleMouse wrote:
| 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.
| santialbo wrote:
| GraphQL was released as an specification with a node example
| implementation. It wasn't "written for server side
| javascript".
| humbleMouse wrote:
| 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
| dmitriid wrote:
| 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.
| monadic5 wrote:
| > 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.
|
| Why the insistence on condescending towards people who make
| decisions you don't understand? It's one of HN's less
| attractive aspects.
| erikpukinskis wrote:
| Does OpenAPI support multiple kinds of data in a single HTTP
| request? I couldn't find anything about that in the docs.
| hardwaresofton wrote:
| 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.
| erikpukinskis wrote:
| 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.
| hardwaresofton wrote:
| 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
| RussianCow wrote:
| > 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
| hardwaresofton wrote:
| > 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.
| RussianCow wrote:
| > 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/
| codenesium wrote:
| 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.
| jkrems wrote:
| > 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.
| dmitriid wrote:
| > 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.
| andrewingram wrote:
| 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_.
| dmitriid wrote:
| > The n+1 problem has solutions though.
|
| It does. But it also means that the problem _exists_. It
| 's there, you run into it _by default_ , and you have to
| take special care to make sure it doesn't happen. And
| data-loaders are just a first step. Some systems try to
| actually calculate query complexities and nesting depth.
|
| > 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
|
| Exactly. The complexity doesn't go anywhere.
|
| I... don't know how all this is an argument against what
| I said.
| erikpukinskis wrote:
| 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.
| flashgordon wrote:
| 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.
| carlps wrote:
| > 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.
| Someone wrote:
| 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.
| ritchiea wrote:
| 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!
___________________________________________________________________
(page generated 2021-02-22 23:02 UTC)