0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

LTS Group(エル・ティー・エス グループ)Advent Calendar 2024

Day 22

AWS SAM を使ったサーバレスアプリケーション初体験

Last updated at Posted at 2024-12-21

概要

10月にDVAを取得し、11月にSAPを取得したのですが、知識を詰め込んだだけでサービス自体にはあまり触れていなかったので、この機会に試験で出題されたAWS SAMを触ってみました。この記事では、AWS SAM を使って簡単なサーバレスアプリケーションを構築する方法を解説します。このアプリケーションでは DynamoDB を利用してタスクを管理し、Lambda 関数を通じてタスクの作成、取得、完了といった操作を行います。構築からデプロイ、ローカルテスト、リソース削除までの手順をカバーします。


1. 開発環境の準備

AWS SAM を使ったサーバレスアプリケーションを構築するには、以下が必要です。

必要なツール

  • AWS CLI: AWS サービスとやり取りするために必要です。
  • SAM CLI: サーバレスアプリケーションの管理ツール。
  • Docker: SAM CLI のローカルテストに必要。
  • Postman または curl などの API テストツール。

インストール確認

以下のコマンドを実行してインストールされているか確認してください。

aws --version
sam --version
docker --version

Docker 起動

Docker をインストールした後、サービスを起動しておきます。


2. プロジェクトの作成

SAM CLI を使ったプロジェクト作成

以下のコマンドでプロジェクトを作成します。

sam init

プロンプトに従って以下の設定を選択します。
今回はAWS Quick Start Templatesから進めていきます。また、本格的な開発というわけではないのでX-rayやCloudWatch Application Insightsは無効で設定をしています。

  1. テンプレートの選択: Hello World Example
  2. ランタイム: Python 3.11
    (存在しなければ後述するtemplate.yamlで指定できるのであまり気にしないでください。)
  3. プロジェクト名: task-app

作成後のディレクトリ構造は以下のようになります。

task-app/
│  .gitignore
│  README.md
│  samconfig.toml
│  template.yaml
│  __init__.py
│
├─events
│      event.json
│
├─hello_world
│      app.py
│      requirements.txt
│      __init__.py
│
└─tests
    │  requirements.txt
    │  __init__.py
    │
    ├─integration
    │      test_api_gateway.py
    │      __init__.py
    │
    └─unit
            test_handler.py
            __init__.py

3. DynamoDB テーブルと Lambda 関数の定義 (解説)

template.yaml は AWS SAM において、アプリケーションの全体構成を記述するファイルです。リソース(DynamoDB テーブル、Lambda 関数など)の作成や API Gateway の設定を定義します。


全体構成の概要

  • DynamoDB テーブル (TaskTable)
    • タスクを管理するためのデータベース。
  • Lambda 関数
    • タスク作成、取得、完了の 3 つの関数を定義。
  • API Gateway
    • Lambda 関数をトリガーするエンドポイントを提供。
  • Outputs セクション
    • デプロイ後に生成されるリソースの情報を出力。

DynamoDB テーブルの定義

以下の部分が DynamoDB テーブルの定義です。

TaskTable:
  Type: AWS::DynamoDB::Table
  Properties:
    TableName: TaskTable
    AttributeDefinitions:
      - AttributeName: id
        AttributeType: S
    KeySchema:
      - AttributeName: id
        KeyType: HASH
    BillingMode: PAY_PER_REQUEST

解説

  • Type: AWS::DynamoDB::Table

    • このリソースは DynamoDB のテーブルを作成します。
  • TableName

    • テーブル名を TaskTable に指定しています。この名前は DynamoDB 内で一意である必要があります。
  • AttributeDefinitions

    • id という属性を定義し、その型を文字列 (S) としています。
  • KeySchema

    • 主キーとして id 属性を指定しています。
    • KeyType: HASH は DynamoDB のパーティションキー (プライマリキー) です。
  • BillingMode: PAY_PER_REQUEST

    • 使用量に応じた料金を課金する設定です。リソースを効率的に利用できます。

Lambda 関数の定義

この YAML ファイルでは 3 つの Lambda 関数を定義しています。それぞれの役割を解説します。


1. タスク作成関数 (CreateTaskFunction)

