はなちるのマイノート

Unityをメインとした技術ブログ。自分らしくまったりやっていきたいと思いますー!

【C#】C#でAWS Lambda & API Gatewayを使ってWebAPIを作る(Windows)

はじめに

最近知ったのですが,AWS LambdaC#に対応しているらしいです。C#大好きっ子としては触らなきゃということで簡単なWebAPIを作ってみました。

AWS Lambda はサーバーレスコンピューティングサービスで、サーバーのプロビジョニングや管理、ワークロード対応のクラスタースケーリングロジックの作成、イベント統合の維持、ランタイムの管理を行わずにコードを実行できます。Lambda を使用すれば、実質どのようなタイプのアプリケーションやバックエンドサービスでも管理を必要とせずに実行できます。

AWS Lambda(イベント発生時にコードを実行)| AWS

一応AWS Lambdaの冒頭の説明文を載せときます。

では早速やっていきましょう。

AWS Toolkit for Visual Studioをインストールする

お手元のVisual StudioAWS Toolkit for Visual Studioをインストールすれば、コーディング&デプロイまでをVisual Studioで行うことができます。

AWS Toolkit for Visual Studio は、Microsoft Windows で実行される Microsoft Visual Studio の拡張機能です。開発者は、アマゾン ウェブ サービスを使用する .NET アプリケーションの開発、デバッグ、デプロイが容易にできるようになります。AWS Toolkit for Visual Studio を使用すると、AWS アプリケーションの構築をより迅速に開始でき、生産性が向上します。

aws.amazon.com

まずはVisual Studioを起動してください。(私の場合はVisual Studio 2019)

とりあえずコードなしで続行を押し、上のツールバーから、拡張機能 -> 拡張機能の管理を選択します。

f:id:hanaaaaaachiru:20210518180606p:plain
コードなしで続行
f:id:hanaaaaaachiru:20210518180741p:plain
拡張機能のウィンドウの開き方
f:id:hanaaaaaachiru:20210518181104p:plain
AWS Toolkitをダウンロード

あとは再起動すればOKです。

補足

AWS Toolkit for Visual StudioはどうやらVisual Studio for Macでは動作しないようです。(2021/05/18時)

aws.amazon.com

ですので、Visual Studio Code用のAWS Toolkit for Visual Studio Codeを代わりに使うことが多いようです。

docs.aws.amazon.com

f:id:hanaaaaaachiru:20210517231538p:plain
拡張機能を追加する

プロジェクトを作成する

