API Gateway + Lambda で .NET 6 の Minimal API を実行してみる

2022.07.17

いわさです。

AWS Lambda では .NET 6 がサポートされていますが、.NET 6 では Minimal API と呼ばれる、従来とは異なるAPIの実装方法が利用出来るようになっています。

Minimal API を使うと、.NET 上で不要な依存関係などを含まない最小限の Web API を作成することが出来ます。

今回、Minimal API をターゲットにした API Gateway を作成する機会がありましたので、構築の流れをご紹介します。

Minimal API の作成

dotnet new webコマンドで作成されるものは最小限の Minimal API となっています。
本日はこちらを利用します。

% dotnet new web
テンプレート "ASP.NET Core Empty" が正常に作成されました。

作成後の操作を処理しています...
/Users/iwasa.takahito/work/hoge0717dotnet2/hoge0717dotnet2.csproj で ' dotnet restore ' を実行しています...
  Determining projects to restore...
  Restored /Users/iwasa.takahito/work/hoge0717dotnet2/hoge0717dotnet2.csproj (in 97 ms).
正常に復元されました。

従来のようなStartup.csやコントローラーは存在せず、以下のように Program.cs にスタートアップ処理やルーティング設定が実装されています。
ここではハイライト部分を少しだけ修正していますが、ほぼデフォルト状態です。

Program.cs

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

app.MapGet("/", () => "hoge");
app.MapGet("/hoge1", () => "hoge1");
app.MapGet("/hoge2", () => "hoge2");

app.Run();

Lambda 用に最適化する

次に、Lambda で実行出来るようにコードを少し修正します。

今までもAWSから提供されている、Amazon.Lambda.AspNetCoreServerを NuGet パッケージで導入することで、ASP.NET Core アプリケーションを Lambda 関数として実行することが出来ました。
今回の Minimal API でもこちらを使います。

このパッケージを導入すると、非 Lambda 関数向けに実装されている ASP.NET Core アプリケーションを Lambda 関数として実行することが出来ます。
しくみとしては、Amazon.Lambda.AspNetCoreServerが API Gateway あるいは Application Load Balancer からのリクエストをネイティブな ASP.NET Core 用に変換し、レスポンスも同じように変換してくれます。そしてローカルで開発中は Kestrel で普通に動きます。最高に便利。

Amazon.Lambda.AspNetCoreServer.Hosting 追加

まずは、Amazon.Lambda.AspNetCoreServer.Hostingをプロジェクトに追加します。

% dotnet add package Amazon.Lambda.AspNetCoreServer.Hosting --version 1.3.1
  Determining projects to restore...
  Writing /var/folders/4d/nhd1bp3d161crsn900wjrprm0000gp/T/tmpMiFDFC.tmp
:
info : Committing restore...
info : Writing assets file to disk. Path: /Users/iwasa.takahito/work/hoge0717dotnet/obj/project.assets.json
log  : Restored /Users/iwasa.takahito/work/hoge0717dotnet/hoge0717dotnet.csproj (in 7.63 sec).

サービスの追加

AddAWSLambdaHostingメソッドを使ってサービスを追加します。
その際に、Lambda 関数のイベントソースを指定します。(RestApi/HttpApi/ApplicationLoadBalancer)

Program.cs

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddAWSLambdaHosting(LambdaEventSource.RestApi);
var app = builder.Build();      

app.MapGet("/", () => "hoge");
app.MapGet("/hoge1", () => "hoge1");
app.MapGet("/hoge2", () => "hoge2");

app.Run();

Lambda用にバンドル

あとは Lambda用にモジュールをバンドルします。 今回は zipパッケージ化して Lambdaコンソールからアップロードします。

% dotnet publish -c Release --sc false -r linux-x64                                 
.NET 向け Microsoft (R) Build Engine バージョン 17.0.0+c9eb9dd64
Copyright (C) Microsoft Corporation.All rights reserved.

  Determining projects to restore...
  All projects are up-to-date for restore.
  hoge0717dotnet -> /Users/iwasa.takahito/work/hoge0717dotnet/bin/Release/net6.0/linux-x64/hoge0717dotnet.dll
  hoge0717dotnet -> /Users/iwasa.takahito/work/hoge0717dotnet/bin/Release/net6.0/linux-x64/publish/

% cd /Users/iwasa.takahito/work/hoge0717dotnet/bin/Release/net6.0/linux-x64/publish/

% zip -r hoge0717dotnet.zip .                                                       
updating: Amazon.Lambda.APIGatewayEvents.dll (deflated 53%)
updating: Amazon.Lambda.RuntimeSupport.dll (deflated 62%)
:
updating: hoge0717dotnet.deps.json (deflated 78%)
updating: Amazon.Lambda.AspNetCoreServer.dll (deflated 56%)

デプロイ先の Lambda を作成しデプロイパッケージをアップロード

Lambda 関数を作成します。
ランタイムは.NET 6 (C#/PowerShell)で、dotnet publishした際のアーキテクチャーにあわせるようにしましょう。

先程作成した zipパッケージをアップロードします。

最後に、ランタイム設定を編集しハンドラを設定します。
ここでは .NET モジュール名を設定します。

API Gateway と統合し、実行

Lambda関数の準備は完了しました。
あとは、API Gateway を統合して実行してみましょう。

先程のサービスパラメータにあわせて、REST APIを作成し、バックエンドに Lambda 関数を統合させます。
ここでは、Lambda プロキシ統合を有効化しています。

minimal API で設定したルートをリソース作成していきます。

ステージへデプロイ出来たら、HTTPクライアントを使ってリクエストを送信してみます。

% curl https://dx7a2kpxch.execute-api.ap-northeast-1.amazonaws.com/prd
hoge
% curl https://dx7a2kpxch.execute-api.ap-northeast-1.amazonaws.com/prd/hoge1
hoge1
% curl https://dx7a2kpxch.execute-api.ap-northeast-1.amazonaws.com/prd/hoge2
hoge2

おお、いけました。

さいごに

本日は、API Gateway + Lambda で .NET 6 の Minimal API を実行してみました。

今回は、もともと Lambda 用に構築されていなかった Minimal API を Lambda 化する流れを理解したかったので、標準テンプレートから新規作成し手動でモジュールアップロードをしました。
Lambda が最初からターゲットであれば AWS から .NET 用にAmazon.Lambda.Templatesというものが提供されていて、Minimal API のテンプレートも既に提供されています。

% dotnet new -i Amazon.Lambda.Templates
次のパッケージがインストールされます:
   Amazon.Lambda.Templates

成功: Amazon.Lambda.Templates::6.2.0により次のテンプレートがインストールされました。
テンプレート名                                               短い名前                                          言語       タグ                   
----------------------------------------------------  --------------------------------------------  -------  ---------------------
Empty Top-level Function                              lambda.EmptyTopLevelFunction                  [C#]     AWS/Lambda/Serverless
Lambda Annotations Framework (Preview)                serverless.Annotations                        [C#]     AWS/Lambda/Serverless
Lambda ASP.NET Core Minimal API                       serverless.AspNetCoreMinimalAPI               [C#]     AWS/Lambda/Serverless
Lambda ASP.NET Core Web API                           serverless.AspNetCoreWebAPI                   [C#],F#  AWS/Lambda/Serverless
:

こちらでは、インフラテンプレートなども含まれており、本エントリで実装したパッケージや追加コードなども含まれているのでそちらもぜひ利用してみてください。