This is a main repository for the Serverless REST API in .NET 6 with AWS Lambda
course.
Project | Description |
---|---|
SimpleApi | Simple REST API with AWS Lambda |
MinimalLambda | Minimal API (using Controller) with AWS Lambda |
SimpleApiWithDynamoDb | Simple REST API with AWS Lambda and DynamoDB |
This is a very quick demo of how to create a serverless rest API using AWS Lambda
and .NET 6
. The project is created using the dotnet new
command and the Amazon.Lambda.Templates
NuGet package.
Install the AWS Lambda templates for .NET 6 using the following command:
dotnet new -i Amazon.Lambda.Templates
If already installed check the installed templates using the following command:
dotnet new --list
Install Amazon.Lambda.Tools Global Tools if not already installed.
dotnet tool install -g Amazon.Lambda.Tools
If already installed check if new version is available.
dotnet tool update -g Amazon.Lambda.Tools
Template Name | Short Name | Language | Tags |
---|---|---|---|
Lambda Empty Serverless | serverless.EmptyServerless | [C#],F# | AWS/Lambda/Serverless |
We will create a new project using the serverless.EmptyServerless
template.
dotnet new serverless.EmptyServerless --name SimpleApi --output dotnet-rest-api-with-lambda
This project's purpose is only demostrating how to create a serverless rest API using AWS Lambda
and .NET 6
.
We don't need serverless.template
file. So, we can delete it.
Now we need to configure aws-lambda-tools-defaults.json
file.
We must set function-runtime
to dotnet6
, function-memory-size
to 256
and function-timeout
to 30
.
function-handler
is the name of the class that will handle the request. In this project, we will use SimpleApi::SimpleApi.Functions::Get
as the handler.
First part is the assembly name, second part is the namespace and the class name. Last part is the method name.
We have a Get
method in Functions
class. This method will handle the request.
public APIGatewayProxyResponse Get(APIGatewayProxyRequest request, ILambdaContext context)
{
return new APIGatewayProxyResponse
{
StatusCode = 200,
Body = "Hello World!",
Headers = new Dictionary<string, string> { { "Content-Type", "text/plain" } }
};
}
Now that we have created the project, we can deploy it to AWS Lambda. Go to the project directory and run the following command:
dotnet lambda deploy-function
We need to configure the Lambda function on AWS Console.
In the Configuration
tab, we need to create a new Function URL
.
The auth type should be NONE
. Then click on Save
.
You have created a serverless rest API using AWS Lambda
and .NET 6
.
We will create a minimal API using AWS Lambda
and .NET 6
. It will be a simple API with a single MapGet method and a single controller which is a simple calculator class with four methods.
We are going to use the serverless.AspNetCoreMinimalAPI
template. You can create a new project using the following command:
dotnet new serverless.AspNetCoreMinimalAPI --name MinimalLambda --output MinimalLambda
or using the Rider IDE.
We need to configure aws-lambda-tools-defaults.json
file.
This time we will use function-handler
as MinimalLambda
. Then we can remove serverless.template
file.
In the Program.cs
file, we have a CreateHostBuilder
method. This method will create a new IHostBuilder
instance.
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddControllers();
// Add AWS Lambda support. When application is run in Lambda Kestrel is swapped out as the web server with Amazon.Lambda.AspNetCoreServer. This
// package will act as the webserver translating request and responses between the Lambda event source and ASP.NET Core.
builder.Services.AddAWSLambdaHosting(LambdaEventSource.RestApi);
var app = builder.Build();
app.UseHttpsRedirection();
app.UseAuthorization();
app.MapControllers();
app.MapGet("/", () => "Welcome to running ASP.NET Core Minimal API on AWS Lambda");
app.Run();
LambdaEventSource.RestApi
is the event source that will be used to handle the request. If we change it to LambdaEventSource.HttpApi
, we will be able to use the new HTTP API.
builder.Services.AddAWSLambdaHosting(LambdaEventSource.HttpApi);
In the Controllers folder, we have a CalculatorController.cs
file. This file contains a Calculator
class with four methods. We can use these methods to perform simple calculations.
Now that we have created the project, we can deploy it to AWS Lambda. Go to the project directory and run the following command:
dotnet lambda deploy-function
With "function-url-enable": true
in aws-lambda-tools-defaults.json
file, we can get the function URL after deploying the project.
Now we can use the function URL to access the API.
They can be accessed using the following URLs:
https://<function-url>/calculator/add/1/2
https://<function-url>/calculator/subtract/1/2
https://<function-url>/calculator/multiply/1/2
https://<function-url>/calculator/divide/1/2
With Postman
, we can send a request to these URLs and get the result.
You have created a minimal API using AWS Lambda
and .NET 6
.
We are going to create a new project with a simple API and a DynamoDB table. We will use the serverless.AspNetCoreMinimalAPI
template.
In this project we need some NuGet packages. We will use AWSSDK.DynamoDBv2
and Amazon.Lambda.AspNetCoreServer.Hosting
with FastEndpoints
, FastEndpoints.Swagger
and ValueOf
packages.
We will add a Domain
folder to the project. In this folder, we will add a User
class and a Common
folder.
In the Common
folder, we will add UserId
, FullName
, EmailAddress
and Password
classes. You can find the code for these classes in the here.
|-- Domain
|-- Common
|-- EmailAddress.cs
|-- FullName.cs
|-- Password.cs
|-- UserId.cs
|-- User.cs
We will add a Contracts
folder to the project. In this folder, we will add Data
, Requests
and Responses
folders.
In the Data
folder, we will add UserDto
class. In the Requests
folder, we will add CreateUserRequest
, DeleteUserRequest
, GetUserRequest
and UpdateUserRequest
classes.
In the Responses
folder, we will add UserResponse
,GetAllUsersResponse
and ValidationFailureResponse
classes. You can find the code for these classes in the here.
|-- Contracts
|-- Data
|-- UserDto.cs
|-- Requests
|-- CreateUserRequest.cs
|-- DeleteUserRequest.cs
|-- GetUserRequest.cs
|-- UpdateUserRequest.cs
|-- Responses
|-- GetAllUsersResponse.cs
|-- UserResponse.cs
|-- ValidationFailureResponse.cs
We will add a Mapping
folder to the project. In this folder, we will add ApiContractToDomainMapper
, DomainToApiContractMapper
, DomainToDtoMapper
and DtoToDomainMapper
classes.
You can find the code for these classes in the here.
|-- Mapping
|-- ApiContractToDomainMapper.cs
|-- DomainToApiContractMapper.cs
|-- DomainToDtoMapper.cs
|-- DtoToDomainMapper.cs
We will add a Repositories
folder to the project. In this folder, we will add IUserRepository
interface and UserRepository
class.
You can find the code for this interface and class in the here.
|-- Repositories
|-- IUserRepository.cs
|-- UserRepository.cs
We will add a Services
folder to the project. In this folder, we will add IUserService
interface and UserService
class.
You can find the code for this interface and class in the here.
|-- Services
|-- IUserService.cs
|-- UserService.cs
We will add a Endpoints
folder to the project. In this folder, we will add CreateUserEndpoint
, DeleteUserEndpoint
, GetUserEndpoint
and UpdateUserEndpoint
classes.
You can find the code for these classes in the here.
|-- Endpoints
|-- CreateUserEndpoint.cs
|-- DeleteUserEndpoint.cs
|-- GetUserEndpoint.cs
|-- UpdateUserEndpoint.cs
We will add a Summaries
folder to the project. In this folder, we will add CreateUserSummary
, DeleteUserSummary
, GetUserSummary
and UpdateUserSummary
classes.
You can find the code for these classes in the here.
|-- Summaries
|-- CreateUserSummary.cs
|-- DeleteUserSummary.cs
|-- GetUserSummary.cs
|-- UpdateUserSummary.cs
We will add a Validation
folder to the project. In this folder, we will add CreateUserRequestValidator
, UpdateUserRequestValidator
and ValidationExceptionMiddleware
classes.
You can find the code for these classes in the here.
|-- Validation
|-- CreateUserRequestValidator.cs
|-- UpdateUserRequestValidator.cs
|-- ValidationExceptionMiddleware.cs
We need to enable Lambda hosting in Program.cs
file.
builder.Services.AddAWSLambdaHosting(LambdaEventSource.HttpApi);
Now we add FastEndpoints
and swagger services.
builder.Services.AddFastEndpoints();
builder.Services.AddSwaggerDoc();
We need to configure DynamoDB in Program.cs
file. We will use AmazonDynamoDBClient
to connect to DynamoDB.
builder.Services.AddSingleton<IAmazonDynamoDB>(_ => new AmazonDynamoDBClient(RegionEndpoint.EUWest1));
We will add UserRepository
and UserService
to the services.
builder.Services.AddSingleton<IUserRepository>(provider =>
new UserRepository(provider.GetRequiredService<IAmazonDynamoDB>(),
config.GetValue<string>("Database:TableName")));
builder.Services.AddSingleton<IUserService, UserService>();
We will add ValidationExceptionMiddleware to the services.
app.UseMiddleware<ValidationExceptionMiddleware>();
app.UseFastEndpoints(x =>
{
x.ErrorResponseBuilder = (failures, _) =>
{
return new ValidationFailureResponse
{
Errors = failures.Select(y => y.ErrorMessage).ToList()
};
};
});
We will add Database:TableName
to the appsettings.json
configuration file.
{
"Database": {
"TableName": "users"
}
}
We will deploy the project to AWS Lambda using the following command.
dotnet lambda deploy-function
In AWS Console, go to DynamoDB service and create a table with the name users
. The table should have a part key with the name pk
and type String
. The table should have a sort key with the name sk
and type String
.
After creating the table, click the Actions
button and select Create access control policy
. Identity provider
should be Login with Amazon
and all permissions should be selected. Click Generate policy
button.
The generated policy will be like this:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"dynamodb:BatchGetItem",
"dynamodb:BatchWriteItem",
"dynamodb:DeleteItem",
"dynamodb:GetItem",
"dynamodb:PutItem",
"dynamodb:Query",
"dynamodb:UpdateItem"
],
"Resource": [
"arn:aws:dynamodb:eu-west-1:YOUR_ACCOUNT:table/users"
],
"Condition": {
"ForAllValues:StringEquals": {
"dynamodb:LeadingKeys": [
"${www.amazon.com:user_id}"
]
}
}
}
]
}
We don't need the Condition
part. So we will remove it. The policy will be like this:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"dynamodb:BatchGetItem",
"dynamodb:BatchWriteItem",
"dynamodb:DeleteItem",
"dynamodb:GetItem",
"dynamodb:PutItem",
"dynamodb:Query",
"dynamodb:UpdateItem"
],
"Resource": [
"arn:aws:dynamodb:eu-west-1:YOUR_ACCOUNT:table/users"
]
}
]
}
Now copy the policy. We will use it in the next step.
In AWS Console, go to Lambda service and select the function we created. In the Configuration
tab, click the Permissions
page. Click the execution role and it will open the IAM service. In the IAM service, click the Add permissions
button then click the Create inline policy
button.
Go to JSON tab and paste the policy we created in the previous step. Click Review policy
button. Give a name to the policy and click Create policy
button.
We have created a simple API with DynamoDB. You can test the API using the Postman.