{
posts {
id
title
Content
}
}
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.
Introduction to GraphQL
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.
Key Concept of GraphQL
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:
mutation CreatePost {
createPost(title: "Sample Post", content: "This is a sample Post", author: "Jone") {
id
title
Content
author
}
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.
subscription {
newPost {
id
title
content
}
}
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.
Advantages of GraphQL
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.
Understanding AWS AppSync
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.
Key Features of AWS AppSync
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.
Step 1: Setting Up Your AWS Environment
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
- Log in to the AWS Management Console
If you don’t have an AWS account, sign up for a free account. Once you have an account, log in to the AWS Management Console. - Navigate to AppSync
In the AWS Management Console, search for “AppSync” in the AWS services search bar and click on it.
Step 2: Creating a GraphQL API
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
- Create a new API
Click “Create API” and choose “Start from scratch.” This will allow us to define our own schema and resolvers. - Define the API name
Enter a name for your API (e.g., “MyBlogPostAPI”). This will be the name used to identify your API in the AWS Management Console.
Step 3: Define the API schema
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.
type Post {
id: ID!
title: String!
content: String!
author: String!
}
type Query {
posts: [Post]
}
type Mutation {
createPost(title: String!, content: String!, authorId: String!): Post
}
type Subscription {
newPost: Post
}
schema {
query: Query
mutation: Mutation
subscription: Subscription
}
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.
Step 4: Adding Data Sources
- Navigate to Data Sources
Click on the “Data Sources” tab in the AppSync console and then click “Create Data Source.” - Select DynamoDB
For this example, choose DynamoDB as your data source and enter a name for it (e.g., “BlogPostTable”).
{
"TableName": "PostTable",
"AttributeDefinitions": [
{
"AttributeName": "pk",
"AttributeType": "S"
}, {
"AttributeName": "sk",
"AttributeType": "S"
}
],
"KeySchema": [
{
"AttributeName": "pk",
"KeyType": "HASH"
},
{
"AttributeName": "sk",
"KeyType": "RANGE"
}
]
}
Step 5: Creating Resolvers
Resolvers are functions that handle requests for data. There are two types of resolvers unit and pipeline resolvers.
- Unit resolvers
A unit resolver is composed of code that defines a single request and response handler that are executed against a data source. The request handler takes a context object as an argument and returns the request payload used to call your data source. The response handler receives a payload back from the data source with the result of the executed request. The response handler transforms the payload into a GraphQL response to resolve the GraphQL field. - Pipeline Resolvers
When implementing pipeline resolvers, the general structure they follow includes:
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:
- Request Handler
Performs operations against the data source. - Response Handler
Processes the data source’s response before passing it to the next function. - Functions
They execute serially in the order defined by the developer. The final result is passed to the after step. - After Step
A handler function that performs final operations on the response from the last function before passing it to the GraphQL response.
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:
- In your API, choose the Schema tab.
- In the Resolvers pane, find the createPost field under the Mutation type, then choose Attach.
- Choose your data source, then choose Create.
- In your code editor, replace the code with this snippet:
import { util } from "@aws-appsync/utils";
import * as ddb from "@aws-appsync/utils/dynamodb";
function request(ctx) {
const { input } = ctx.arguments;
const id = util.autoId()
const sk = `${id}`;
const item = {
id,
...input
};
const key = { pk: "POST", sk };
return ddb.put({ key, item });
}
function response(ctx) {
return ctx.result;
}
export {
request,
response
};
To Add a resolver for posts:
- In your API, choose the Schema tab.
- In the Resolvers pane, find the posts field under the Query type, then choose Attach.
- Choose your data source, then choose Create.
- In your code editor, replace the code with this snippet:
import * as ddb from '@aws-appsync/utils/dynamodb'
export function request(ctx) {
return ddb.get({ key: { pk: "POST" } })
}
export const response = (ctx) => ctx.result
Testing Your GraphQL API
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
- Navigate to the Queries Tab
In the AppSync console, go to the “Queries” tab. This will open the GraphQL playground
Run a Query: Enter the following query to fetch all posts:
query ListPost {
posts {
id
title
Content
author }
}
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:
mutation CreatePost {
createPost(title: "Sample Post", content: "This is a sample Post", author: "Jone") {
id
title
Content
author
}
- Click the “Run” button to execute the mutation.
You should see the new post in the response. - Run the Query Again:
Run the ListPost query again to see the newly created post in the list.
Deploying Blog Post Applications with Serverless
Step-by-Step: Deploying with Serverless
- Install Serverless Framework:
If you haven’t already, install it globally using npm.
npm install -g serverless
2. Create a Serverless Project:
Initialize a new Serverless project.
serverless create --template aws-nodejs --path graphql-appsync
cd graphql-appsync
3. Instal Dependencies:
Install the AWS AppSync plugin for Serverless.
npm install serverless-appsync-plugin
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.
service: blog-post
frameworkVersion: "3"
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:
service: blog-post
frameworkVersion: "3"
plugins section includes the AppSync plugin to enable integration with AWS AppSync.
plugins:
- serverless-appsync-plugin
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:
name: blog-post-api
authentication:
type: "API_KEY"
apiKeys:
- name: blog-post-key
expiresAfter: 1M
The resolvers section specifies how to handle GraphQL operations:
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:
Mutation.createPost:
kind: UNIT
dataSource: postTable
code: resolvers/createPost.js
Query.posts:
kind: UNIT
dataSource: postTable
code: resolvers/getAllPost.js
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:
Resources:
MyTable:
Type: AWS::DynamoDB::Table
Properties:
TableName: BlogPost
AttributeDefinitions:
- AttributeName: pk
AttributeType: S
- AttributeName: sk
AttributeType: S
KeySchema:
- AttributeName: pk
KeyType: HASH
- AttributeName: sk
KeyType: RANGE
BillingMode: PAY_PER_REQUEST
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.
Serverless Deploy
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:
service: blog-post
frameworkVersion: "3"
provider:
name: aws
region: us-east-1
runtime: nodejs20.x
plugins:
- serverless-appsync-plugin
appSync:
name: blog-post-api
authentication:
type: "API_KEY"
apiKeys:
- name: blog-post-key
expiresAfter: 1M
schema: "schema.graphql"
dataSources:
postTable:
type: AMAZON_DYNAMODB
description: "Blog Post Table"
config:
tableName: BlogPost
resolvers:
Mutation.createPost:
kind: UNIT
dataSource: postTable
code: resolvers/createPost.js
Query.posts:
kind: UNIT
dataSource: postTable
code: resolvers/getAllPost.js
resources:
Resources:
MyTable:
Type: AWS::DynamoDB::Table
Properties:
TableName: BlogPost
AttributeDefinitions:
- AttributeName: pk
AttributeType: S
- AttributeName: sk
AttributeType: S
KeySchema:
- AttributeName: pk
KeyType: HASH
- AttributeName: sk
KeyType: RANGE
BillingMode: PAY_PER_REQUEST
Conclusion
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.
30/10/2024

.png?width=170&height=122&name=glassdoor%20(1).png)
