How to build Serverless GraphQL API using AWS AppSync
Tags: aws, lambda, appsync, graphql
Published: 2022-09-25 12:00:06

## What is GraphQL?
GraphQL is a query language for APIs which provides a complete and understandable description of the data in the API. GraphQL APIs give the exact data that the client wants, nothing more or less.

GraphQL is fast and flexible to use as compared to REST. GraphQL allows clients to decide what data to be returned unlike servers in REST. GraphQL reduces the number of HTTP requests since it can get you all the data required by your app in a single request. According to official documentation, apps using GraphQL can be quick even on slow mobile network connections.

## GraphQL Operations

1. **Query** - Used to fetch the data from the GraphQL API, same as GET request
2. **Mutation** - Used to manipulate the data, same as CREATE, UPDATE, DELETE
3. **Subscription** - Used to listen or subscribe to the changes to the data

## What is AppSync?
AWS AppSync is a fully managed, serverless GraphQL API service offered by Amazon Web Services. AppSync allows developers to build GraphQL APIs without much hassle; it takes care of the parsing and resolution of requests.

It also natively supports integration with other AWS services like AWS Lambda, NoSQL and SQL databases, and HTTP APIs to gather backend data for the API.

## What are we going to build?
We will build a GraphQL API using AWS AppSync to perform CRUD operations. For example, we will make an API that will allow us to create, read, update and delete a blog. We will use DynamoDB to store our blog data to achieve the functionality of the CRUD API we will use Lambda. To configure our resources we will use [Serverless Framework](https://www.serverless.com/).

## Initialising the project
First of all, create an empty directory and we will create a new serverless project in this directory. You can use the following command to do that.

`serverless create --template aws-nodejs`

The above command will create a new serverless project for you from scratch and you can find the `serverless.yml` file in the editor. This file is the heart of the project, where we will define all our infrastructure.

This is how the `serverless.yml` file will look after all the resources are defined. I will explain each section of this file further.

{% embed https://gist.github.com/iabhishek07/132a2a82d35d69cf2433bbed8b61965a %}

Firstly, start defining the basics like region, stage, and global configuration variables in the provider section.

```
provider:
  name: aws
  runtime: nodejs12.x
  lambdaHashingVersion: 20201221
  region: ${env:REGION, 'ap-south-1'}
  stage: ${opt:stage, 'dev'}
  timeout: 30

```
Then, we define global-level environment variables, as defined in the image below.


```
  # Environment variables
  environment:
    STAGE: ${self:provider.stage}
    REGION: ${self:provider.region}
    SERVICE_NAME: ${self:service}-${self:provider.stage}
    DYNAMODB: ${self:service}-${self:provider.stage}
```

## IAM role statements
Since we are going to use DynamoDB to store the data and it will be integrated with the lambda function, we will need to define IAM role statements to give permission to the lambda function to access our DynamoDB table.

```
# IAM statements
  iamRoleStatements:
    - Effect: Allow
      Action:
        - dynamodb:GetItem
        - dynamodb:UpdateItem
        - dynamodb:DeleteItem
        - dynamodb:PutItem
      Resource: "arn:aws:dynamodb:${opt:region, self:provider.region}:*:table/${self:provider.environment.DYNAMODB}"
    - Effect: Allow
      Action:
        - lambda:invokeFunction
      Resource: "*"
```

## serverless-appsync-plugin
serverless-appsync-plugin allows us to deploy AppSync API without much hassle, it provides a lot of configurations to set up your API on AppSync.

```
plugins:
  - serverless-appsync-plugin
```

## Lambda Functions

```
functions:
  createBlog:
    handler: createBlog/index.handler
    name: createBlog-${self:provider.stage}
  getBlog:
    handler: getBlog/index.handler
    name: getBlog-${self:provider.stage}
  updateBlog:
    handler: updateBlog/index.handler
    name: updateBlog-${self:provider.stage}
  deleteBlog:
    handler: deleteBlog/index.handler
    name: deleteBlog-${self:provider.stage}
```

Now, it's time to set up the appsync configuration provided by serverless-appsync-plugin, this plugin has a lot of configurations available, in the below code snippet you can find some of them. In the custom section of the serverless.yml file, we can define the configurations.

To know more about what each of these configuration parameters does, head over to this [link](https://www.npmjs.com/package/serverless-appsync-plugin).

```
custom:
  appSync:
    name: appsync-crud-api
    schema: schema.api.graphql
    authenticationType: API_KEY
    apiKeys:
      - apiKey
    dataSources:
      - type: AWS_LAMBDA
        name: createBlog
        description: 'Lambda'
        config:
          functionName: createBlog           
      - type: AWS_LAMBDA
        name: getBlog
        description: 'Lambda'
        config:
          functionName: getBlog
      - type: AWS_LAMBDA
        name: updateBlog
        description: 'Lambda'
        config:
          functionName: updateBlog
      - type: AWS_LAMBDA
        name: deleteBlog
        description: 'Lambda'
        config:
          functionName: deleteBlog
```

## DynamoDB Table
To store the blog data we are using the dynamodb table which can be configured like the below:

```
resources:
  Resources:
    BlogsTable:
      Type: 'AWS::DynamoDB::Table'
      Properties:
        AttributeDefinitions:
          - AttributeName: id
            AttributeType: S
        KeySchema:
          - AttributeName: id
            KeyType: HASH
        ProvisionedThroughput:
          ReadCapacityUnits: 1
          WriteCapacityUnits: 1
        TableName: ${self:provider.environment.DYNAMODB}
```

## GraphQL Schema
Every graphql API needs a schema where we define all the operations(query, mutation, subscription). We will need to create a file named `schema.api.graphql`. This same file we have referred to in the appsync plugin configuration is in the custom section. The file should look something like this:

```
schema {
    query: Query
    mutation: Mutation
}

type Query {
    # Query for blog details
    getBlog(id: ID!): Blog
}

type Mutation {
    # Create blog
    createBlog(input: CreateBlogInput!): AWSJSON

    # Update blog
    updateBlog(input: UpdateBlogInput!): AWSJSON

    # delete blog
    deleteBlog(id: ID!): AWSJSON
}

input UpdateBlogInput {
    id: ID!
    title: String
    blogUrl: String
    author: String
    publicationDate: AWSDate
}

input CreateBlogInput {
    title: String!
    blogUrl: String!
    author: String!
    publicationDate: AWSDate!
}

type Blog {
    id: ID
    title: String
    blogUrl: String
    author: String
    publicationDate: AWSDate
}
```

## Lambda Function Code
Now it's time to move towards lambda functions, which will act as a resolver for the API. Hence the name, "Lambda Resolvers". As you can see in the image below, I have created a folder for each of the lambda functions which we defined in the functions section in the `serverless.yml` file.

All four lambdas just perform very simple dynamodb CRUD operations using dynamodb `DocumentClient()` from aws-sdk. I won't explain the lambda code since it's really straightforward. You can head over to this [repository](https://bit.ly/appsync-crud-api) and find the code.

![Lambda Folder Structure](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/p0d6iryy2nb9ps5s92r1.png)

If you have followed until now, then it's time to deploy our service 🚀.

Use `serverless deploy` to deploy all of your defined resources to the aws cloud. This will give you the deployed API URL and API_KEY in the console which can be used by the client application.

## Testing the GraphQL API
Once your deployment is successful, you'll see something like this in the AppSync console. You'll see a tile with the name you have given to your API.

![Testing in AppSync Console](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ygms2qhz32yvwxperw7h.png)


Click on the tile and you'll see another interface, then in the left nav click on Queries. You should see the following interface where you will find all the CRUD operations we have defined in our `schema.api.graphql` file.

In the mutations section, you'll find `createBlog`, `updateBlog`, and `deleteBlog`, and in the queries section, you'll find `getBlog`.

You can then test the `createBlog` mutation by entering some data and hitting the play button on the top should give you the success response by returning the created blog's data in the rightmost window.

![Testing in AppSync Console](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/s93fjcfiwkbddgou9wyy.png)

By doing the same steps, you can test the other operations as well.

Aaaand 🥁, we are done with the whole backend side of things. We just created an API for a simple blog application.

That's all for this blog, if you liked it do not forget to react to the blog. Thanks for reading and following along, Peace ☮✌️.

**Feel free to reach out to me:**

> GitHub - https://github.com/iabhishek07
> Twitter - https://twitter.com/abhishekrwagh
> LinkedIn - https://www.linkedin.com/in/iamabhishek21/
> Email - waghabhi21@gmail.com