Building a RESTful API on AWS
Creating AWS resources will incur charges if the configurations are not within the free-tier limits. Always check the AWS pricing before creating any AWS resources.
Introduction
In this tutorial, you'll learn how to build an API on AWS using Lambda, API Gateway, OpenAPI, DynamoDB, Cognito, and WAF. Specifically, we'll cover how to set up a serverless API that supports all CRUDL (Create, Read, Update, Delete, List) operations, implement rate limiting, access logging, API keys, and user-owner-based authorization.
By the end of this tutorial, you will have a fully functional API deployed on AWS, and you'll be able to apply these skills to build scalable and secure serverless applications.
Getting Started
What is a RESTful API?
A RESTful API (Representational State Transfer API) is a web service that uses HTTP methods to enable communication between a client and a server. It allows for interaction with web services using standard HTTP methods like GET, POST, PUT, DELETE, and PATCH.
What Services Will We Be Using?
We'll be using the following services in this tutorial:
- AWS Lambda: A serverless compute service that lets you run code without provisioning or managing servers.
- Amazon API Gateway: A fully managed service that makes it easy for developers to create, publish, maintain, monitor, and secure APIs.
- Amazon DynamoDB: A fast and flexible NoSQL database service for all applications that need consistent, single-digit millisecond latency at any scale.
- Amazon Cognito: A service that provides authentication, authorization, and user management for web and mobile apps.
- AWS WAF (Web Application Firewall): A web application firewall that helps protect your web applications from common web exploits.
Prerequisites
Before you begin, make sure you have the following:
- An AWS Account: Sign up for an AWS account if you don't have one.
- AWS CLI Installed and Configured: Install the AWS CLI and configure it with your AWS credentials.
- Node.js v18 Installed: Ensure you have Node.js v18 installed on your machine.
- Basic Knowledge of JavaScript and AWS Services: Familiarity with JavaScript programming and AWS services like Lambda and API Gateway.
Steps
We'll follow these steps to build our API:
- Set Up the Development Environment: Configure AWS CLI and set up your project directory.
- Create a DynamoDB Table: Set up a DynamoDB table to store data for the API.
- Develop Lambda Functions for CRUDL Operations: Write Lambda functions to handle Create, Read, Update, Delete, and List operations.
- Define API with OpenAPI Specification: Use OpenAPI to define your API endpoints and methods.
- Configure Amazon API Gateway: Set up API Gateway to integrate with Lambda functions and enforce rate limiting and API keys.
- Set Up Amazon Cognito for Authorization: Configure Cognito for user authentication and authorization.
- Implement AWS WAF for Security: Set up AWS WAF to protect your API from common web exploits.
- Deploy and Test the API: Deploy your API and test all endpoints to ensure they work correctly.
Step 1: Set Up the Development Environment
Before diving into coding, we need to set up our development environment to interact with AWS services and manage our project efficiently.
Instructions:
-
Set Up the Project Directory
-
Create a new directory for your project and navigate into it:
bashLoading... -
Initialize a new Node.js project:
bashLoading...
-
-
Install Necessary Dependencies
-
Install AWS SDK and other required packages:
bashLoading... -
Note: We use
for generating unique identifiers anduuid
for token handling if needed.jsonwebtoken
-
Step 2: Create a DynamoDB Table
We'll create a DynamoDB table to store the data that our API will manage.
Instructions:
-
Create the DynamoDB Table
-
Use the AWS CLI to create a table named
with a primary keyItems
:itemId
bashLoading... -
Verify Table Creation:
bashLoading...
-
-
Enable DynamoDB Stream (Optional)
-
If you plan to handle real-time updates, enable DynamoDB Streams:
bashLoading...
-
Step 3: Develop Lambda Functions for CRUDL Operations
We'll create Lambda functions to perform Create, Read, Update, Delete, and List operations on our DynamoDB table.
Instructions:
-
Set Up Lambda Function Directory
-
Create a directory for Lambda functions:
bashLoading...
-
-
Create the Create Function (
)createItem.js
-
Code:
javascriptLoading...
-
-
Create the Read Function (
)getItem.js
-
Code:
javascriptLoading...
-
-
Create the Update Function (
)updateItem.js
-
Code:
javascriptLoading...
-
-
Create the Delete Function (
)deleteItem.js
-
Code:
javascriptLoading...
-
-
Create the List Function (
)listItems.js
-
Code:
javascriptLoading...
-
-
Package and Deploy Lambda Functions
-
Package Functions:
bashLoading... -
Deploy Functions Using AWS CLI:
bashLoading... -
Note: Replace
with the ARN of an IAM role that has the necessary permissions.[YOUR_IAM_ROLE_ARN]
-
Step 4: Define API with OpenAPI Specification
We'll define our API endpoints using the OpenAPI specification to ensure consistency and enable automatic documentation.
Instructions:
-
Create an OpenAPI YAML File (
)api.yaml
-
Structure:
yamlLoading...
-
-
Integrate OpenAPI with API Gateway
-
Use the AWS CLI to import the API definition:
bashLoading... -
Note: This command will return the
of the created API.id
-
Step 5: Configure Amazon API Gateway
We'll set up API Gateway to integrate with our Lambda functions, enforce rate limiting, and manage API keys.
Instructions:
-
Link Lambda Functions to API Endpoints
-
For each endpoint and method, configure API Gateway to use the corresponding Lambda function.
-
Example: Link the
endpoint to thePOST /items
Lambda function.createItem
-
-
Enable Rate Limiting and Throttling
-
Create a Usage Plan:
bashLoading... -
Associate API Stages:
bashLoading... -
Note: Replace
with your API's ID.[API_ID]
-
-
Implement API Keys
-
Create an API Key:
bashLoading... -
Associate API Key with Usage Plan:
bashLoading... -
Note: Replace
and[USAGE_PLAN_ID]
with the appropriate IDs.[API_KEY_ID]
-
-
Enable Access Logging
-
Set Up a CloudWatch Log Group:
bashLoading... -
Enable Logging on API Gateway Stage:
bashLoading... -
Note: Replace
and[LOG_GROUP_ARN]
accordingly.[LOG_FORMAT]
-
Step 6: Set Up Amazon Cognito for Authorization
We'll use Amazon Cognito to manage user authentication and secure our API endpoints.
Instructions:
-
Create a Cognito User Pool
-
Using AWS CLI:
bashLoading... -
Note: This will return the
.UserPoolId
-
-
Create a Cognito User Pool Client
-
Create User Pool Client:
bashLoading... -
Note: Replace
with your User Pool ID.[USER_POOL_ID]
-
-
Configure API Gateway to Use Cognito Authorizer
-
Create an Authorizer:
bashLoading... -
Attach Authorizer to API Methods
- For each method, update the integration to require authorization.
-
-
Update Lambda Functions to Extract User Information
- As seen in the Lambda functions, use to get user details.
event.requestContext.authorizer.claims
- As seen in the Lambda functions, use
Step 7: Implement AWS WAF for Security
We'll protect our API from common web exploits using AWS WAF.
Instructions:
-
Create a Web ACL
-
Create Web ACL:
bashLoading... -
Note:
should define the rules you want to apply.waf-rules.json
-
-
Associate Web ACL with API Gateway
-
Get the ARN of the API Gateway Stage
bashLoading... -
Associate Web ACL
bashLoading... -
Note: Replace
and[WEB_ACL_ARN]
accordingly.[API_GATEWAY_STAGE_ARN]
-
Step 8: Deploy and Test the API
Now that everything is set up, we'll deploy the API and test all endpoints.
Instructions:
-
Deploy the API
-
Create Deployment
bashLoading...
-
-
Test the Endpoints
-
Create Item
bashLoading... -
Get Item
bashLoading... -
Update Item
bashLoading... -
Delete Item
bashLoading... -
List Items
bashLoading... -
Note: Replace
,[API_ID]
,[REGION]
,[JWT_TOKEN]
, and[API_KEY]
with actual values.{itemId}
-
Conclusion
Congratulations! You've successfully built a secure, serverless API on AWS using Node.js and various AWS services. You now know how to integrate AWS Lambda, API Gateway, DynamoDB, Cognito, and WAF to create a scalable and secure API.
Customizing the Project
You can further enhance this project by:
- Adding Pagination: Implement pagination in the list endpoint to handle large datasets.
- Implementing CI/CD: Set up a continuous integration and deployment pipeline using AWS CodePipeline.
- Enhancing Security: Add additional AWS WAF rules or integrate AWS Shield for DDoS protection.
Next Steps
To continue learning:
- Explore AWS Services: Delve deeper into AWS services like AWS Step Functions or Amazon SQS.
- Learn about Serverless Frameworks: Use frameworks like Serverless or AWS SAM to simplify deployment.
- Study Advanced Security: Implement OAuth 2.0 or integrate with AWS Secrets Manager for credential management.
References
Here's a complete bash script that automates all the steps in this tutorial. Running this script will set up a fully functional RESTful API on AWS.
All Steps as a Script
Notes:
- Before running this script, ensure that:
- You have the AWS CLI installed and configured with appropriate permissions.
- You have installed for JSON parsing in bash.
jq
- You replace any placeholders with your actual values where necessary.
- The script will create AWS resources that may incur costs. Be sure to clean up resources when they are no longer needed.
- This script assumes that the AWS CLI is configured with credentials that have the necessary permissions to create IAM roles, Lambda functions, API Gateway APIs, DynamoDB tables, Cognito user pools, and WAF configurations.
Commands and Code Snippets
Here's a summary of the commands and code used throughout this tutorial for your convenience.