GraphQL is a query language for APIs that abstracts multiple data sources and enables app developers to request data in the format they need, without requiring backend API changes. Because GraphQL decouples front- and backend, it can consolidate multiple APIs into a single endpoint.
GraphQL’s combination of expressiveness, performance, and flexibility has made it a runaway hit with developers, who find it more efficient than REST for many common use cases, and a natural fit for composing microservice calls.
In this post, I’ll create a GraphQL resolver using FaunaDB for a schema of posts, authors, and comments to support a blog engine. It’s ported from an original example for the Serverless Framework.
GraphQL commonly accesses a database to resolve queries. A typical pattern is that each domain object (author, blog post, comment) is backed by a microservice which queries a database or other resource. GraphQL queries these microservices in parallel and composes the results for the client. FaunaDB is well suited for GraphQL’s parallel execution model, with strong consistency that can protect against some of the uncertainties that come with accessing data via microservices.
Below you can see how FaunaDB’s query syntax compares with GraphQL. You’ll notice that GraphQL abstracts away concerns like pagination and indexes, presenting an app-focused surface area, while FaunaDB queries give more explicit control to allow for fine tuning and more complex queries.
I based this example on Kevin Old’s blog example, which demonstrates the Serverless Framework with GraphQL. For this post, I ported Kevin’s example from DynamoDB to FaunaDB, reducing the code and complexity in the process. I also upgraded the example from version 0.5 of the Framework to the current version.
One advantage of working with an existing project is that you can see how much code DynamoDB required for its care and feeding compared to the relative simplicity of using FaunaDB. (Go ahead and click that last link there and read a handful of FaunaDB queries. You’ll be glad you did.)
The service provides an API for a basic blog structure, including posts, authors and comments. The entire API consists of only 1 HTTP endpoint.
Getting started
To run the demo below, you’ll need to do a few things first:
1. Install Serverless Framework with NodeV4+:
npm install serverless -g
2. Get the example service code by cloning our demo repo:
git clone https://github.com/fauna/serverless-graphql-blog
cd serverless-graphql-blog
3. Inside the serverless-graphql-blog
checkout, install dependencies:
npm install
cd blogs
npm install
Create a database on FaunaDB
Now that you have the tools you’ll need for this demo, create a database on FaunaDB. This database will hold the data returned by your GraphQL endpoint.
1. If you don’t have a FaunaDB account, start a free trial.
2. Create a database in the FaunaDB Dashboard:
- Click Create a Database.
- Enter the name graphql-blog-demo in the text box.
- Click Create Database again.
3. Get a key:
- Click / in the upper left side of the screen.
- Click Manage Keys and Create a Key.
- Name your key, assign it a server role, and choose the graphql-blog-demo database.
- Click Create Key.
- Your key’s secret will be displayed. Copy it to your
serverless.yaml
file, replacingSERVER_SECRET_FOR_YOUR_FAUNADB_DATABASE
.
Deploy your GraphQL endpoint
Now that FaunaDB has some data to return via your GraphQL handler, it’s time to deploy that GraphQL endpoint so you can use it to query FaunaDB.
When you run the following command, be sure to note the POST endpoint URL it’s assigned.
serverless deploy
You’ll see a result like this, which contains your POST endpoint URL:
Service Information
service: serverless-graphql-blog
stage: dev
region: us-east-1
api keys:
None
endpoints:
POST - https://XYZ.execute-api.us-east-1.amazonaws.com/dev/blog/graphql
functions:
setupFaunaDB: serverless-graphql-blog-dev-setupFaunaDB
sadiavas: serverless-graphql-blog-dev-sadiavas
Serverless: Removing old service versions...
Invoke the private endpoint for creating the classes and indexes in your FaunaDB database. This creates the posts, authors, and comments classes, and indexes for loading posts by author.
serverless invoke --function setupFaunaDB
Querying with GraphiQL
The graphql-js endpoint provided in this Serverless project is compatible with GraphiQL, a query visualization tool.
Usage with GraphiQL.app (an Electron wrapper around GraphiQL) is recommended and shown below:
Sample GraphQL queries
First, create an author and some of their posts.
To create an author, visit the authors
class in the FaunaDB dashboard. The URL is: https://dashboard.fauna.com/db/graphql-blog-demo/classes/authors
Click “Create Instance”, enter some JSON-formatted data. Then save your author instance.
{
"name": "Chris",
"id": "123"
}
Create a Blog Post
Now, you can switch to GraphiQL to run a mutation to create a blog post. Make sure to enter the endpoint URL that was returned by serverless deploy
. Then you can enter a GraphQL query like this to create a blog post for your author:
mutation createNewPost {
post: createPost (id: "5",
title: "Fifth post!",
bodyContent: "Test content",
author: "123") { id, title } }
Now that you’ve created some data, you can run other queries.
List of author names
{ authors { name } }
Results
{
"data":{
"authors":[
{"name":"Chris"}
]
}
}
List of posts with id and title
{ posts { id, title } }
Results
{
"data": {
"posts": [
{ "id":"1",
"title":"First Post Title"
}
]
}
}
List of posts with id, title and nested author name
{ posts { id, title, author { name } } }
Results
{
"data": {
"posts": [
{ "id":"1",
"title":"First Post Title",
"author":{
"name":"Chris"
}
}
]
}
}
Conclusion
If you’re using FaunaDB as the backend of an existing app, standing up a microservice to allow GraphQL access to your database is an architecturally sound approach, which works especially well if you are already taking advantage of FaunaDB’s native object-level access control. Your FaunaDB/GraphQL endpoint can also compose data from other APIs, backend services, and IT systems.
If you are already building microservices, FaunaDB can unify your data model. FaunaDB’s support for joins, constraints, and triggers lets you provide efficient access for each microservice, all while enforcing access control and validation logic.
Of course, you don’t have to build microservices to benefit from the combination of GraphQL and FaunaDB. FaunaDB’s query language is flexible in a similar way to GraphQL, but processed by the backend database. A mature GraphQL/FaunaDB connector will be able to consolidate requests across multiple GraphQL schema resolvers into a single FaunaDB query. This approach will add an additional layer of optimization potential to your GraphQL queries. Watch this space for more GraphQL updates.
Visit the FaunaDB Serverless GraphQL Blog README for more query examples, and notes about how you can contribute to the example.