Visual Studioを立ち上げ、新しいプロジェクトを作成を選択すると、AWS Lambda Project (.NET Core - C#)が追加されているはずですので選択します。

f:id:hanaaaaaachiru:20210519141211p:plain
AWS Lambda Projectを作成

どのテンプレート利用してを作成するか聞かれる(Select Blueprint)ので、今回は最小構成であるEmpty Functionを選択しました。

f:id:hanaaaaaachiru:20210519141531p:plain
ブループリント選択

無事にプロジェクトが作成されると、以下の構成でファイルが生成されます。

f:id:hanaaaaaachiru:20210519141756p:plain
作成されたプロジェクト
.Project
 |---- Properties
 |   └ launchSettings.json
 |--- Function.cs
 |--- aws-lambda-tools-defaults.json
 --- readme.md

※ 厳密には他のファイルも生成されいますが、VisualStudioのソリューションエクスプローラーで確認できるものを掲載

自身のAWSのアカウントのアクセスキーを確認する

自分のAWSアカウントにログインを行い、マイセキュリティ資格情報という欄からアクセスキーとシークレットアクセスキーを取得します。

https://docs.aws.amazon.com/

f:id:hanaaaaaachiru:20210517233255p:plain
アクセスキーとシークレットキー

私の場合はまだ作成していなかったので、新しいアクセスキーを作成を押し、作成された2つの文字列をメモしておいてください。

VisualStudioとAWSのアカウントを紐づける

取得したアクセスキーを用いて、Visual Studioを自身のAWSと紐づけます。

VisualStudioにて表示 -> AWS Explorerを選択し、AWS Explorerを開いてください。

f:id:hanaaaaaachiru:20210519143349p:plain
AWS Explorer

無事に開けると以下の画像のような表示になると思うので、人の右上にプラスマークが書かれているボタンを押してユーザーの追加を行います。

f:id:hanaaaaaachiru:20210519143552p:plain
ユーザーの追加

先程取得しアクセスキーとシークレットアクセスキーを利用して、項目を埋めOKを押せばユーザーの追加は完了です。

ちなみにProfile Nameはお好きな名前で、Regionは東京がいいでしょう。

f:id:hanaaaaaachiru:20210519144308p:plain
ユーザー追加

無事に自身のAWSアカウントに接続できればAWS Explorerに色々な情報が追加されているはずです。

f:id:hanaaaaaachiru:20210519144511p:plain
無事ユーザー追加ができた場合

コードを記述してみる

生成されたファイルで一番重要なのがFunction.csです。ここに実行したいコードを記述していきます。

デフォルトでは以下のコードが生成されているはずです。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

using Amazon.Lambda.Core;

// Assembly attribute to enable the Lambda function's JSON input to be converted into a .NET class.
[assembly: LambdaSerializer(typeof(Amazon.Lambda.Serialization.SystemTextJson.DefaultLambdaJsonSerializer))]
namespace AWSLambdaTest
{
    public class Function
    {        
        /// <summary>
        /// A simple function that takes a string and does a ToUpper
        /// </summary>
        /// <param name="input"></param>
        /// <param name="context"></param>
        /// <returns></returns>
        public string FunctionHandler(string input, ILambdaContext context)
        {
            return input?.ToUpper();
        }
    }
}


初めてのコーディングはやっぱりHello, Worldだろうということで、とりあえずHello, Worldを返す関数を作成しました。

using Amazon.Lambda.Core;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Net;
using System.Text.Json;

[assembly: LambdaSerializer(typeof(Amazon.Lambda.Serialization.Json.JsonSerializer))]
namespace AWSLambdaTest
{
    public class Function
    {
        public LambdaResponse FunctionHandler(object input, ILambdaContext context)
        {
            var body = new Dictionary<string, string>() {
                { "message", "Hello, World" },
            };

            var response = new LambdaResponse()
            {
                isBase64Encoded = false,
                statusCode = HttpStatusCode.OK,
                headers = new Dictionary<string, string>()
                {
                    {"my_header", "my_value" }
                },
                body = JsonConvert.SerializeObject(body),
            };

            return response;
        }

        public class LambdaResponse
        {
            [JsonProperty(PropertyName = "isBase64Encoded")]
            public bool isBase64Encoded;

            [JsonProperty(PropertyName = "statusCode")]
            public HttpStatusCode statusCode;

            [JsonProperty(PropertyName = "headers")]
            public Dictionary<string, string> headers;

            [JsonProperty(PropertyName = "body")]
            public string body;
        }
    }
}

コードの書き方については以下の公式サイトを参照するのが確実です。
docs.aws.amazon.com

また今回書いたコードはNewtonsoft.JsonAmazon.Lambda.Serialization.Jsonというライブラリへの依存があるので、ツール -> NuGetパッケージマネージャー -> ソリューションのNuGetパッケージ管理により2つをインストールしてください。

f:id:hanaaaaaachiru:20210519175441p:plain
ライブラリのインストール

また単純にAWS Lambdaのコードを作るだけならもっと簡単にできるのですが、AWS Gatewayを使ってWebAPI化するには返り値の細かい仕様があります。(最初これに気付かずかなり苦戦しました。。。)

API ゲートウェイでの「不正な Lambda プロキシ応答」または 502 エラーの解決

{
    "isBase64Encoded": true|false,
    "statusCode": httpStatusCode,
    "headers": { "headerName": "headerValue", ... },
    "body": "..."
}

コードをデプロイする

記述したコードをAWSにデプロイしてみましょう。

右側に表示されているソリューションエクスプローラーからプロジェクトを選択・右クリックし、Publish to AWS Lambda ...をクリック。

f:id:hanaaaaaachiru:20210519145042p:plain
Publish to AWS Lambda

すると色々と情報を聞かれるので、それぞれ入力を行ってください。

f:id:hanaaaaaachiru:20210519145538p:plain
入力項目1

一番上にあるRole Nameが曲者で、Lambda 機能を使用するために必要なアクセス許可を設定するみたいです。
AWS Lambda 実行ロール - AWS Lambda

正直なところどれを選べばいいかよく分からなかったのですが、とりあえずデフォルトっぽいAWS Lambda Roleを選択しました。

あとはメモリ・タイムアウトをそれぞれ128, 10sに設定してみて、Uplodeを実行。

f:id:hanaaaaaachiru:20210519150414p:plain
入力項目2

デプロイした関数のテストを行う

アップロードが完了すると、Visual StudioでAWS上にある関数のテストが行えるようになります。

f:id:hanaaaaaachiru:20210519154148p:plain
テストツール

今回作成したメソッドの引数はなくても動くので、実行ボタンを押せばHello, Worldが表示されているはずです。

AWS上で関数のテストをする

一応AWS Console上での関数のテストのやり方を紹介しておきます。

AWS Lambdaの管理画面を開くと、先程作成した関数が表示されているはずです。(リージョンを間違えないように)

aws.amazon.com

f:id:hanaaaaaachiru:20210519154727p:plain
関数の確認

関数名をクリックした後、テストというタグを押します。

f:id:hanaaaaaachiru:20210519154913p:plain
関数のテスト

後はVisualStudioで行ったようにテストを実行します。

f:id:hanaaaaaachiru:20210519155415p:plain
テスト実行
f:id:hanaaaaaachiru:20210519155445p:plain
結果

WebAPI化する

結構長期戦になってきましたが、あとWeb API化すれば完成です。もう少し頑張りましょう。

APIを作成するにはAmazon API Gatewayを利用します。

aws.amazon.com

ただAWS Lambdaの関数の画面から簡単に設定できるので身構える必要はありません。

テストをしていた画面の上にスクロールするとトリガーの追加というボタンがあるはずです。

f:id:hanaaaaaachiru:20210519155927p:plain
トリガーの追加

クリックすると以下の画面がでるはずなので、API Gatewayを選択します。

f:id:hanaaaaaachiru:20210519160128p:plain
トリガーの追加

すると詳細の入力画面が出てくるので、以下の画像を参考にしながら追加してください。

f:id:hanaaaaaachiru:20210519160341p:plain
トリガーの設定

テストしてみる

おそらくこれまでの操作がうまくいっていればそのままAPI エンドポイントのリンクを踏めば動くはずですが、一応テストをしておきましょう。

自分でAWS Gatewayの管理画面を開いてください。一応以下の画像の赤く囲われたところを押せば管理画面に遷移することができます。

f:id:hanaaaaaachiru:20210519163050p:plain
AWS Gatewayの管理画面に遷移

すると以下のような画面になるはずですので、テストをクリック。

f:id:hanaaaaaachiru:20210519180438p:plain
テストをしてみる

今までの手順で作成したらRest APIの全てのメソッドに対して処理を走らせる(設定から変えられます)ようになっているのですが、今回書いたコードはGETメソッドでも正しく動作するのでGETで確かめてみます。

f:id:hanaaaaaachiru:20210519180843p:plain
テストを実行する

実験してみる

最後に、実際にURLをたたいて確かめてみましょう。URLはAWS Lambdaのトリガーの詳細のところに書いてあります。

f:id:hanaaaaaachiru:20210519181114p:plain
APIエンドポイントの場所

実行してみると....。

f:id:hanaaaaaachiru:20210519181311p:plain
出力

さいごに

10000文字ぐらいある想像以上に長い記事になってしまって、書いている私自身へとへとになってきてしまいました。無事にここまでできた方はお疲れ様です。

途中でも少し書いたのですが、コードの返り値に仕様があったのを完全に見落としていて502エラーが永遠に出てきて大変でした。

ただ一度やり方を覚えてしまえばBodyの中身を書き換えるだけなので、なんでもできちゃいます。無敵です。

良かったらうまく活用してみてください。

ではまた。