F# でAWS Lambdaのはじめかた

## Problem

[AWS Lambda が、.NET Core 2.1 ](https://docs.aws.amazon.com/lambda/latest/dg/dotnet-programming-model.html)をサポートされて、１年以上経過しました。
しかし、サポートされているのはC#だけではありません。F＃もまた同様です。
F#は.NETで実行される機能言語であり、C＃で記述されたAWS SDK for .NETなど、他の.NET言語で記述されたパッケージを使用できます。

これまでに、F#を使用したAWS Lambdaのプロジェクトを作ったことがない方にも分かるように作り方をまとめます。

## Solution

### 開発環境

#### Windowsの場合

開発環境は以下の通りです。

項目|値
---|---
IDE|Visual Studio 2019

#### Macの場合

項目|値
---|---
IDE|Visual Studio Code


### 準備

#### Windowsの場合

##### AWS Toolkit for Visual Studio のインストール

AWS Toolkit for Visual Studioをインストールしておくことで、簡単にプロジェクトを作成することができます。
[こちら](https://marketplace.visualstudio.com/items?itemName=AmazonWebServices.AWSToolkitforVisualStudio2017)からダウンロードし、インストールしましょう。

#### Macの場合

##### Amazon.Lambda.Templates のインストール

Amazon.Lambda.Templatesをインストールしておくことにより、`dotnet`コマンドで簡単にプロジェクトを作成することができます。
[こちら](https://docs.aws.amazon.com/ja_jp/lambda/latest/dg/lambda-dotnet-coreclr-deployment-package.html)からダウンロードし、インストールしましょう。
また、こちらはWindowsでも使用することができます。

### プロジェクトを作る

プロジェクトを作りましょう。

#### Windowsの場合

`Create a new project`より`AWS Lambda Project with Tests(.Net Core - F#)`を選択します。
![スクリーンショット 2019-12-20 18.02.08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/153907/06754105-102d-5b0e-1ded-e0d3ef70f60f.png)
プロジェクト名を入力後、使用するテンプレートを選択します。今回の例では`Empty Function`を選択しました。
![スクリーンショット 2019-12-20 18.06.30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/153907/0ef3f5e8-d0c9-8353-71a5-319b5f190a2b.png)

#### Macの場合

```sh
dotnet new lambda.EmptyFunction -o HelloLambda -lang f#
code ./HelloLambda -r
```

これで、プロジェクトWindow/Macのいずれかで、プロジェクトを作成することができました。
それでは、プロジェクトで作成されたファイルのいくつかを見てみましょう。

### 生成されたファイル

`Functions.fs`: -  Lambdaのハンドラーを定義します。

```fsharp
namespace HelloLambda


open Amazon.Lambda.Core

open System


// Assembly attribute to enable the Lambda function's JSON input to be converted into a .NET class.
[<assembly: LambdaSerializer(typeof<Amazon.Lambda.Serialization.Json.JsonSerializer>)>]
()


type Function() =
    /// <summary>
    /// A simple function that takes a string and does a ToUpper
    /// </summary>
    /// <param name="input"></param>
    /// <param name="context"></param>
    /// <returns></returns>
    member __.FunctionHandler (input: string) (_: ILambdaContext) =
        match input with
        | null -> String.Empty
        | _ -> input.ToUpper()

```

aws-lambda-tools-defaults.json –デプロイに必要な設定情報が含まれています。

```json
{
  "Information" : [
    "This file provides default values for the deployment wizard inside Visual Studio and the AWS Lambda commands added to the .NET Core CLI.",
    "To learn more about the Lambda commands with the .NET Core CLI execute the following command at the command line in the project root directory.",

    "dotnet lambda help",

    "All the command line options for the Lambda command can be specified in this file."
  ],
  "profile"     : "default",
  "region"      : "ap-northeast-1",
  "configuration" : "Release",
  "framework"     : "netcoreapp2.1",
  "function-runtime" : "dotnetcore2.1",
  "function-memory-size" : 256,
  "function-timeout"     : 30,
  "function-handler"     : "HelloLambda::HelloLambda.Function::FunctionHandler"
}
```

### 実行してみる

#### Windowsの場合

`AWS .NET Mock Lambda Test Tool (Preview)`を使用することでLambda関数の処理を確かめることができます。

![スクリーンショット 2019-12-20 18.39.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/153907/032d0724-54b4-d6da-c2a8-4c06960a9745.png)

#### Macの場合

WindowsのようなToolkitはないので、単体テストコードを使用することでLambda関数の処理を確かめることができます。
テストコードは`プロジェクトフォルダ/test/プロジェクト名.Tests/`にあります。

```fsharp
namespace HelloLambda.Tests


open Xunit
open Amazon.Lambda.TestUtilities

open HelloLambda


module FunctionTest =
    [<Fact>]
    let ``Invoke ToUpper Lambda Function``() =
        // Invoke the lambda function and confirm the string was upper cased.
        let lambdaFunction = Function()
        let context = TestLambdaContext()
        let upperCase = lambdaFunction.FunctionHandler "hello world" context

        Assert.Equal("HELLO WORLD", upperCase)

    [<EntryPoint>]
    let main _ = 0
```

```sh
cd HelloLambda/test/HelloLambda.Tests 
dotnet test
```

## Conclusion

AWS Lambdaプロジェクトを作成し、実行して検証するところまではこれでできるようになりました。
S3のPutイベントを元にサムレイル画像を生成したり、リアルタイムにストリーミングデータを処理したり...色々と試してみてください。