CreateTaskFunction:
  Type: AWS::Serverless::Function
  Properties:
    CodeUri: hello_world/
    Handler: app.create_task
    Runtime: python3.11
    Architectures:
      - x86_64
    Environment:
      Variables:
        TABLE_NAME: TaskTable
    Policies:
      - DynamoDBCrudPolicy:
          TableName: TaskTable
    Events:
      CreateTaskApi:
        Type: Api
        Properties:
          Path: /tasks
          Method: post
  • CodeUri:

    • 関数コードが格納されているフォルダを指定します (hello_world/)。
  • Handler:

    • app.py 内の create_task 関数がエントリポイントとして実行されます。
  • Runtime:

    • 使用する言語のランタイムを指定します (python3.11)。
  • Environment:

    • Lambda 関数で使用する環境変数を定義します。
    • TABLE_NAME 変数に DynamoDB テーブル名 TaskTable を指定しています。
  • Policies:

    • DynamoDB の操作権限を指定します。
    • DynamoDBCrudPolicy により、TaskTable に対して読み取り、書き込み、更新、削除の操作が可能になります。
  • Events:

    • API Gateway をトリガーとして設定。
    • /tasks に対する POST リクエストを処理します。

2. タスク取得関数 (GetTasksFunction)

GetTasksFunction:
  Type: AWS::Serverless::Function
  Properties:
    CodeUri: hello_world/
    Handler: app.get_tasks
    Runtime: python3.11
    Architectures:
      - x86_64
    Environment:
      Variables:
        TABLE_NAME: TaskTable
    Policies:
      - DynamoDBReadPolicy:
          TableName: TaskTable
    Events:
      GetTasksApi:
        Type: Api
        Properties:
          Path: /tasks
          Method: get
  • Policies:

    • DynamoDBReadPolicy により、DynamoDB テーブルからのデータ読み取り操作が可能です。
  • Events:

    • /tasks に対する GET リクエストを処理します。

3. タスク完了関数 (CompleteTaskFunction)

CompleteTaskFunction:
  Type: AWS::Serverless::Function
  Properties:
    CodeUri: hello_world/
    Handler: app.complete_task
    Runtime: python3.11
    Architectures:
      - x86_64
    Environment:
      Variables:
        TABLE_NAME: TaskTable
    Policies:
      - DynamoDBCrudPolicy:
          TableName: TaskTable
    Events:
      CompleteTaskApi:
        Type: Api
        Properties:
          Path: /tasks/{id}/complete
          Method: put
  • Events:
    • /tasks/{id}/complete に対する PUT リクエストを処理します。
    • {id} は URL パスパラメータとして指定されます。

Outputs セクション

Outputs セクションでは、デプロイ後に生成されるリソースの情報を出力します。これにより、API Gateway エンドポイント URL や Lambda 関数 ARN などが簡単に参照できます。

Outputs:
  CreateTaskApi:
    Description: "API Gateway endpoint URL for creating tasks"
    Value: !Sub "https://${ServerlessRestApi}.execute-api.${AWS::Region}.amazonaws.com/Prod/tasks"
  GetTasksApi:
    Description: "API Gateway endpoint URL for retrieving tasks"
    Value: !Sub "https://${ServerlessRestApi}.execute-api.${AWS::Region}.amazonaws.com/Prod/tasks"
  CompleteTaskApi:
    Description: "API Gateway endpoint URL for completing tasks"
    Value: !Sub "https://${ServerlessRestApi}.execute-api.${AWS::Region}.amazonaws.com/Prod/tasks/{id}/complete"

解説

  • CreateTaskApi:
    • タスク作成用 API のエンドポイントを出力します。
  • GetTasksApi:
    • タスク取得用 API のエンドポイントを出力します。
  • CompleteTaskApi:
    • タスク完了用 API のエンドポイントを出力します。
  • !Sub:
    • 文字列中の ${} 部分を CloudFormation が解釈して動的に値を埋め込みます。

4. Lambda 関数の実装

以下は、app.py ファイルに記述された 3 つの Lambda 関数についての解説です。


全体構成

import json
import boto3
import uuid
import os

