[AWS]SAMでTypeScriptがサポートされたので5分でAPIを作成する

1年前にはTypeScriptサポートされていなかったので無理矢理使っていました。
Template.yamlのCodeUriをTypeScriptのビルド先のJavaScriptを指定するって感じでね。。他いろいろ工夫していました。

久々にSAMを触ってみるとネイティブサポートされていたのでサクッと立ち上げてみます。

以下参考です(てかまんまかも)。(最後にVSCode DevContainer含めたGit公開するので許してね)

https://dev.classmethod.jp/articles/typescript-native-support-in-the-aws-sam-cli/

https://aws.amazon.com/jp/about-aws/whats-new/2022/02/typescript-native-support-aws-serverless-application-model-cli-esbuild-public-preview/

# 環境

* Ubuntu-22.04 (WSL2)
* Docker(20.10.21)
* nodejs(16.9.1)
* npm(7.21.1)
* エディタ
    * [VSCode](https://azure.microsoft.com/ja-jp/products/visual-studio-code/)

# 準備 (5分間に含みません)

以下をインストールします。(インストール済みの方はスキップでOK)

<details><summary>Docker インストール</summary>

https://docs.docker.jp/desktop/install.html

上記参考にインストール

```bash
docker --version
Docker version 20.10.21, build baeda1f
```
</details>

<details><summary>AWS CLI インストール</summary>

https://docs.aws.amazon.com/ja_jp/cli/latest/userguide/getting-started-install.html

```bash
curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip"
unzip awscliv2.zip
sudo ./aws/install
```

以下のように表示されればOK(2022/12/05時点の最新版はこれ)

```bash
/usr/local/bin/aws --version aws-cli/2.9.4 Python/3.9.11 Linux/5.15.74.2-microsoft-standard-WSL2 exe/x86_64.ubuntu.22 prompt/off
```

Path通ってればこっちでOK

```bash
aws --version aws-cli/2.9.4 Python/3.9.11 Linux/5.15.74.2-microsoft-standard-WSL2 exe/x86_64.ubuntu.22 prompt/off
```
</details>

<details><summary>SAM CLI インストール</summary>

https://docs.aws.amazon.com/ja_jp/serverless-application-model/latest/developerguide/serverless-sam-cli-install.html

```bash
wget https://github.com/aws/aws-sam-cli/releases/latest/download/aws-sam-cli-linux-x86_64.zip
unzip aws-sam-cli-linux-x86_64.zip -d sam-installation
sudo ./sam-installation/install
```

```bash
sam --version
SAM CLI, version 1.66.0
```
</details>

# SAM プロジェクト作成

```bash
$ sam init

You can preselect a particular runtime or package type when using the `sam init` experience.
Call `sam init --help` to learn more.

Which template source would you like to use?
        1 - AWS Quick Start Templates
        2 - Custom Template Location
Choice: 1

Choose an AWS Quick Start application template
        1 - Hello World Example
        2 - Multi-step workflow
        3 - Serverless API
        4 - Scheduled task
        5 - Standalone function
        6 - Data processing
        7 - Infrastructure event management
        8 - Serverless Connector Hello World Example
        9 - Multi-step workflow with Connectors
        10 - Lambda EFS example
        11 - Machine Learning
Template: 1

Use the most popular runtime and package type? (Python and zip) [y/N]:

Which runtime would you like to use?
        1 - aot.dotnet7 (provided.al2)
        2 - dotnet6
        3 - dotnet5.0
        4 - dotnetcore3.1
        5 - go1.x
        6 - go (provided.al2)
        7 - graalvm.java11 (provided.al2)
        8 - graalvm.java17 (provided.al2)
        9 - java11
        10 - java8.al2
        11 - java8
        12 - nodejs18.x
        13 - nodejs16.x
        14 - nodejs14.x
        15 - nodejs12.x
        16 - python3.9
        17 - python3.8
        18 - python3.7
        19 - ruby2.7
        20 - rust (provided.al2)
Runtime: 13

What package type would you like to use?
        1 - Zip
        2 - Image
Package type: 1

Based on your selections, the only dependency manager available is npm.
We will proceed copying the template using npm.

Select your starter template
        1 - Hello World Example
        2 - Hello World Example TypeScript
        3 - Hello World Example TypeScript w/ Lambda Powertools
Template: 2

Would you like to enable X-Ray tracing on the function(s) in your application?  [y/N]:

Project name [sam-app]:

Cloning from https://github.com/aws/aws-sam-cli-app-templates (process may take a moment)

    -----------------------
    Generating application:
    -----------------------
    Name: sam-app
    Runtime: nodejs16.x
    Architectures: x86_64
    Dependency Manager: npm
    Application Template: hello-world-typescript
    Output Directory: .

    Next steps can be found in the README file at ./sam-app/README.md


    Commands you can use next
    =========================
    [*] Create pipeline: cd sam-app && sam pipeline init --bootstrap
    [*] Validate SAM template: cd sam-app && sam validate
    [*] Test Function in the Cloud: cd sam-app && sam sync --stack-name {stack-name} --watch
```

生成されたディレクトリに移動して確認します。

```bash
$ cd sam-app/
$ tree -a
.
├── events
│   └── event.json
├── .gitignore
├── hello-world
│   ├── app.ts
│   ├── .eslintignore
│   ├── .eslintrc.js
│   ├── jest.config.ts
│   ├── .npmignore
│   ├── package.json
│   ├── .prettierrc.js
│   ├── tests
│   │   └── unit
│   │       └── test-handler.test.ts
│   └── tsconfig.json
├── README.md
└── template.yaml

4 directories, 13 files
```

# ビルド

hello-world ディレクトリでnpm installします。

```bash
$ cd hello-world
$ npm install
```

プロジェクトTOPに戻ってsam buildします。

```bash
$ cd ..
$ sam build

        SAM CLI now collects telemetry to better understand customer needs.

        You can OPT OUT and disable telemetry collection by setting the
        environment variable SAM_CLI_TELEMETRY=0 in your shell.
        Thanks for your help!

        Learn More: https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-telemetry.html

Your template contains a resource with logical ID "ServerlessRestApi", which is a reserved logical ID in AWS SAM. It could result in unexpected behaviors and is not recommended.
Building codeuri: /home/user/sam-app/hello-world runtime: nodejs16.x metadata: {'BuildMethod': 'esbuild', 'BuildProperties': {'Minify': True, 'Target': 'es2020', 'EntryPoints': ['app.ts']}} architecture: x86_64 functions: HelloWorldFunction
Running NodejsNpmEsbuildBuilder:CopySource
Running NodejsNpmEsbuildBuilder:NpmInstall
Running NodejsNpmEsbuildBuilder:EsbuildBundle

Build Succeeded

Built Artifacts  : .aws-sam/build
Built Template   : .aws-sam/build/template.yaml

Commands you can use next
=========================
[*] Validate SAM template: sam validate
[*] Invoke Function: sam local invoke
[*] Test Function in the Cloud: sam sync --stack-name {{stack-name}} --watch
[*] Deploy: sam deploy --guided
```

# デプロイ

```bash
$ sam deploy --guided

Configuring SAM deploy
======================

        Looking for config file [samconfig.toml] :  Not found

        Setting default arguments for 'sam deploy'
        =========================================
        Stack Name [sam-app]: 
        AWS Region [ap-northeast-1]: 
        #Shows you resources changes to be deployed and require a 'Y' to initiate deploy
        Confirm changes before deploy [y/N]: y
        #SAM needs permission to be able to create roles to connect to the resources in your template
        Allow SAM CLI IAM role creation [Y/n]: 
        #Preserves the state of previously provisioned resources when an operation fails
        Disable rollback [y/N]: 
        HelloWorldFunction may not have authorization defined, Is this okay? [y/N]: y
        Save arguments to configuration file [Y/n]: 
        SAM configuration file [samconfig.toml]: 
        SAM configuration environment [default]: 

        Looking for resources needed for deployment:
         Managed S3 bucket: aws-sam-cli-managed-default-samclisourcebucket-xxxxxxx
         A different default S3 bucket can be set in samconfig.toml

        Saved arguments to config file
        Running 'sam deploy' for future deployments will use the parameters saved above.
        The above parameters can be changed by modifying samconfig.toml
        Learn more about samconfig.toml syntax at 
        https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-config.html

Uploading to sam-app/xxxxxxxxxxxxx  543 / 543  (100.00%)

        Deploying with following values
        ===============================
        Stack name                   : sam-app
        Region                       : ap-northeast-1
        Confirm changeset            : True
        Disable rollback             : False
        Deployment s3 bucket         : aws-sam-cli-managed-default-samclisourcebucket-xxxxxxxxxx
        Capabilities                 : ["CAPABILITY_IAM"]
        Parameter overrides          : {}
        Signing Profiles             : {}

Initiating deployment
=====================
Uploading to sam-app/xxxxxxxxxxxxx.template  1332 / 1332  (100.00%)

Waiting for changeset to be created..
CloudFormation stack changeset
---------------------------------------------------------------------------------------------------------
Operation                  LogicalResourceId          ResourceType               Replacement              
---------------------------------------------------------------------------------------------------------
+ Add                      HelloWorldFunctionHelloW   AWS::Lambda::Permission    N/A                      
                           orldPermissionProd                                                             
+ Add                      HelloWorldFunctionRole     AWS::IAM::Role             N/A                      
+ Add                      HelloWorldFunction         AWS::Lambda::Function      N/A                      
+ Add                      ServerlessRestApiDeploym   AWS::ApiGateway::Deploym   N/A                      
                           ent47fc2d5f9d              ent                                                 
+ Add                      ServerlessRestApiProdSta   AWS::ApiGateway::Stage     N/A                      
                           ge                                                                             
+ Add                      ServerlessRestApi          AWS::ApiGateway::RestApi   N/A                      
---------------------------------------------------------------------------------------------------------

Changeset created successfully. arn:aws:cloudformation:ap-northeast-1:xxxxxxx:changeSet/samcli-deployxxxx/xxxxx-38c1-xxxxxxxx-893e-xxx


Previewing CloudFormation changeset before deployment
======================================================
Deploy this changeset? [y/N]: y

2022-12-05 23:03:59 - Waiting for stack create/update to complete

CloudFormation events from stack operations (refresh every 0.5 seconds)
---------------------------------------------------------------------------------------------------------
ResourceStatus             ResourceType               LogicalResourceId          ResourceStatusReason     
---------------------------------------------------------------------------------------------------------
CREATE_IN_PROGRESS         AWS::CloudFormation::Sta   sam-app                    User Initiated           
                           ck                                                                             
CREATE_IN_PROGRESS         AWS::IAM::Role             HelloWorldFunctionRole     -                        
CREATE_IN_PROGRESS         AWS::IAM::Role             HelloWorldFunctionRole     Resource creation        
                                                                                 Initiated                
CREATE_COMPLETE            AWS::IAM::Role             HelloWorldFunctionRole     -                        
CREATE_IN_PROGRESS         AWS::Lambda::Function      HelloWorldFunction         -                        
CREATE_IN_PROGRESS         AWS::Lambda::Function      HelloWorldFunction         Resource creation        
                                                                                 Initiated                
CREATE_COMPLETE            AWS::Lambda::Function      HelloWorldFunction         -                        
CREATE_IN_PROGRESS         AWS::ApiGateway::RestApi   ServerlessRestApi          -                        
CREATE_IN_PROGRESS         AWS::ApiGateway::RestApi   ServerlessRestApi          Resource creation        
                                                                                 Initiated                
CREATE_COMPLETE            AWS::ApiGateway::RestApi   ServerlessRestApi          -                        
CREATE_IN_PROGRESS         AWS::ApiGateway::Deploym   ServerlessRestApiDeploym   -                        
                           ent                        ent47fc2d5f9d                                       
CREATE_IN_PROGRESS         AWS::Lambda::Permission    HelloWorldFunctionHelloW   -                        
                                                      orldPermissionProd                                  
CREATE_IN_PROGRESS         AWS::Lambda::Permission    HelloWorldFunctionHelloW   Resource creation        
                                                      orldPermissionProd         Initiated                
CREATE_IN_PROGRESS         AWS::ApiGateway::Deploym   ServerlessRestApiDeploym   Resource creation        
                           ent                        ent47fc2d5f9d              Initiated                
CREATE_COMPLETE            AWS::ApiGateway::Deploym   ServerlessRestApiDeploym   -                        
                           ent                        ent47fc2d5f9d                                       
CREATE_IN_PROGRESS         AWS::ApiGateway::Stage     ServerlessRestApiProdSta   -                        
                                                      ge                                                  
CREATE_IN_PROGRESS         AWS::ApiGateway::Stage     ServerlessRestApiProdSta   Resource creation        
                                                      ge                         Initiated                
CREATE_COMPLETE            AWS::ApiGateway::Stage     ServerlessRestApiProdSta   -                        
                                                      ge                                                  
CREATE_COMPLETE            AWS::Lambda::Permission    HelloWorldFunctionHelloW   -                        
                                                      orldPermissionProd                                  
CREATE_COMPLETE            AWS::CloudFormation::Sta   sam-app                    -                        
                           ck                                                                             
---------------------------------------------------------------------------------------------------------
CloudFormation outputs from deployed stack
-----------------------------------------------------------------------------------------------------------
Outputs                                                                                                   
-----------------------------------------------------------------------------------------------------------
Key                 HelloWorldFunctionIamRole                                                             
Description         Implicit IAM Role created for Hello World function                                    
Value               arn:aws:iam::xxxxxxxxxxxx:role/sam-app-HelloWorldFunctionRole-xxxxxx            

Key                 HelloWorldApi                                                                         
Description         API Gateway endpoint URL for Prod stage for Hello World function                      
Value               https://xxxxxxxxxx.execute-api.ap-northeast-1.amazonaws.com/Prod/hello/               

Key                 HelloWorldFunction                                                                    
Description         Hello World Lambda Function ARN                                                       
Value               arn:aws:lambda:ap-northeast-1:xxxxxxxxxxx:function:sam-app-HelloWorldFunction-       
xxxxxxxxxxxx                                                                                              
-----------------------------------------------------------------------------------------------------------

Successfully created/updated stack - sam-app in ap-northeast-1
```

初回はguidedオプション付けると便利です。
以降は`sam deploy`(オプションなし)でOKです。
初回で設定した内容がsamconfig.tomlに記載され参照されます。


# 確認

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/86605/d83c86e7-4229-5362-23ca-169b28c6a6f3.png)

ServerlessRestApiのリンクから「ステージ」からURLが確認できます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/86605/01e85f82-ecd1-33a7-2891-298097a87eb9.png)

遷移するとhello worldが表示されます。

```bash
{"message":"hello world"}
```

# お片付け

```bash
$ aws cloudformation delete-stack --stack-name sam-app
```

これでデプロイしたリソースが全て削除されます。

# おまけ

https://github.com/hf7777hi/sam-helloworld-for-typescript

今回のHelloWorldを含めた、VSCodeのDevContainer環境(NodeJS 16)を用意しました。
Dockerさえあれば即開発に移れます。