Build Your Serverless GraphQL API with Webiny

In this tutorial, you will create a Habits Tracker API service, which will consist of the Habit model. By accessing the /graphql URL, you will read (query) and write (mutations) new data for our habits.

Webiny framework provides different scaffolding tools. What you will use is the GraphQL Apollo service scaffold to create the API service.

Before adding more functionalities, you will learn the queries and mutations in the How to GraphQL section. Then, you will test the GraphQL service with the out-of-the-box TDD setup from Webiny.


You can find the example repo for this tutorial here.

We have an active community on slack. If you struggle in any part of the tutorial, talk to the core-team, and get help. Webiny team is always there for any questions.

First, let’s go through the core concepts used in this tutorial.

Core Concepts

Serverless architecture


Serverless architectures are application designs that incorporate third-party “Backend as a Service” (BaaS) services, and/or that include custom code run in managed, ephemeral containers on a “Functions as a Service” (FaaS) platform. Resource here



At its core, GraphQL enables declarative data fetching where a client can specify what data it needs from an API. Instead of many endpoints that return fixed data structures, a GraphQL server only exposes a single endpoint and responds with the data a client asked for. - Resources here.



Webiny is a platform for building serverless applications and APIs. Out of the box, Webiny provides a complete plugin based admin interface and a set of ready-made apps. It is built for self-hosting on AWS.

Webiny is the easiest way to adopt serverless.

It is created with technology and tools you know and Love:

If you have ever used these technologies, you already know Webiny = )

How to GraphQL

As noted in the GraphQL website. GraphQL is a query language for APIs and a runtime for fulfilling those queries with your existing data.

Core Concepts

Let’s go through the fundamental language constructs of GraphQL.

Defining types as well as sending queries and mutations.

We define the schema of our API with the GraphQL type system Schema Definition Language (SDL) Which is the syntax for writing schemas.

Fetching Data With Queries

As we noted earlier, the Main GraphQL API URL is the URL we care about the most. The Main GraphQL API is the single endpoint.

GraphQL is about asking for specific fields on objects. It's completely flexible and lets the client decide what data is needed.

The client needs to send more information to the server to express its data needs. This information is called a Query.

