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.
- Install the Serverless Framework: Open your terminal and run:
npm install -g serverless
- Create a New Project:
serverless create --template aws-nodejs --path my-serverless-api
cd my-serverless-api
- 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
Go to AWS Management Console and navigate to Cognito.
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.