A Step-by-Step Guide for Deploying a Node.js GraphQL Server to AWS Lambda with GitHub Actions and Terraform
Tags: node, aws, github, webdev
Published: 2023-07-13 12:55:59

Deploying a Node.js GraphQL server to AWS Lambda offers numerous advantages, including scalability, cost efficiency, and simplified management. In this step-by-step guide, we'll walk you through the process of setting up a deployment pipeline for your Node.js GraphQL server using GitHub Actions for continuous integration and Terraform for AWS infrastructure management. By the end, you'll have a streamlined workflow for deploying your server to AWS Lambda with ease, using the NodeJS. 

Prerequisites:
Before we begin, ensure you have the following prerequisites in place:

1. A Node.js GraphQL server: Prepare your Node.js GraphQL server code, ensuring it is functional and ready for deployment.
2. AWS Account: Sign up for an AWS account if you don't have one already.
3. GitHub Account: Ensure you have a GitHub account to utilize GitHub Actions.
4. Basic knowledge of Git and GitHub: Familiarize yourself with version control and basic Git operations.
5. Terraform Installed: Install Terraform on your local machine (https://www.terraform.io/downloads.html).

Step 1: Set up AWS Lambda and API Gateway using Terraform:
To begin, we'll use Terraform to provision the necessary AWS resources. Create a new directory and follow these steps:

1. Initialize Terraform in your project directory using the command: terraform init.
2. Create a new file named main.tf and define the AWS resources required for Lambda and API Gateway. Here's a sample configuration:

```hcl
provider "aws" {
  region = "us-east-1"  # Replace with your desired AWS region
}

resource "aws_lambda_function" "graphql_server" {
  function_name = "my-graphql-server"
  runtime = "nodejs18.x"
  handler = "index.handler"
  memory_size = 512
  timeout = 10

  # Add other necessary configurations, such as VPC settings or environment variables.
}

resource "aws_api_gateway_rest_api" "graphql_api" {
  name = "my-graphql-api"
  endpoint_configuration {
    types = ["REGIONAL"]
  }
}

resource "aws_api_gateway_resource" "graphql_resource" {
  rest_api_id = aws_api_gateway_rest_api.graphql_api.id
  parent_id = aws_api_gateway_rest_api.graphql_api.root_resource_id
  path_part = "graphql"
}

resource "aws_api_gateway_method" "graphql_method" {
  rest_api_id = aws_api_gateway_rest_api.graphql_api.id
  resource_id = aws_api_gateway_resource.graphql_resource.id
  http_method = "POST"
  authorization = "NONE"
}

resource "aws_api_gateway_integration" "graphql_integration" {
  rest_api_id = aws_api_gateway_rest_api.graphql_api.id
  resource_id = aws_api_gateway_resource.graphql_resource.id
  http_method = aws_api_gateway_method.graphql_method.http_method
  integration_http_method = "POST"
  type = "AWS_PROXY"
  uri = aws_lambda_function.graphql_server.invoke_arn
}

resource "aws_lambda_permission" "graphql_permission" {
  statement_id = "AllowAPIGatewayInvoke"
  action = "lambda:InvokeFunction"
  function_name = aws_lambda_function.graphql_server.function_name
  principal = "apigateway.amazonaws.com"
  source_arn = aws_api_gateway_rest_api.graphql_api.execution_arn
}
```

- Customize the configuration to suit your requirements, such as function name, region, or additional environment variables.
- Apply the Terraform configuration by running: terraform apply.
- Terraform will provision the Lambda function, API Gateway, and necessary permissions.

Step 2: Configure GitHub Actions for Continuous Deployment:
GitHub Actions allow you to automate the deployment process. Follow these steps to create a deployment workflow:

1. Create a new file named .github/workflows/deploy.yml in your GitHub repository.
2. Define the deployment workflow using the following code snippet:

```yaml
name: Deploy to AWS Lambda

on:
  push:
    branches:
      - main

jobs:
  deploy:
    runs-on: ubuntu-latest

    steps:
      - name: Checkout code
        uses: actions/checkout@v2

      - name: Set up Node.js
        uses: actions/setup-node@v2
        with:
          node-version: 18

      - name: Install dependencies
        run: npm ci

      - name: Deploy to AWS Lambda
        uses: appleboy/lambda-action@v0.5.0
        with:
          aws_access_key_id: ${{ secrets.AWS_ACCESS_KEY_ID }}
          aws_secret_access_key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
          region: us-east-1  # Replace with your desired AWS region
          function_name: my-graphql-server
          zip_file: index.js
```

- The workflow is triggered whenever changes are pushed to the main branch.
- Ensure you have the AWS access keys stored as secrets in your GitHub repository settings.
- Customize the region and function name in the workflow file to match your setup.
Step 3: Update your Node.js GraphQL Server code:
To ensure your GraphQL server works correctly in the Lambda environment, make a few adjustments:

1. Modify your server code (e.g., index.js) to export a handler function. Here's an example:

```JavaScript
const { ApolloServer, gql } = require('apollo-server-lambda');

const typeDefs = gql`
  type Query {
    hello: String
  }
`;

const resolvers = {
  Query: {
    hello: () => 'Hello, World!',
  },
};

const server = new ApolloServer({
  typeDefs,
  resolvers,
});

exports.handler = server.createHandler();
```

- Ensure you have the necessary dependencies (e.g., apollo-server-lambda) in your package.json file.

Step 4: Commit and Deploy:
Commit your changes to the GitHub repository, and the deployment workflow will automatically trigger. The GitHub Actions workflow will build your project, create a deployment package, and deploy it to AWS Lambda.

Congratulations! You have successfully set up a deployment pipeline for your Node.js GraphQL server using GitHub Actions and Terraform. You now have an automated process for deploying your server to AWS Lambda. This streamlined workflow will save you time and effort, allowing you to focus more on developing your application. Experiment with different features and configurations to further optimize your deployment process. Happy coding and deploying!