# DynamoDB リソースの設定
# 本番環境とローカル環境で切り替え可能
# dynamodb = boto3.resource('dynamodb', endpoint_url="http://host.docker.internal:8000")
dynamodb = boto3.resource('dynamodb')

# 環境変数から DynamoDB テーブル名を取得
table_name = os.environ['TABLE_NAME']
table = dynamodb.Table(table_name)

ポイント

  • boto3.resource('dynamodb'):
    • AWS DynamoDB にアクセスするための設定。
    • 本番環境では endpoint_url を設定せずにデフォルトで動作します。
  • 環境変数 TABLE_NAME:
    • DynamoDB テーブル名を環境変数から取得し、動的に設定します。

1. タスク作成関数 (create_task)

def create_task(event, context):
    """
    タスクを作成するLambda関数
    """
    body = event.get('body')
    if not body:
        return {
            "statusCode": 400,
            "body": json.dumps({"message": "Invalid request, 'body' is missing"})
        }

    try:
        data = json.loads(body)
    except json.JSONDecodeError:
        return {
            "statusCode": 400,
            "body": json.dumps({"message": "Invalid JSON in request body"})
        }

    # タスクを作成
    task_id = str(uuid.uuid4())
    task = {
        "id": task_id,
        "title": data.get("title", "Untitled Task"),
        "description": data.get("description", ""),
        "status": "pending"  # デフォルトで未完了状態
    }
    table.put_item(Item=task)

    return {
        "statusCode": 201,
        "body": json.dumps({"message": "Task created", "task": task})
    }

動作の流れ

  1. リクエストボディの検証

    • event['body'] が存在するか確認。
    • JSON 形式で解析し、不正なリクエストはエラーを返します。
  2. タスクデータの作成

    • UUID で一意の ID を生成。
    • タスクの title, description, status を設定。
  3. DynamoDB に保存

    • table.put_item(Item=task) を使用してデータを挿入。
  4. レスポンス

    • 作成されたタスクのデータを含むレスポンスを返します。

2. タスク取得関数 (get_tasks)

def get_tasks(event, context):
    """
    すべてのタスクを取得するLambda関数
    """
    response = table.scan()
    tasks = response.get("Items", [])
    return {
        "statusCode": 200,
        "body": json.dumps({"tasks": tasks})
    }

動作の流れ

  1. データ取得

    • table.scan() で DynamoDB テーブル内のすべてのタスクを取得します。
  2. レスポンス

    • 取得したタスクデータを JSON 形式で返します。

3. タスク完了関数 (complete_task)

def complete_task(event, context):
    """
    指定されたタスクを完了にするLambda関数
    """
    # タスクIDを取得
    path_parameters = event.get("pathParameters", {})
    task_id = path_parameters.get("id")

    if not task_id:
        return {
            "statusCode": 400,
            "body": json.dumps({"message": "Task ID is required in the path"})
        }

    # タスクの状態を更新
    try:
        response = table.update_item(
            Key={"id": task_id},
            UpdateExpression="SET #status = :status",
            ExpressionAttributeNames={
                "#status": "status"
            },
            ExpressionAttributeValues={
                ":status": "completed"
            },
            ReturnValues="UPDATED_NEW"
        )
        return {
            "statusCode": 200,
            "body": json.dumps({"message": "Task completed", "updatedAttributes": response.get("Attributes", {})})
        }
    except Exception as e:
        return {
            "statusCode": 500,
            "body": json.dumps({"message": "Failed to complete task", "error": str(e)})
        }

動作の流れ

  1. タスク ID の取得

    • event['pathParameters']['id'] から ID を取得。
    • ID が指定されていない場合はエラーを返します。
  2. DynamoDB 更新

    • 指定された ID のタスクを検索し、statuscompleted に変更。
    • 更新された内容をレスポンスとして返します。
  3. エラーハンドリング

    • 更新処理中の例外はキャッチし、エラーメッセージを含むレスポンスを返します。

ローカル環境での注意点

  • ローカル環境で動作確認する場合、endpoint_url を設定して DynamoDB Local を使用します。
  • 本番環境ではコメントアウトして、標準の AWS DynamoDB に接続します。
