AWS CDK(JavaScript) + AWS Lambda(C#) をやる(AWS Lambda Function URLsで)

# 準備(詳しくないので雑に書く)
- https://engr-tie.net/posts/lambda-net6/prepare/
    - .NET6.0 SDK -> https://dotnet.microsoft.com/download
    - `dotnet new -i Amazon.Lambda.Templates`
    - `dotnet tool install -g Amazon.Lambda.Tools`
    - AWS CLI -> https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html
    - AWS CDK -> https://aws.amazon.com/cdk/

# 途中は略
なんかいい感じにcdkとlambdaを実装してください

# 要点(この記事の肝)

## Lambda(C#)部分のビルドについて

パスは適当に読み替えてください。
概要としては `dotnet lambda package` でzipファイルの生成です

```bash:build.bash
# cdkのルートディレクトリにいるものとして

# .csprojファイルのあるディレクトリへ移動
pushd path/to/CSName/src/Project

# このコマンドでビルドされて 
# path/to/CSName/src/Project/bin/Release/net6.0 フォルダへ 
# zip ファイルが生成される
dotnet lambda package 

# ルートディレクトリに戻る
popd

# さっきビルドされたファイルを適当な場所に置く。どこでもいい
cp path/to/CSName/src/Project/bin/Release/net6.0/CSName.zip ./cache/CSName.zip 
```

## CDK(JavaScript側の指定について)

パスは適当に読み替えてください。
概要としては `dotnet lambda package` で生成されたzipファイルを `Code.fromAsset` で指定することです


```javascript:cdk.js
const path = require("path")
const { aws_lambda, CfnOutput } = require('aws-cdk-lib');

      const fn_cs = new Function (this,"cs",{
        runtime: aws_lambda.Runtime.DOTNET_6, // C#だし
        // さっき cp で配置した場所(よく考えたらcpでコピーする必要ないかもなぁ……)
        code: aws_lambda.Code.fromAsset(path.join(__dirname, '../cache/CSName.zip')),
        // https://docs.aws.amazon.com/lambda/latest/dg/csharp-handler.html#csharp-handler-signatures
        // `ASSEMBLY::TYPE::METHOD` この形式。
        handler: "CSName::Project.Function::FunctionHandler",
        
        // 残りの指定は適当にどうぞ 
      })
      // AWS Lambda Function URLs やりたい人は適当に設定してください
      const furl = fn_cs.addFunctionUrl({
        authType: FunctionUrlAuthType.NONE,
      })
      // 設定されたURLを出力するため
      new CfnOutput(this,"CSUrl",{
        value: furl.url,
      });

```

## Lambda(C#)部分の実装について

公式ドキュメントは https://docs.aws.amazon.com/lambda/latest/dg/lambda-csharp.html ですが、ぶっちゃけよく分かりませんでした。

要点としては

- Handlerで指定された関数が呼ばれる
- AWS LambdaにJSONが渡されれば、それは `LambdaSerializer` が良い感じにデシリアライズして関数の第1引数に設定してくれる
- 関数の戻り値は`LambdaSerializer` が良い感じにシリアライズしてくれる
- AWS Lambda Function URLs でやる場合、POSTされた入力は、入力JSONの $.Body へ文字列として埋め込まれる

みたいなところです。

```csharp:Function.cs
using Amazon.Lambda.Core;
using System.Text.Json;

// 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 Project;

public class MyInput{
    public string Test {get;set;} = "";
}

public class MyOutput{
    public string Result {get;set;} = "";
}

public class MyLambdaFunctionInput{
    public string Body {get;set;} = "";
}


public class Function
{

    ///
    /// JSONとして単一の文字列が渡される場合のシグネチャ(引数と戻り値の型)
    /// "Hello, world!" みたいな単一文字列が直接Lambdaへ渡される場合
    /// そして単一の文字列が戻り値となる
    ///
    public string StringHandler(string input, ILambdaContext context)
    {
        return input.ToUpper()
    }

    ///
    /// 良い感じのJSONが渡される場合のシグネチャ
    /// { "Test": "Hello" } みたいな JSON が直接Lambdaへ渡される場合
    /// そして戻り値の型が良い感じに JSON になったものが戻り値となる
    ///
    public MyOutput FunctionHandler(MyInput input, ILambdaContext context)
    {
        return new MyOutput{
            Result = input.Test.ToUpper(),
        };
    }

    ///
    /// よく分からんけど何か入力のシリアライズとかを自前でやる場合
    /// よくわからん
    ///
    public Stream StreamHandler(Stream input){
        return input;
    }

    ///
    /// AWS Lambda Function URLsで受ける場合の例
    /// AWS Lambda Function URLsで呼ばれた場合
    /// 入力JSONの $.Body として入力内容が文字列として入り込むのでまずBodyをstringとして読む
    /// そのあと JSON にする
    /// この例では
    /// curl https://anywhere.lambda-url.ap-where.on.aws/ -X POST -H "Content-Type: application/json" -d '{"Test":"Hello"}'
    /// みたいな入力を想定している
    /// 
    public MyOutput LURLHandler(MyLambdaFunctionInput input, ILambdaContext context){
    
        MyInput? myInput = 
            JsonSerializer.Deserialize<MyInput>(input.Body);


        return new MyOutput{
            Result = input.Body.ToUpper(),
        };
    }
}


```

以上。