How to GraphQL – A Fullstack Tutorial for GraphQL
howtographql.com
howtographql.com
There are no good articles on server best practices, how best to use ORM with it (especially as it relates to lazy loading), etc.
While we are going full board with GraphQL, we’re having to really fly by the seats of our collective pants because practical GraphQL serving is a far cry from idiomatic GraphQL. Some of us have more complicated applications than NEWHOPE, EMPIRE, and JEDI.
Co-creator of How to GraphQL here. I’m very excited to tell you that we’re currently working on a new iteration of the page and content that will include more in-depth chapters about dataloaders, authentication, authorization and other advanced topics.
Would be great to hear more thoughts on which topics you’d like to see covered.
Using JavaScript ones is not an option. So that is the kind of thing I would care about.
If there's solid libraries for each of the common languages used to write serverless code, then I think that'd be a big plus for decision makers who are on the fence about adopting GraphQL
But I think there's something "there" - graph dbs, datomic, web prolog - they all seem to point to clients asking a "what" with the server figuring out the "how" [ed: and not in the least: whence (from where)] .
GraphQL clients cover a ton of the functionality—so much so that you're more concerned about the basic concerns you're already familiar with: doing stuff with your data.
The server has the inverse problem. A GraphQL server library covers the low-level part of breaking down the query into actionable slices, but how you resolve those is more of an open-ended problem. And because there's such a variety of ways you could be fetching that data, it's hard for the server library to steer the implementer in any one direction. Every server is going to be vastly different, while every client is going to use very similar patterns.
I thinks it important to remember that GraphQL should form a very thin layer of an application stack. I gave a 4 hour intro lesson at my employer and the bulk of it was not GraphQL, but how we resolve GraphQL against our specific backend data sources.
GraphQL is not about the server-side - that's an implementation detail and is orthogonal to GraphQL itself. I think it's important that we don't conflate ORMs with GraphQL just because an ORM can be used to simplify the server-side implementation (take a look at Graphene [1] or Prisma [2]).
[1] https://github.com/graphql-python/graphene [2] https://github.com/prismagraphql/prisma
And yet. Somebody has to be there to parse GraphQL and turn those queries into database or other external calls--and do so efficiently--for a large/combinatoric number of potential variations of entity graphs.
This is why we are going to surface the more complex children of certain models as root queries instead. It’s considerably less than ideal from an idiomatic GraphQL point of view, but it’s much more practical. If data models are simpler, then GraphQL works great. Or if the data model is flat, it works great. Anything else and it’s not as cut and dry.
That said, GraphQL-the-spec does highlight a key ORM weakness--it's not so easy to dynamically construct complex join queries with decently-optimized fetch plans.
Took me a minute to grok that this comparison implicitly depends on a Graph DB server.
If I were writing a book, I would probably start by explaining use cases where graphs are a better data structure... then advance to query concepts.
I’ve written many RESTlike APIs (no hypermedia) and they mostly returned data. In fact, the whole premise is to be able to access resources which typically boils down to some data model response.
A SPARQL query can federate data from several SPARQL endpoints (this is all the point of the LinkedData movement).
So we have NO additional layers between the DB and the client (except for some security features, and query throttling)
This is a simple pattern that makes data access trivial. (if you manage to store your data in such a graph database, which is NOT trivial)
As far as I understand, if you follow a similar philosophy, then GraphQL will shine too (especially because the tooling on the client-side is infinitely superior with GraphQL, than it is with SPARQL).
But the more I read this HN thread, the more it seems GraphQL is used for service integration. And that is a completely different problem.
So, I feel like data access with GraphQL is super nice. (especially if you use best practices for your data, like in the LinkedData principles) But service integration sounds yet another hell. (because services are rarely designed to be properly integrated together).
And I think this now makes some sense as to why there is hardly any documentation with respect to practical GraphQL and ORM (in the vein of Spring Boot and Hibernate for us old Java folk).
Thanks for the explanation!
Yes it makes sense from a client-side / front-end perspective, but that's because the server is just a [handwave]. Someone else's problem.
I've used some of their tools (and I am even working on a library that would be a good compliment to Prisma), but don't come out of this tutorial thinking that Prisma is some sort of defacto standard back-end for GraphQL APIs.
- Access restrictions, and security is very painful. Trying to enforce RBAC through postgresql policies over hundreds of tables with slightly different policies is a nightmare. Hiding all this on the DB's end and burying this stuff in migrations sucks for anyone trying to develop on it.
- I still have not found a good solution to querying/filtering over things like nested JSONB objects without writing my own resolver functions, which then complicates numerous things.
- Versioning is a mess, especially when you don't have an easy way to force clients to upgrade (i.e. mobile apps), along with other parties using your graphql api directly.
- However the worst thing so far to me has been i have watched as UI developers go from writing simple rest queries, and doing a bit of work on the front-end to writing extremely inefficient and convoluted queries. Even worse is when a third party is doing it and i have no say over what they do with it.
I haven't used either yet, but I spoke to one of the founders a while back and auth difficulties was one of the things we talked about. I believe they're open sourcing their data layer soon.
I haven't used Postgraphile, but it sounds like you are just exposing your database directly out through a GraphQL wrapper. You'd be experiencing the same pain if you tried this approach with any API technology (gRPC, REST, SOAP, etc).
You should still have code for authorization and business logic, and your API should probably be exposing a focused subset of your data model unless your clients really need to be able to traverse the entire database.
To me having to maintain two separate graphql services for a single API seems extremely convoluted. I can't expose the private api to any other internal services, because all the authorization and restrictions are done on the application layer.
To me isn't that just using a GraphQL server as an ORM? To me that seems like an extremely roundabout way to do something like that.
Which application tier? It sounds like you're using GraphQL in-memory to query the database in the same process that's creating the GraphQL query. You should be treating GraphQL as a database, and it should not exist on the same machine that's using it. This way your GraphQL app has centralized permissions & auth, and all your other apps would then be beholden to whatever you implemented.
> just using a GraphQL server as an ORM
If you're using it the way above, then yes. But that's the wrong way to use it.
A more complete approach would be to structure your application in a more typical fashion, and put a GraphQL layer on top. Have a data access layer that maps from our back end sources (databases/REST/RPC services) to GraphQL types. Then have a logic/authorization layer, with GraphQL on top. Using Postgrapile seems to take those application layers away for the sake of convenience.
To your last point, there are a few ways you can provide feedback on or limit the cost of your queries. I'd recommend checking out Github's article on resource limitation [0] and the section on query cost analysis in an article by the Apollo team [1].
[0] https://developer.github.com/v4/guides/resource-limitations/ [1] https://dev-blog.apollodata.com/securing-your-graphql-api-fr...
Adamkl is right, you are missing a layer in your application. postgraphile, prisma and hasura turn your database into a graphql api, but you don't want to expose that directly. Graphql Bindings allow you to construct a Graphql Api by mapping an existing Api and implementing extra logic.
This allows you to keep permission and business logic in your application layer where it belongs.
My Co-founder Johannes is giving a talk on this technique at GraphQL Europe on Friday. The talks will be available online shortly after, so I would recommend keeping an eye out for that if you are not going.
Doesn't that drastically increase complexity in the fact that you now need to maintain multiple services? Why not just skip postgraphile and just use an ORM in your business layer? As opposed to being required to maintain multiple services.
It also feels very odd that since you can't even expose your private one to other internal services because all your authorization and access restrictions are now sitting in your business layer, which to me seems like a huge waste.
If you look at the architecture of modern tech companies they are already moving in this direction. Facebook has TAO for data access, and twitter has Strato: https://about.sourcegraph.com/graphql/graphql-at-twitter/ The purpose of these data services is to enable feature developers to focus on their feature instead of worrying about infrastructure, caching and scalability. Prisma is an open source version of that same pattern.
To the question of whether you should expose your database API to other internal services or not. This very much depends on the kind of architecture you are choosing. If you are building microservices you typically want to ensure that only the microservice owning the data can access and update it.
Facebook has a quite different approach where TAO enforces access control policies, and all services can query the same data. We'll explore how Prisma can support this pattern in the future.
At my company, we are taking a different approach by defining GraphQL APIs that are essentially exposing pure data (similar to Prisma) and then we are merging them and proxying them through multiple layers that augment and alter the schema and data as it passes through.
We can do this because we are leveraging The ability to inspect and alter the abstract syntax trees that power GraphQL under the hood.
Our data APIs map from existing SOAP/XML services to small GraphQL sub-sections of our greater API.
Then, we merge those small APIs together with Apollo's graphql-tools, similar to what Airbnb is doing[1].
Now we are starting work on our proxy/processing layers using this[2] work-in-progress.
[1]https://medium.com/airbnb-engineering/reconciling-graphql-an...
My thoughts on the issue:
- Perhaps GraphQL's biggest mistake is using "QL" in the name. GraphQL is NOT AND SHOULD NOT be a replacement for SQL, and that's where I think folks get confused. Whenever I see complaints about "I can't do joins, and GraphQL is missing generic filter statements" I'm sure people are totally missing the point of GraphQL.
- Your last bullet point (about UI developers going from writing simple rest queries to convolute front end queries) made me extremely sad, as when done right this is where GraphQL truly excels. Where I've used GraphQL to great success is to define my types to very closely match what the UI developers need. In fact, I have the UI devs themselves write the type and query definitions, code reviewed by backend engineers. This makes it trivial for UI devs to code against, for example, a mocked up version of the APIs while backend devs build out the resolvers.
The issue is that GraphQL is GREAT as a layer BETWEEN your lower level data sources and backend APIs and your front end, and the "translation layer" is done in the resolvers. This is especially true for native clients when you may have multiple versions of clients in the wild.
as for your migrations problems, a combination of sqitch and apgdiff provides a way to work with sql similar to other languages (migration files are created automatically and managed by sqitch)
I mean, I get that react(-like) UI frameworks or node.js servers are happy using it, as this is their version of creating a "narrow" interface. However most platforms do support powerful type-to-serialization mappings through either reflection or code generation. We can create "narrow" interfaces easily, and these can be used with much less hassle than GraphQL.
Can somebody share their story if/when GraphQL were beneficial with a strongly typed language?
With those, we get type safety on input arguments, and can make sure that our data access layer maps from back-end data sources to our output GraphQL types.
[1] https://gist.github.com/adamkl/27539b3a8129f23e3576bfc37b3ea...
But at the backend level, I find Graphql bit too verbose. There is a lot of code being repeated (or referenced) and it makes your code bloated with having to manage several different places.
For example if you have a customers table, you have to declare the fields you have in the table for the schema, then you declare them all again on the queries/mutations/resolvers. Which are again repeated at the client side. So if you ever alter something in your table, you have to touch around 4-5 files for each change. You then multiply that by the number of tables you have and you get the idea. It is essentially worse if your database schema have quite a bit of nested JSON data.
Sure there are pros and cons to this but atleast with me, so far, the cons seem to outweigh the pros. I miss being able to whip up an API endpoint on the fly.
Graphql backend coding reminds me of the days of SOAP with the WSDL and all, I recall it made me hate coding. I was thrilled to see REST get popularized and get away from SOAP completely. Now it seems we are back in a quasi-SOAP world again with Graphql. I'm sure it's a bit more improved now but once being burned I just don't feel comfortable going back to anything that resembles it.
I generally like simple and quick solutions that addresses problems. But Graphql seems like it's in the other spectrum of it. On the bright side, Graphql is somewhat fun. :)
Or use the parameters to specify a version.. but I think the reverse proxy solution is cleaner
Its primary use case right now is to replace a REST API, but at its heart, GraphQL is a specification for a type system, query language and the semantics to resolve one against the other. I can’t speak to other implementations, but graphql-js gives you the tools to parse queries and schemes into abstract syntax trees, and once you have that, there’s a lot you can do. With those tools, people have been creating all sorts of things. Take a look at Apollo’s work on merging schemas together for a good example. [1]
Personally, I’m working on a proxy layer that will sit in front of a GraphQL API and act as a sort of business rule engine. It analyses the incoming queries to figure out which sets of rules need to be run.
These sorts of solutions don’t have anything to do with APIs. Heck, you could create a GraphQL schema to act as a classic data access layer, and call it internally from your own code... Which is what Prisma is doing.
I think this ability to leverage the capabilities of GraphQL to create innovative new solutions muddies the waters for those who are looking to create a simple API.
[1] https://www.apollographql.com/docs/graphql-tools/schema-stit...
(Disclaimer: From my personal blog)
const typeDefs = `
type Query {
info: String!
feed: [Link!]!
}
type Link {
id: ID!
description: String!
url: String!
}
`
Why is this rubbish in backticks accepted? It is especially stunning to see this in "modern" ES6+ code explaining the newest hype. It's not even mentioned that it sucks, it's presented like proper code.