// The query
listHabits is called the root field of the query.
Everything that follows the root field is called the payload of the query.
listHabits {
// The response
"listHabits": [
{ "title": "Drink Water", "habitScore": 3 },
{ "title": "Run", "habitScore": 2 },
{ "title": "Journey", "habitScore": 3 }
The title was the only field that we specified in the queries payload.
If we needed the habit score, all we need to do is include the habitScore
the field in the query payload.

In a GraphQL query, each field can have 0 or more arguments if specified in the GraphQL schema.

One of the significant strengths of GraphQL is it allows for querying nested information. For example, to load all the habits that each person has written as more info:

listAccountability {
habits {

Next to requesting information from a server with queries, we can change server-side data through mutations.

With GraphQL, we do these changes with so-called mutations.

Writing Data with Mutations

There are three kinds of mutations:

  • creating new data
  • updating existing data
  • deleting existing data

Mutations generally follow the same syntactical structure as queries. What differentiates them from queries is that they always need to start with the mutation keyword.

Example mutation

mutation {
createHabit(title: "Drink Water", habitScore: 1) { // root Field - createHabit

Notice that similar to the query that you wrote before, the mutation also has a root field, the createHabit root field. You also learned about the concept of arguments for fields.

The createHabit fields take two arguments that specify the habits title and habit score. Like with the query, you are also able to determine the payload for the mutation, in which you can ask for different properties of a new person object.

Being able to query information when sending mutations can be a powerful tool that allows retrieval of data from the server in just a single round trip.

The server response from the above mutation will look as below.

"createHabit": {
"title": "Drink Water",
"habitScore": 1,

Precisely as with queries, the server response is shaped according to the mutation that was sent.


To create the Serverless GraphQL API, you will need to set up a Webiny project.

The base prerequisites to create a Webiny project are:

  1. node.js >= 10.14.0
  2. yarn < 2.0
  3. AWS account with an IAM user for programmatic usage
  4. MongoDB database in the cloud

Make sure to set up all the above requirements to continue with the next steps.

Webiny Project

When you create your Webiny project and deploy it with yarn webiny deploy api --env=local, the output of this command will look like below.

Webiny project deploy result

For now, the Main GraphQL API URL is what we care about the most.

Using this URL, you can access the GraphQL playground in which you can see the complete GraphQL schema created from all of the services that Webiny provides.

Check out the schema below.

Webiny project GraphQL playground

When you create your API service, you will see your APIs Queries and Mutations sections. That means you have successfully created and deployed our API service.

Learn more about Webiny API Architecture here.

Serverless API with Webiny

Webiny Project Structure

Before continuing to build the API service, let’s see how Webiny projects are organized.

Check out the Webiny serverless-api project structure in the image below:

Webiny project structure

To learn more about the Webiny project structure, check out our docs here.

The one folder that is important for us is the API folder.

Webiny project API folder

As you can see, these are other folders of individual apps that Webiny provides out of the box. These folders represent the API code that is triggered in the Cloud.

Our goal is to create our API service in the api folder.


In terms of deployments, the resources.js file is essential. In this file, we have all of the Cloud resources that are necessary for the Webiny API to work.

Creating API Service

Webiny scaffold is a tool that you can use to set up different ready-made services. It offers you a couple of scaffolds.

The one we need for our project is the GraphQL Apollo Scaffold.

npx webiny scaffold

Webiny GraphQL Apollo service scaffold

We will create a minimal API service, which we will name it the habits-tracker API. It will consist of one model, the habit model. You will be able to access the /graphql URL, by querying and writing new habits.

Webiny GraphQL Apollo service location

You need to provide the location of our new API service in the api folder because the API folder represents the whole Webiny API stack, and that's the location where you want to have our API service.

Every Apollo service that you create consists of different models. The core data model that you will have will be the Habit model.

Webiny scaffold GraphQL Apollo Service model

As you can see in the image below, the habits-tracker folder is inside the API folder. Except for the habits-tracker folder, there are some other changes.

Habits Tracker API service

We mentioned earlier, the resources.js file represents the whole cloud infrastructure that needs to be deployed. The scaffolding tool created another entry in the resources.js file that describes the newly added API. Check the image below.

Habits Tracker resources

Habits tracker API

We mentioned earlier that Webiny has a simple system of plugins that powers both the React apps and the API services. As soon as you begin developing something with Webiny, you'll be working with plugins.

The source code of the API service is in the src folder. The plugins folder is the place that contains all the plugins we are using.

Habits Tracker source code structure

The two most essential plugins are the graphql and the model plugin. We will go through each of the plugins and see what they represent.

Habits Tracker plugins

Model plugin

The models.ts file has a list of commodo models that we want our GraphQL to have.


Commodo is a set of higher order functions (HOFs) that let you define and compose rich data model objects.

The Commodo library is part of the Webiny project by default. It enables you to create data models.

GraphQL plugin

The graphql.ts file represents the schema we want the API to have. The scaffolding tool creates the whole schema for us. We will have basic getHabit and listHabits queries and the basic mutations in place such as createHabit, deleteHabit, and updateHabit.

This is a very convenient and easy to start with for every developer to develop their custom API services.


To see the updated GraphQL schema, you need to deploy the created project by running this command.

yarn webiny deploy api --env=local

If you are deploying a completely new service, you deploy the whole API stack. After the first deploy of the created service, you can continue deploying only that particular API service.

Now you can open the Main GraphQL URL, and see the updated GraphQL schema with Habits queries.

Habits Tracker query Habits

And the Habits mutations.

Habits Tracker mutation habits

Extend the API service

We mentioned in the Habits Tracker API section that the scaffolding tool setup provides two plugins. They are the graphql and the model plugins.

Habits Tracker plugins

Model plugin

In the models.ts file, we will add another field in the Habit model such as habitScore. As shown in the image below

Expand API service

After you change the model, you will need to change the GraphQL schema in the GraphQL too in the src/plugins/graphql.ts file

You have the Habit type; besides the Habit, you will have the input type used for mutations in writing and updating data. So whenever you have the Habit Type mentioned, you need to add the habitScore field. You have the Where and Sort types that are used when you query for Habits.

See the changes in the image below.

Extend Habit model

Now you will deploy only the new API service you created, for the changes to take place in the cloud.

The API service name is in the resources.js file; you can look for the Habits-tracker entry. Check the image below.

Habits Tracker resources

Deploy the new API service by running this command:

yarn webiny deploy api apiHabitsTracker api --env=local

Habits Tracker deploy after extending our API

As you can see, since you deployed the API Service, the deploy time is 13 seconds.

You can now open the Main GraphQL API and see the newly added fields in the Habit model.

Habits Tracker habitScore field

Now, you can test out the API service by creating a new Habit. Check out the image below.

Create new Habit - GraphQL Playground

As you can see, you got an error Not authorized. - To create new data, you need to create a Personal Access Token from the Admin UI. Check your profile by clicking on your image profile and then in your name.

Personal Access Tokens in user profile

Click on the Personal Access Tokens field, as shown in the image below:

Personal access token

And provide a token name in the input, as shown in the image below.

Pat name

Copy the provided Personal Access token

Copy Pat

Now we are ready to read queries and write mutations to the Habit model = )

Querying Habits

Habit Tracker Query

Creating Habits Habit Tracker mutation

Debug with TDD

One of the challenges of Cloud Development is debugging and slow iterations.

For every change you do, you have to deploy them to the Cloud to ensure everything works as expected.

The Debugging process is prolonged; you can use console logs in the code and then re-deploy the code to see the cloud watch logs.

To experience an excellent flow of work, you write tests. As you may be noticed, in the Habits Tracker folder, you had a folder called __tests__.

Habits Tracker source code structure

The scaffolding tool created the __tests__ folder for us. With the existing tests, you are creating the local GraphQL Service, by creating the same function that the API Gateway will execute in the Cloud.

This enables us to invoke the function locally, and assert certain things are in order.

This process is much faster because by running the yarn test command, the tests that the scaffold created will be executed.

You have one test for the CRUD operations for the base model, and one for the validation if the title field is not valid. See the image below.

Habits Tracker source code tests

The tests are passing because I already added the habitScore field on the tests.

As a practice, you can continue and add the changes in the __tests__/graphql/habits.js file, and in the __tests__/crud.test.js file, to see if the tests will pass or fail.

You can expand your API with other functionalities, and by adding the tests, you can be assured that the API is working, by quickly debugging if something goes wrong.

If you have any question, as we noted earlier, join our Slack Community here. Our team is always there for any questions.



Congrats 🎉

You learned what Webiny offers in terms of serverless applications. Having a Webiny project set up means having several apps to get you going right away.

With a couple of steps, you were able to start testing your custom API service immediately.

You learned the GraphQL fundamentals such as queries and mutations and tested your knowledge with the Webiny API service scaffold.

You can continue developing your API service with additional models and functionalities.

Want to learn more about Serverless APIs with Webiny? Check our docs here.

Until next time, happy Coding = )

Last updated on by albionahoti