Building a Serverless API with AWS Lambda and Node.js

Building a Serverless API with AWS Lambda and Node.js

·

4 min read

Introduction

Serverless architecture has transformed backend development, allowing developers to focus purely on writing code without worrying about managing servers. AWS Lambda, in combination with API Gateway and the Serverless Framework, offers an excellent way to build scalable and cost-efficient APIs. In this post, we'll walk through creating a serverless API using AWS Lambda, Node.js, and MongoDB with Mongoose.

Prerequisites

Before we dive in, make sure you have:

  • A basic understanding of Node.js.

  • An AWS account.

  • Installed Node.js (v14 or later).

  • Installed the Serverless Framework

npm install -g serverless

Setting Up the Serverless Framework

First, let’s set up a new Serverless project and install necessary packages.

  1. Install the Serverless Framework: Open your terminal and run:
npm install -g serverless
  1. Create a New Project:
serverless create --template aws-nodejs --path my-serverless-api
cd my-serverless-api
  1. Project Structure: Your project will look like this:
├── handler.js
├── serverless.yml
└── package.json

Writing Your First Lambda Function

Let’s create a simple function to return a "Hello, World!" message.

In the handler.js file, replace the default function with:

module.exports.hello = async (event) => {
  return {
    statusCode: 200,
    body: JSON.stringify({
      message: 'Hello, World!',
    }),
  };
};

Configuring API Gateway

To expose the Lambda function via HTTP, configure API Gateway in the serverless.yml file.

service: my-serverless-api

provider:
  name: aws
  runtime: nodejs14.x

functions:
  hello:
    handler: handler.hello
    events:
      - http:
          path: hello
          method: get
          cors: true

Deploy it by running:

serverless deploy

This will create an HTTP endpoint that returns the message "Hello, World!".

Environment Variables Configuration

To manage environment variables (such as API keys or database URIs), you can define them in serverless.yml.

Step 1: Define Environment Variables in serverless.yml

Under the provider section:

provider:
  name: aws
  runtime: nodejs14.x
  environment:
    MONGODB_URI: "mongodb+srv://<username>:<password>@cluster.mongodb.net/myDatabase"
    MY_API_KEY: "12345"

Step 2: Access Environment Variables in Lambda Functions

Use process.env to access the environment variables in your code.

module.exports.hello = async (event) => {
  const apiKey = process.env.MY_API_KEY;

  return {
    statusCode: 200,
    body: JSON.stringify({
      message: `Your API key is ${apiKey}`,
    }),
  };
};

Redeploy the service with:

serverless deploy

Connecting to MongoDB Using Mongoose

To interact with MongoDB, you'll need to install and configure Mongoose.

Step 1: Install Mongoose

Run the following command to install Mongoose:

npm install mongoose

Step 2: Create a MongoDB Connection

In the handler.js file, create a Mongoose connection:

const mongoose = require('mongoose');

const connectToDatabase = async () => {
  if (mongoose.connection.readyState === 1) return;
  await mongoose.connect(process.env.MONGODB_URI, {
    useNewUrlParser: true,
    useUnifiedTopology: true,
  });
};

module.exports.createUser = async (event) => {
  await connectToDatabase();
  const User = mongoose.model('User', new mongoose.Schema({ name: String }));

  const data = JSON.parse(event.body);
  const user = new User({ name: data.name });

  await user.save();

  return {
    statusCode: 201,
    body: JSON.stringify({ message: 'User created', user }),
  };
};

Step 3: Add Mongoose Connection in serverless.yml

Make sure that your MongoDB connection URI is added to the environment section:

provider:
  name: aws
  runtime: nodejs14.x
  environment:
    MONGODB_URI: "mongodb+srv://<username>:<password>@cluster.mongodb.net/myDatabase"

Now, you can connect to MongoDB in your Lambda functions and perform CRUD operations.

Adding an Authorizer for API Security

To secure your API, you can integrate an authorizer using AWS Cognito or JWT tokens. Here’s an example using a Cognito Authorizer.

Step 1: Create a Cognito User Pool

  1. Go to AWS Management Console and navigate to Cognito.

  2. Create a new User Pool and note down the pool’s ARN.

Step 2: Configure Authorizer in serverless.yml

In your serverless.yml, set up the authorizer:

functions:
  securedEndpoint:
    handler: handler.securedEndpoint
    events:
      - http:
          path: secure
          method: get
          authorizer:
            arn: arn:aws:cognito-idp:<region>:<account-id>:userpool/<user-pool-id>

This configuration means that any request to /secure must include a valid Cognito token to be processed.

Step 3: Implement the Secured Endpoint in Lambda

In handler.js, add the secured function:

module.exports.securedEndpoint = async (event) => {
  return {
    statusCode: 200,
    body: JSON.stringify({ message: 'This is a secured endpoint' }),
  };
};

Testing Locally with Serverless Offline

To test Lambda functions locally, install the serverless-offline plugin:

npm install serverless-offline --save-dev

Then add it to the serverless.yml:

plugins:
  - serverless-offline

Run the service locally:

serverless offline

Visit http://localhost:3000/hello or any other endpoint you’ve set up.