Architectural Use Cases
GraphQL server with a connected database
- Often used for greenfield projects
- Uses single web server that implements GraphQL
- Server resolves queries and constructs response with data that it fetches from the database
GraphQL server to integrate existing system
- Compelling use case for companies with legacy infrastructures and many different APIs
- GraphQL can be used to unify existing systems and hide complexity of data fetching logic
- The server doesn’t care about what the data sources are (databases, web services, 3rd party APIs, …)
A hybrid approach with a connected database and integration of existing system
Resolver functions
- GraphQL queries/mutations consist of set of fields
- GraphQL server has one resolver function per field
- The purpose of each resolver is to retrieve the data for its corresponding field
example:1
2
3
4
5
6
7
8
9query {
User(id: "er3txsa9frju") {
name
friends(first: 5) {
name
age
}
}
}
Resolver functions1
2
3
4User(id: String!): User
name(user: User!): String!
age(user: User!): Int!
friends(first: Int, user: User!): [User!]!
GraphQL Clients
- Client doesn’t care where the data is coming from
- Opportunity for new abstractions on the frontend
GraphQL execution
GraphQL doesn’t just specify a way to describe schemas and a query language to retrieve data from those schemas, but an actual execution algorithm for how those queries are transformed into results. This algorithm is quite simple at its core: The query is traversed field by field, executing “resolvers” for each field. So, let’s say we have the following schema:
1 | type Query { |
The following is a query we would be able to send to a server with that schema:
1 | query { |
every field in the query can be associated with a type:
1 | query: Query { |
The execution starts at the query type and goes breadth-first. This means we run the resolver for Query.author
first. Then, we take the result of that resolver, and pass it into its child, the resolver for Author.posts
. At the next level, the result is a list, so in that case, the execution algorithm runs on one item at a time. So the execution works like this:
1 | Query.author(root, { id: 'abc' }, context) -> author |
At the end, the execution algorithm puts everything together into the correct shape for the result and returns that.
One thing to note is that most GraphQL server implementations will provide “default resolvers” - so you don’t have to specify a resolver function for every single field.
Batched Resolving
DataLoader is a generic utility to be used as part of your application’s data fetching layer to provide a consistent API over various backends and reduce requests to those backends via batching and caching