# dynamodb = boto3.resource('dynamodb', endpoint_url="http://host.docker.internal:8000")
dynamodb = boto3.resource('dynamodb')

このように、ローカルテスト用と本番環境用を簡単に切り替えることができます。

5. ローカルテスト

ローカルテストでは、AWSリソースを直接触らずに環境を模擬して、Lambda関数やDynamoDBテーブルの動作確認を行います。このセクションでは、DynamoDB Local を使用したローカルテストの手順を詳しく説明します。


前提条件

  1. AWS SAM CLI がインストールされていること。
  2. Docker がインストールされ、起動していること。
  3. DynamoDB Local が起動していること(この記事を参考)。

手順

1. DynamoDB Local の起動

以下のコマンドで DynamoDB Local を Docker コンテナとして起動します。

docker run -d -p 8000:8000 amazon/dynamodb-local
  • オプションの確認
    • -d : バックグラウンドで実行。
    • -p 8000:8000 : ホストとコンテナのポートを 8000 にバインド。

2. DynamoDB テーブルの作成

以下のコマンドで DynamoDB Local にテーブルを作成します。

aws dynamodb create-table \
    --table-name TaskTable \
    --attribute-definitions AttributeName=id,AttributeType=S \
    --key-schema AttributeName=id,KeyType=HASH \
    --billing-mode PAY_PER_REQUEST \
    --endpoint-url http://localhost:8000
  • 各パラメータの意味
    • --table-name TaskTable: 作成するテーブル名。
    • --attribute-definitions: テーブルの属性定義。ここでは id を文字列型で定義。
    • --key-schema: プライマリキーを指定。
    • --billing-mode PAY_PER_REQUEST: 従量課金モードを指定。
    • --endpoint-url http://localhost:8000: ローカル DynamoDB に接続。

3. DynamoDB の状態確認

テーブルが作成されたかを確認します。

aws dynamodb list-tables --endpoint-url http://localhost:8000

出力例:

{
    "TableNames": [
        "TaskTable"
    ]
}

次に、テーブルの詳細情報を確認します。

aws dynamodb describe-table --table-name TaskTable --endpoint-url http://localhost:8000

4. イベントファイルの準備

Lambda 関数のテストに使用するイベントファイルを用意します。

① タスク作成 (create_task.json):

{
    "resource": "/tasks",
    "path": "/tasks",
    "httpMethod": "POST",
    "isBase64Encoded": false,
    "headers": {
        "Content-Type": "application/json"
    },
    "body": "{\"title\": \"Test Task\", \"description\": \"This is a test task.\"}"
}

② タスク取得 (get_tasks.json):

{
    "resource": "/tasks",
    "path": "/tasks",
    "httpMethod": "GET",
    "isBase64Encoded": false,
    "headers": {
        "Content-Type": "application/json"
    }
}

③ タスク完了 (complete_task.json):
pathpathParameters.idは作成したタスクを確認して適宜変えてください。

{
    "resource": "/tasks/{id}/complete",
    "path": "/tasks/a044c959-0139-401d-8131-9781a991ffe0/complete",
    "httpMethod": "PUT",
    "isBase64Encoded": false,
    "headers": {
        "Content-Type": "application/json"
    },
    "pathParameters": {
        "id": "a044c959-0139-401d-8131-9781a991ffe0"
    }
}

5. Lambda 関数のローカルテスト

AWS SAM CLI を使用して Lambda 関数をローカルでテストします。

  1. SAM ビルド

以下のコマンドで Lambda 関数をビルドします。

sam build

成功例:

Build Succeeded
Built Artifacts  : .aws-sam/build
Built Template   : .aws-sam/build/template.yaml
  1. Lambda 関数のテスト
  • タスク作成

    sam local invoke CreateTaskFunction --event events/create_task.json
    
  • タスク取得

    sam local invoke GetTasksFunction --event events/get_tasks.json
    
  • タスク完了

    sam local invoke CompleteTaskFunction --event events/complete_task.json
    

出力例:

  • タスク作成の成功例
    {
        "statusCode": 201,
        "body": "{\"message\": \"Task created\", \"task\": {\"id\": \"01e86c41-a58b-46b0-9495-c8390a0bb420\", \"title\": \"Test Task\", \"description\": \"This is a test task.\", \"status\": \"pending\"}}"
    }
    

