In this blog post, we’ll explore how to build and deploy GraphQL APIs using AWS AppSync and the Serverless Framework. This tutorial is designed to be easy to follow for both beginners and experienced developers. By the end, you’ll have a working GraphQL API deployed on AWS.
GraphQL is an open-source query and data manipulation language developed by Facebook, GraphQL allows you a more flexible and feasible way to fetch and manipulate data compared to traditional API calls. It allows you to request the exact data you need. With GraphQL you as a client can specify the structure of data you want to receive, and the server will return only that data.
GraphQL is built with a strongly typed schema. That defines the type and relationships of data that can be queried. Clients interact with schema using mutations, queries, and subscriptions.
Query Language for APIs
GraphQL allows you to specify exactly what data you want in a single request. You can fetch the data you need in a single query and avoid multiple roundtrips to the server.
Single Endpoint
Not like REST APIs, which often require multiple endpoints for different resources, GraphQL APIs have only a single endpoint. Clients send their queries to the endpoint that GraphQL provides, and the server will process the query and return the appropriate response you need.
Strongly Types Schema
The schema we use in GraphQL is defined using GraphQL Schema Definition Language (SDL). This schema definition includes various types, queries, mutations, and subscriptions. Each type can have fields, which can themselves be complex types or simple scalar types like strings, integers, and booleans.
Queries
GraphQL queries allow you as a client to request specific fields you need from a resource and nested resources in a single request. A query mirrors the shape of the response the client expects. Below is a simple query example:
This query will fetch posts and retrieve their ID, title, and content of their posts.
Mutations
Mutations allow clients to modify data on the server side. They are similar to queries; queries allow clients to fetch data, but mutations allow clients to create, update, and delete data. Mutation also specifies the data that should be returned after modification. Here’s an example of a mutation to create a new post:
Subscriptions
Subscriptions allow clients to receive updated data in real time from the server. This is useful for applications that need to react to changes in data, such as chat apps or live sports scores. Subscriptions use WebSockets to push updates to the clients whenever specified events occur.
Resolvers
Resolver is noting it’s a function that connects GraphQL queries and mutations to your backend data. When a query is made, GraphQL calls the appropriate resolver to fetch the requested data. Resolver can fetch data from databases, APIs, or any other data source.
GraphQL runs faster
GraphQL is significantly faster than other communication APIs because it allows you to narrow down your request query by selecting only the fields you want to query.
Best for complex systems and microservices
We can combine multiple systems behind GraphQL’s API. It unifies them and hides their complexity. The GraphQL server is also used to fetch data from the existing systems and package it up in the GraphQL response format. This is most beneficial for legacy infrastructures or third-party APIs that are enormous in size and difficult to maintain and handle. When we have to migrate from a monolithic backend application to a microservice architecture, the GraphQL API can help us to handle communication between multiple microservices by merging them into one GraphQL schema.
Efficient Data Fetching
The main advantage of GraphQl over REST is that REST responses contain too much data or sometimes not enough data, which creates the need for another request. GraphQL solves this problem by fetching only the exact and specific data in a single request.
Single End Point
Having a single endpoint simplifies the client-server interaction; clients do not need to manage multiple endpoints for different resources; we can manage multiple resources in a single endpoint.
Real-Time Data
Built-in support for subscriptions allows clients to receive real-time updates, which is essential for many modern applications.
AWS AppSync is a managed service that uses GraphQL to make it easy for applications to get exactly the data they need. It automatically scales your GraphQL API and provides real-time updates with built-in data synchronization.
Managed GraphQL Service
This service abstracts away all of the runtime semantics and operational challenges of a GraphQL API, making it painless for developers.
Real-Time Data
It supports GraphQL subscriptions. This way, you can build real-time applications simply.
Integration with AWS Services
Integration is no challenge since the API is perfectly compatible with AWS services such as DynamoDB, Lambda, and Cognito which turn your machine into a platform for applications of any scale.
Now that we’ve covered the fundamentals of GraphQL and AppSync, let’s take a step-by-step approach to creating a backend application for our blog posts.
Before we dive into creating our GraphQL API, we need to set up our AWS environment. This includes creating an AWS account and configuring the necessary services.
Step-by-Step: Setting Up AWS
Now that our AWS environment is set up, let’s create our GraphQL API using the AppSync console. We’ll start by defining a simple schema and then add data sources and resolvers.
Step-by-Step: Creating a GraphQL API
In the AppSync console, you’ll be prompted to define your API schema. You can start with a sample schema or create your own. For this guide, let’s start with a simple schema for a Blog Post application.
This schema defines a Post type with id, title, content, and author fields. It also defines a Query type for fetching posts and a Mutation type for creating posts.
Save the schema
Click “Save” to save your schema. AppSync will validate your schema and provide feedback if there are any errors.
Resolvers are functions that handle requests for data. There are two types of resolvers unit and pipeline resolvers.
Before Step: Preprocesses request data before it moves through the resolver. This allows initial operations to be performed.
Function(s): After the before step, the request is passed to a list of functions. Each function has its own request and response handler:
We’ll need to create a resolver for each field in our schema that interacts with our data source. We’ll use unit resolvers and AppSync JavaScript (APPSYNC_JS) as the resolver runtime.
Add a resolver for createPost:
To Add a resolver for posts:
AWS AppSync provides a built-in GraphQL playground to test your API. This playground allows you to run queries and mutations against your API and see the results in real-time.
Step-by-Step: Testing the API
Run a Query: Enter the following query to fetch all posts:
2. Click the “Run” button to execute the query:
You should see an empty list if no posts have been created yet.
Run a Mutation: Enter the following mutation to create a new post:
2. Create a Serverless Project:
Initialize a new Serverless project.
3. Instal Dependencies:
Install the AWS AppSync plugin for Serverless.
4. Configure serverless.yml:
Edit the serverless.yml file to include the AppSync plugin and configure your API.
First of all, set up the service name as blog-post and specify that you are using version 3 of the Serverless Framework.
The provider section defines AWS as the cloud provider, sets the region to us-east-1, and specifies Node.js version 20.x as the runtime environment for your application.
provider:
plugins section includes the AppSync plugin to enable integration with AWS AppSync.
plugins:
The appSync section configures your AppSync API, naming it blog-post-api, using API_KEY for authentication, and defining an API key that expires after one month. appSync:
Mutation.createPost
Defines a unit resolver for the createPost mutation, using postTable as the data source and referencing the code in resolvers/createPost.js.
Query.posts:
Defines a unit resolver for the posts query, also using postTable as the data source, with the implementation in resolvers/getAllPost.js.
resolvers:
The resources section defines a DynamoDB table named BlogPost with a primary key (pk) of type string and specifies the key schema for the table.
resources:
5. Create Schema File:
Create a file named schema.graphql in the root of your project and paste the above schema.
6. Create Resolves:
Create a folder named resolvers in the root of your project and create two js files one is createPost.js and another one is getAllPost.js and paste the resolvers code that we define above.
7. Deploy Your Service:
Run the deploy command to deploy your API.
This command will package and deploy your service to AWS. The Serverless Framework will provide the API endpoint after deployment.
Retrieve the Endpoint: After deployment, the Serverless Framework will output the API endpoint. You can use this endpoint to interact with your GraphQL API.
Full Code:
Following this guide, you have successfully set up a GraphQL API with the help of AWS AppSync and managed to deploy it utilizing Serverless Framework.
You’ve learned how to add and connect data sources, write resolvers, and carry out the testing of your API.
With this configuration, it is possible to create highly flexible and scalable APIs that are capable of complex query resolution.
AWS AppSync and the Serverless Framework work together to provide a strong toolkit for building modern apps, facilitating real-time data handling, and simplifying development.