July 29, 2022 –5 min read
Amazon API Gateway is an AWS service for managing APIs at any scale.
Broadly it’s categorized into two products – REST APIs and HTTP APIs. While both allow us to build RESTful APIs, the REST API product in Gateway provides more advanced features and configurations.
REST API supports different integration options to power the APIs we build, and AWS Lambda is one of them.
In a previous blog post, I walked through the different building blocks of the Amazon API Gateway REST API. If you are entirely new to this, I highly recommend checking that out first to understand some of the basic terminologies and features.
Amazon API Gateway – Introduction To Building REST APIs
Learn how to build a REST API using API Gateway. We will learn the different building blocks of REST APIs, how they connect with each other, and how you can build and configure an API in the AWS Console.
In this post, we will learn how to build a REST API using Amazon API Gateway with AWS Lambda Proxy integration built in .NET Core.
With Proxy Integration, the HTTP Request coming into the API Gateway is passed as is to the Lambda Function, and the function is responsible for interpreting the request.
You will learn:
- Build an AWS Lambda in .NET to handle Amazon API Gateway Request/Response.
- Persist data to Amazon DynamoDB and perform Create, Read, Update & Delete (CRUD) operations on the data.
- Set up and integrate with AWS Lambda from API Gateway.
Let’s first build out the Lambda function to handle Amazon API Gateway requests/responses.
📹AWS Lambda For The .NET Developer – Udemy Course
Check out my latest course on building AWS Lambda Functions using .NET.
The AWS Toolkit extension makes it easy to build AWS applications in .NET core. It’s available on multiple IDEs. You can check out the setup video, available for a free preview on mine Udemy Course here.
Create an Empty Lambda Function from the available Visual Studio templates. To interact with API Gateway Events, we need a NuGet package – Amazon.Lambda.APIGatewayEvents
public async Task<APIGatewayProxyResponse> FunctionHandler( APIGatewayProxyRequest request, ILambdaContext context) var userIdString = request.QueryStringParameters?["userId"]; if (Guid.TryParse(userIdString, out var userId)) var dynamoDbContext = new DynamoDBContext(new AmazonDynamoDBClient()); var user = await dynamoDbContext.LoadAsync<User>(userId); if (user != null) return new APIGatewayProxyResponse() StatusCode = 200, Body = JsonSerializer.Serialize(user) ; return new APIGatewayProxyResponse() StatusCode = 400, Body = "Bad Request" ;
The above function code connects to the DynamoDB User table and retrieves the User information from the table for the given user id GUID. It extracts the
userId from the API Gateway request from the query string parameters collection.
Since I have set up the AWS Credentials for my local development environment using configuration files, I don’t have to pass in any credentials explicitly. If you want to set it up for your development environment, check out my blog post on How To Manage Credentials When Building a .NET Application on AWS.
The DynamoDB context, by convention, uses the class name, in this case, user, to find the table it needs to read data. For a valid user id, it returns the User object returned from the DynamoDB table back to the caller. The function returns the
APIGatewayProxyResponse type with the details populated with the appropriate HTTP status code.
The Lambda project comes with the Mock Lambda Test tool, which helps test the Lambda function in development environments. Running the Lambda function project launches the tool and opens a browser.
It provides the UI to simulate an API Gateway Proxy request. Select the appropriate Example Requests type, API Gateway AWS Proxy, which populates the Function Input with a sample gateway request JSON object. Update the properties on the sample request and hit the Execute Function method.
You can test the lambda function with different input options and parameters using the Mock Lambda Test Tool.
With the Lambda function built and tested locally, let’s deploy it to our AWS Account. The easiest way is from the Visual Studio with the AWS Toolkit installed.
I usually set up a build-deploy pipeline in a real-world application to automate this. Check below how to use CloudFormation templates to automate build-deploy pipeline.
Let’s now use the ‘Publish To Lambda Function’ option by right-clicking on the project in Visual Studio.
Enter the function name (
user-service), and the role policies (BasicExecutionPolicy) for the Lambda function and click deploy.
Once deployed to AWS, we need to make sure the lambda function has access to talk to the appropriate DynamoDB tables. In this case, we need to explicitly add the permissions to talk to the User table in our account.
Add this by updating the Lambda IAM role automatically created when we deployed from Visual Studio.
Navigate to the Lambda Function in the AWS Console, under Configuration → Permissions, and select the Execution Role assigned to the Lambda Function.
It opens the IAM Role, where you can add additional permissions to the role.
I have added specific permissions (Read, Put, Update and Delete) for the User table. Provide only the minimum required permissions and explicitly choose the Resources that need access. This follows the Apply least-privilege permissions with IAM Policies guidelines.
With the Lambda function up and running in our AWS account, it’s time to integrate it with the AWS API Gateway integration method.
Once you create a new API Gateway REST API, add a User resource and a
GET method under that. You can follow the steps detailed in my previous post to get this setup.
To set up Lambda integration, select the Lambda function under the Integration Request. Provide the details of the region and the Lambda Function to connect to integrate.
check theUse Lambda Proxy Integration‘ option, which turns on Proxy integration for the integration.
Once you assign the integration to the Lambda function, it will automatically prompt to add permission for the Gateway to invoke the Lambda function. This is required so that API Gateway can invoke/trigger the Lambda Function whenever a request comes to this API Method.
Each method added in API Gateway needs an associated Lambda function to handle the request.
Depending on the use case and how you want to scale, you can use the same Lambda function or have a different Lambda function for each method/endpoint.
If you are unsure, you can start with one Lambda function for each resource in API Gateway and then decide to break it up further if you need to as your application grows.
To reuse the same Lambda function to handle multiple HTTP methods, we can switch the functionality in the Lambda Function based on the HTTP Method. The
HttPMethod property of the
APIGatewayProxyRequest provides this value.
The main function handler, now takes in the request and uses switch/case on the
HtppMethod to determine what action to perform. For a
POST request, it calls the
public async Task<APIGatewayProxyResponse> FunctionHandler( APIGatewayProxyRequest request, ILambdaContext context) return request.HttpMethod switch "GET" => await HandleGet(request), "POST" => await HandlePost(request), _ => new APIGatewayProxyResponse() StatusCode = 500, Body = "Unknown Request" ; private async Task<APIGatewayProxyResponse> HandlePost( APIGatewayProxyRequest request) var user = JsonSerializer.Deserialize<User>(request.Body); if (user != null) await _dynamoDbContext.SaveAsync(user); return new APIGatewayProxyResponse() StatusCode = 200, Body = "User Added" ; return new APIGatewayProxyResponse() StatusCode = 400, Body = "Bad Request" ;
HandlePost function expects the User information to be part of the HttpRequest Body in JSON format. For a valid user, it writes it to the User table in DynamoDB.
The response for all the requests is still the same
You can use the Mock Lambda Test tool to test these changes on your development environment and deploy them to the AWS Lambda function as before.
To interact and make the API callable for your users, you need to Deploy the API to a Stage.
A Stage is a logical reference to a lifecycle state of your API (for example,
Once deployed, you can use the URL for the API to test the end-end integration. Test the
POST methods on the /user resource.
But with the current setup, if we deploy the API to two stages, it will still be talking to the same backend integrations – Lambda Function and DynamoDB table. We can solve that using Stage variables and integrate with different backend services based on the stage it’s running on. I’ll cover this as part of a separate blog post.
Full source code and demo available here.
I hope this helped you to set up your Amazon API Gateway REST APIs using Lambda Functions running on .NET Core.