6. DynamoDB Local でデータ確認

DynamoDB Local に保存されたデータを確認します。

aws dynamodb scan --table-name TaskTable --endpoint-url http://localhost:8000

出力例:

{
    "Items": [
        {
            "title": {
                "S": "Test Task"
            },
            "description": {
                "S": "This is a test task."
            },
            "id": {
                "S": "01e86c41-a58b-46b0-9495-c8390a0bb420"
            },
            "status": {
                "S": "pending"
            }
        }
    ],
    "Count": 1,
    "ScannedCount": 1,
    "ConsumedCapacity": null
}

補足: DynamoDB Local GUI (dynamodb-admin)

より視覚的に DynamoDB Local を操作したい場合は、dynamodb-admin を使用します。
https://github.com/aaronshaf/dynamodb-admin

  1. インストール

    npm install -g dynamodb-admin
    
  2. 起動

    dynamodb-admin --dynamo-endpoint=http://localhost:8000 --skip-default-credentials
    
  3. アクセス

    • ブラウザで http://localhost:8001 にアクセスします。
    • テーブルデータを GUI で確認できます。

6. 本番環境へのデプロイ

ローカルでの動作確認が終わったら、次は本番環境へのデプロイを行います。AWS SAM CLI を使用して、作成したリソースを AWS にデプロイする方法を以下に詳しく説明します。


デプロイ手順

1. sam deploy --guided コマンドの実行

以下のコマンドを実行して、AWS にデプロイします。

sam deploy --guided

2. 対話形式の設定

コマンド実行後に対話形式で設定を進めます。以下は設定の例です。

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

        Looking for config file [samconfig.toml] :  Not found
        Setting default arguments for 'sam deploy'

Stack Name [task-app]:  # デプロイする CloudFormation スタック名を入力します (例: task-app)
AWS Region [us-east-1]: ap-northeast-1  # デプロイするリージョンを指定します (例: ap-northeast-1)

# Shows you resources changes to be deployed and require a 'Y' to initiate deploy
Confirm changes before deploy [y/N]: Y  # デプロイ前にリソースの変更を確認したい場合は "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]: Y  # 必要な IAM ロールを作成する場合は "Y"

# Preserves the state of previously provisioned resources when an operation fails
Disable rollback [y/N]: N  # エラー時にロールバックを無効にしたい場合は "Y" を選択

# 今回は簡単な検証目的なので認証不要
CreateTaskFunction has no authentication. Is this okay? [y/N]: Y
GetTasksFunction has no authentication. Is this okay? [y/N]: Y
CompleteTaskFunction has no authentication. Is this okay? [y/N]: Y

Save arguments to configuration file [Y/n]: Y  # 設定を `samconfig.toml` に保存する場合は "Y"
SAM configuration file [samconfig.toml]:  # デフォルトで "samconfig.toml" を指定
SAM configuration environment [default]:  # 環境名を指定 (通常は "default")

3. デプロイの進行

設定を入力すると、以下のような進捗が表示されます。

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

Initiating deployment
=====================

Waiting for changeset to be created..

CloudFormation stack changeset
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------     
Operation                                               LogicalResourceId                                       ResourceType                                            Replacement
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------     
+ Add                                                   CompleteTaskFunctionCompleteTaskApiPermissionProd       AWS::Lambda::Permission                                 N/A
+ Add                                                   CompleteTaskFunctionRole                                AWS::IAM::Role                                          N/A
+ Add                                                   CompleteTaskFunction                                    AWS::Lambda::Function                                   N/A
+ Add                                                   CreateTaskFunctionCreateTaskApiPermissionProd           AWS::Lambda::Permission                                 N/A
+ Add                                                   CreateTaskFunctionRole                                  AWS::IAM::Role                                          N/A
+ Add                                                   CreateTaskFunction                                      AWS::Lambda::Function                                   N/A
+ Add                                                   GetTasksFunctionGetTasksApiPermissionProd               AWS::Lambda::Permission                                 N/A
+ Add                                                   GetTasksFunctionRole                                    AWS::IAM::Role                                          N/A
+ Add                                                   GetTasksFunction                                        AWS::Lambda::Function                                   N/A
+ Add                                                   ServerlessRestApiDeployment26a16bfa26                   AWS::ApiGateway::Deployment                             N/A
+ Add                                                   ServerlessRestApiProdStage                              AWS::ApiGateway::Stage                                  N/A
+ Add                                                   ServerlessRestApi                                       AWS::ApiGateway::RestApi                                N/A
+ Add                                                   TaskTable                                               AWS::DynamoDB::Table                                    N/A
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 

