Scalable APIs with GraphQL and Netlify Functions
In this tutorial, we will be exploring serverless functions by learning how to use them with GraphQL to build scalable APIs.
What is serverless?
A serverless function is a way for adding a backend to your app without managing a server, virtual machine, or docker container. Behind every serverless function invocation is a server hosted and managed by a cloud provider such as AWS, Google Cloud, Netlify, Vercel, and so on. The providers are abstracting away a lot of the complexity so you can focus on just what your function needs to do. Serverless functions are basically functions-as-a-service.
What we’re building
In this tutorial, we will be using Netlify Functions, which are built on top of AWS Lambda Functions. We'll be building a Project Tracker with GraphQL, serverless functions, and Airtable. We will be using The Airtable API to create and retrieve projects. Let's get started!
Setting up
Before we get into creating a new lambda function, we need to sign up for an Airtable account to be able to use it as a DB. After you create an account, open your command-line interface and running the following:
npm install netlify-cli -g
This command will install Netlify CLI, which we will us to create a new serverless function. Next we need to set up our project, execute the following:
mkdir functions && touch netlify.toml
The command will first create a new folder named functions
then will create a new file netlify.toml
at the root. Netlify uses this file to configure the resources you’ll be using, in this case functions. With this in place, add the following code below to netlify.toml
.
// netlify.toml
[build]
functions = "functions"
These two lines tell Netlify that our serverless functions live in a folder named functions
. Now, open your CLI and make sure to be in the folder that contains the functions
folder.
netlify functions:create serverless-graphql
The Netlify CLI will prompt you with options to choose between several ready to use templates. Choose the one named >[apollo-graphql] GraphQL function using Apollo-Server-Lambda!
. It’s the starter for the serverless function that uses Apollo GraphQL. Once the project is initialized, cd
into the functions
folder, then install the Airtable SDK.
npm install airtable
Next, create a .env
file at the root of the project and replace the variables with your credentials.
// .env
AIRTABLE_API_KEY=<your-api-key>
AIRTABLE_BASE_ID=<your-table-base-id>
AIRTABLE_TABLE_NAME=<your-table-name>
AIRTABLE_API_KEY
is your API key on your Airtable account.AIRTABLE_BASE_ID
is the id of your DB table (see here).AIRTABLE_TABLE_NAME
is the name given to your table.
With our setup and configuration complete, we can dive into coding our serverless function.
Building the serverless function with GraphQL
First, structure the project like so:
functions
├── graphql.js
├── utils
| └── airtable.js
└── package.json
As you can see, the logic to interact with Airtable is holden by the file airtable.js
. The entry point of the serverless function is graphql.js
.
Connecting with Airtable
Let’s add the code below to the file airtable.js
.
// utils/airtable.js
const Airtable = require('airtable')
const { AIRTABLE_API_KEY, AIRTABLE_BASE_ID, AIRTABLE_TABLE_NAME } = process.env
const base = new Airtable({ apiKey: AIRTABLE_API_KEY }).base(AIRTABLE_BASE_ID)
const table = base(AIRTABLE_TABLE_NAME)
const getAllProjects = async () => {
const allProjects = await table.select({}).firstPage()
return allProjects.map(({ id, fields }) => transformResponse(id, fields))
}
const addProject = async ({ project }) => {
const { name, description, date } = project
const createProject = await table.create([
{
fields: {
name,
description,
date,
status: 'In progress',
},
},
])
const { id, fields } = createProject[0]
return transformResponse(id, fields)
}
const transformResponse = (id, fields) => ({
id,
name: fields.name,
description: fields.description,
date: fields.date,
status: fields.status,
})
exports.getAllProjects = getAllProjects
exports.addProject = addProject
Airtable
allows us to connect our app to Airtable with the credentials passed in as arguments to it. After that, we initialize the DB table with the table
constant.
Next, we retrieve all projects
from Airtable
using the function getAllProjects()
. To add a new project, we rely on the method addProject()
, which receives the object to add as a parameter. Finally, we use the method table.create()
to persist the data on the DB.
Now, we have the functions needed to add and fetch the projects from Airtable. Let’s use them in the file graphql.js
to perform the queries.
Creating the API with GraphQL
// graphql.js
const { ApolloServer, gql } = require('apollo-server-lambda')
const { getAllProjects, addProject } = require('./utils/airtable')
const typeDefs = gql`
type Project {
id: ID
name: String
description: String
date: String
status: String
}
input ProjectInput {
name: String
description: String
date: String
}
type Query {
getProjects: [Project]
addProject(project: ProjectInput): Project
}
`
const resolvers = {
Query: {
getProjects: () => {
try {
const allRecords = getAllProjects()
return allRecords
} catch (error) {
throw new Error(error)
}
},
addProject: (_, args) => {
try {
const createProject = addProject(args)
return createProject
} catch (error) {}
},
},
}
const server = new ApolloServer({
typeDefs,
resolvers,
})
const handler = server.createHandler()
module.exports = { handler }
If you have experience with Apollo Server, you should already notice that the library used here (apollo-server-lambda
) is different from the one used for building servers. This package uses middleware to inject our lambda serverless function to Apollo Server.
Next , we import the functions getAllProjects
and addProject
from airtable.js
. With this, we can define a new GraphQL Schema using gql
. The query getProjects
has to return an array of type Project
. The method addProject
expects an object of type ProjectInput
as a parameter and should return a value that reflects the Project
type.
Any GraphQL Schema has to have a GraphQl resolver that corresponds to it. That’s why, here, we have on the resolvers
object, the functions getProjects()
and addProject()
. The first fetch all projects from Airtable and the second add a new object to the table.
Now, we have a schema and a resolver. We need to pass in the values to the constant server
to let it handle the request when the endpoint /graphql
is hit.
Testing the GraphQL API
With this step, the serverless app is ready to be tested in the browser. So, begin by browsing to the root of the project and running this command:
netlify dev
Our serverless function should be up and running and accessible here:
The app will land on the GraphQL Playground. It’s a neat tool built on top of GraphiQL. It’s a GraphQL IDE for sending queries or mutations, exploring the API docs, sending HTTP headers, and more.
http://localhost:8888/.netlify/functions/graphql
Now, add this code block below to create a new project.
mutation {
addProject(project: { name: "My first project", description: "First project's description", date: "2020-12-11" }) {
name
description
date
status
}
}
After sending the query, you should see this:
create-post
{
getProjects {
id
name
description
date
status
}
}
Once all projects are fetched, the result should look like this:
get-all-posts
Next steps
Awesome! Our serverless function is looking nice. We’ve built a GraphQL API using serverless functions and Airtable. Let’s now deploy it to Netlify!
To do so, we first need to sign up here. Then, initialize our app with git. Make sure to be at the root of the project before executing the following.
git init
Add a .gitignore
file at the root of the project.
touch .gitignore
Add this code block to ignore the files listed below when adding changes to git.
// .gitignore
/functions/node_modules
/functions/.env
Add and commit changes to git.
git add -A && git commit -m 'Ready to deploy on Netlify'
Create a new repository on Github and follow the steps to push your project. Next, go to Netlify and connect your Github repo. Move the package.json
file to the root of the project, then create the environment variables on Netlify.
Deploy your serverless functions. We can now preview and interact with our app here: https://graphql-airtable.netlify.app/.netlify/functions/graphql
You can find the finished project in this Github repo. Thanks for reading!
Conclusion
Serverless is an exciting piece of technology. It allows us to build up a backend quickly without the hassle of managing a server, which brings us to the JAMStack. An architecture designed to make the web faster, more secure, and easier to scale with static sites and serverless functions.