Deploy this changeset? [y/N]: y

y を入力してデプロイを進めます。


4. デプロイ完了後の確認

デプロイが成功すると以下のような結果が表示されます。

Successfully created/updated stack - task-app in ap-northeast-1
Outputs
----------------------------------------------------------------------------------------------------------------------------------
Key                 TaskTableName
Description         DynamoDB table name
Value               TaskTable

Key                 CompleteTaskApi
Description         API Gateway endpoint URL for completing tasks
Value               https://xxxxxx.execute-api.ap-northeast-1.amazonaws.com/Prod/tasks/{id}/complete

Key                 GetTasksApi
Description         API Gateway endpoint URL for retrieving tasks
Value               https://xxxxxx.execute-api.ap-northeast-1.amazonaws.com/Prod/tasks

Key                 CreateTaskApi
Description         API Gateway endpoint URL for creating tasks
Value               https://xxxxxx.execute-api.ap-northeast-1.amazonaws.com/Prod/tasks
----------------------------------------------------------------------------------------------------------------------------------

API エンドポイントの確認

  1. タスク作成 API

    • URL: https://xxxxxx.execute-api.ap-northeast-1.amazonaws.com/Prod/tasks
    • HTTP メソッド: POST
    • リクエストボディ例:
      {
        "title": "New Task",
        "description": "This is a new task."
      }
      
  2. タスク取得 API

    • URL: https://xxxxxx.execute-api.ap-northeast-1.amazonaws.com/Prod/tasks
    • HTTP メソッド: GET
  3. タスク完了 API

    • URL: https://xxxxxx.execute-api.ap-northeast-1.amazonaws.com/Prod/tasks/{id}/complete
    • HTTP メソッド: PUT

補足: デプロイの問題解決

template.yamlに問題がある場合

  • デプロイ時にエラーが発生した場合、以下のコマンドで template.yamlの構成に問題がないかを確認できます。
    sam validate
    

エラーが発生した場合

  • デプロイ時にエラーが発生した場合、以下のコマンドで CloudFormation のスタック状況を確認できます。
    aws cloudformation describe-stacks --stack-name task-app
    
  • マネジメントコンソールにアクセスしてCloudFormationのイベントタブからも原因を確認可能です。
    (キャプチャは正常にデプロイが完了しているものです)
    スクリーンショット 2024-12-21 124135.png

7. 本番環境での動作確認

1. デプロイ後の API Gateway 確認

AWS マネジメントコンソールから API Gateway の設定を確認します。

API Gateway コンソールに移動:

  • AWS マネジメントコンソールで「API Gateway」に移動します。
  • デプロイされた API (例: task-app) がリストに表示されていることを確認します。

スクリーンショット 2024-12-21 123231.png


2. Postman を使った API テスト

Postman を使用して、本番環境の API をテストしました。以下の順序で API を実行しています。


① タスクの作成 (POST)

スクリーンショット 2024-12-21 124655.png


② タスクの取得 (GET)

スクリーンショット 2024-12-21 125007.png


③ タスクの完了 (PUT)

スクリーンショット 2024-12-21 125337.png


④ 完了後のタスクの取得 (GET)

スクリーンショット 2024-12-21 125447.png


結果のまとめ

  • 全ての操作 (タスクの作成、取得、完了) が正常に動作することを確認しました。
  • DynamoDB に保存されたデータがリアルタイムで更新されていることも確認済みです。

8. 最後に

リソースの削除

  • 不要になったリソースを削除するには以下のコマンドを使用します。
    sam delete
    

これで、簡単にですがSAMを試すことができました。結構簡単にいろいろできそうなので、まだまだ触れていない部分も引き続き勉強を続けていきます!

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?