
AWS Hands-on for Beginners サーバーレスアーキテクチャで翻訳 Web API を構築する をやってみた
この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。
Classmethod Canadaでオペレーション業務をしているaiです。日々いろいろなサービスの調査等をしていますが、復習のため基本的な構成のハンズオンをやってみました。このハンズオンの内容をまとめて書きたいと思います。
コースで構築するアーキテクチャ
リクエストとして「こんにちわ」と入力すると、「Hello」と英語で返すものを作ります。
〜 流れ 〜
- API Gatewayがリクエスを受け付けると、Lambdaを呼び出す
- 
Lambdaの中でAmazon translate(翻訳サービス)を呼び出し、翻訳結果を取得する 
- 
その結果をAPI Gatewayに返し、APIレスポンスを送る 
- 
翻訳のインプット・アウトプットの履歴をDynamoDBに履歴を残す 
1. Lambdaハンズオン①-Lambda を単体で触ってみる
Lambda作成
Lambdaを新規作成します。


作成したものはこちら。


Lambdaのコードをテストする
まず「Test」ボタンの横の▼から「Configure test event」をクリックしテストイベント作成します。

デフォルトで「hello-world」が選択されていますが、他のサービスからのサンプルイベント等を選ぶことができます。
今回は、Event name を入力し、テンプレートは変更せずこのまま保存します。

テストイベントを保存すると、このように一覧に表示されます。 次はTestをクリックし、実行します。するとこのようにResponseとログを確認できます。
 

ログ記録ライブラリを使用してみる
より詳細なログ記録には、ログ記録ライブラリを使用できます。
import os
import logging
logger = logging.getLogger()
logger.setLevel(logging.INFO)
def lambda_handler(event, context):
logger.info('## ENVIRONMENT VARIABLES')
logger.info(os.environ['AWS_LAMBDA_LOG_GROUP_NAME'])
logger.info(os.environ['AWS_LAMBDA_LOG_STREAM_NAME'])
logger.info('## EVENT')
logger.info(event)
引用: ログ記録ライブラリ
上のコードから以下のように3行を追加しました。logger.info(event) で event の内容をログとして出力することができます。

Lambdaのコードを追記後、Deployをクリックし保存します。 テストイベントを実行し、実行したテストイベントの内容が表示されていることを確認しました。

CloudWatch logsでログを確認する
モニタリングタブではCloudWatch logsで出力されたログを確認できます。CloudWatch logsでは、イベントの内容や処理時間等を確認できます。

2. Lambdaハンズオン②-他のサービスを呼び出す
Python SDKを使う
AWS SDK for Python (Boto3)を使います。
上のリンクのAPI Referenceで各サービスでの使い方を確認できます。
今回はTranslateを見ていきます。

翻訳するための translate_text()メソッドを使っていきます。
Request Syntaxから必要な箇所を抜粋してコードに追加します。
translate_text()のRequest Syntaxはこちらです。
response = client.translate_text(
    Text='string',
    TerminologyNames=[
        'string',
    ],
    SourceLanguageCode='string',
    TargetLanguageCode='string',
    Settings={
        'Formality': 'FORMAL'|'INFORMAL',
        'Profanity': 'MASK'
    }
)
SourceLanguageCodeとTargetLanguageCodeは必須項目で、
サポートされている言語および言語コードでコードを確認できます。
下記のResponse Syntaxから、TranslatedTextを取得できれば良いので...
{
    'TranslatedText': 'string',
    'SourceLanguageCode': 'string',
    'TargetLanguageCode': 'string',
    'AppliedTerminologies': [
        {
            'Name': 'string',
            'Terms': [
                {
                    'SourceText': 'string',
                    'TargetText': 'string'
                },
            ]
        },
    ],
    'AppliedSettings': {
        'Formality': 'FORMAL'|'INFORMAL',
        'Profanity': 'MASK'
    }
}
下記のようにコードを書き換えました。
import json
import boto3
translate = boto3.client('translate')
def lambda_handler(event, context):
    input_text = 'おはよう'
    response = translate.translate_text(
        Text=input_text,
        SourceLanguageCode='ja',
        TargetLanguageCode='en',
    )
    output_text=response.get('TranslatedText')
    return {
        'statusCode': 200,
        'body': json.dumps({
            'output_text': output_text
    })
}
IAMロールを修正する
LambdaにTranslateにアクセスする権限を付与します。今回はハンズオンですのでTranslateFullAccessを許可しました。

テスト実行する
再度テスト実行すると、翻訳された結果が返ってきました。

3. API Gateway ハンズオン - API Gateway を単体で触ってみる
ここでは、API Gatewayのメソッドの統合タイプとして「Mock」を選択し、Lambda関数との連携を行わず固定のJsonを返すように設定します。
APIの作成
まず最初に、REST APIを選びます。

次の画面で以下のように設定し、APIを作成します。

次に、リソースを作成します。


作成したリソースに対しメソッドを作成します。

GETを作成し、Mockを選択し保存します。

統合レスポンス(Integration Responce)をクリックします。

マッピングテンプレートを追加すると、右側の枠が表示されるので、Content-type にapplication/jsonと入力し、右側の赤枠の箇所にJsonを定義し保存します。

APIのテスト
テストをクリックします。
 クエリ文字列などがあれば指定します。今回は何も指定せず、「テスト」をクリックし、先ほど入力したjsonが返ってくることが確認できました。
クエリ文字列などがあれば指定します。今回は何も指定せず、「テスト」をクリックし、先ほど入力したjsonが返ってくることが確認できました。

APIのデプロイ
APIのデプロイを選択し、新しくステージを作成します。


メソッドのGETを選択し、表示されているURLをクリックします。

別タブでURLが開き、先ほどのjsonがデプロイされていることを確認しました。

フロントエンド開発者のために、最初にAPIのMockを定義しておくことで、開発者同士の認識齟齬を減らすことができる。とのことです。
ここで作成した「/sample」リソースはこれ以降は使わないので削除します。
4. API Gatewayハンズオン - Lambda + API Gateway
先ほど作成したLambda関数とAPI Gatewayを連携させるように設定します。
API Gatewayの設定
まずは、ルートの直下にtranslateというリソースを作成します。

その下にGETメソッドを作成します。
「Lambdaプロキシ統合の使用」にチェックしAPI Gatewayからのインプットとアウトプットをそのままパススルーするように設定します。

API Gatewayに権限をつけてもいいか聞かれるのでOKをクリックします。

「Lambdaプロキシ統合の使用」にチェックしたので、「統合レスポンス」がグレイアウトし変換するように設定できなくなっています。
次に、「メソッドリクエスト」をクリックします。

ここで「URLクエリ文字列パラメータ」でクエリ文字列を追加します。「必須」にチェックを入れます。

Lambdaの設定
ここからLambdaを開いて修正します。

Lambdaを以下の形式で返すように修正します。
{
    statusCode: "...",            // a valid HTTP status code
    headers: { 
        custom-header: "..."      // any API-specific custom header
    },
    body: "...",                  // a JSON string.
    isBase64Encoded:  true|false  // for binary support
}
新しくテストイベントを作成します。queryStringParameters を"input_text":"こんにちわ"と変更しました。

Lambdaコード変更後がこちらです。新しく追加したテストイベントが選択されていることを確認し「テスト」ボタンをクリックします。

以下、テスト結果です。引数に設定したものがHelloとして入ってきていることを確認しました。

API Gatewayを実行
APIのデプロイから、先ほど作成したdevステージへデプロイします。


devステージのメソッドのGETを選択し、表示されているURLを開きます。

エラーとなるのですがこれは設定したクエリパラメータを渡していないためです。

クエリパラメーターのinput_textをURLに追加すると、英語に翻訳されたものが返ってきました。

5. DynamoDB ハンズオン - テーブル作成
DynamoDBのテーブルを作成します。
* Partition keyのみをプライマリーキーとして作成
* Partition keyとしてtimestampを指定
以下の設定としました。他の項目はデフォルトで作成しました。




6. DynamoDB ハンズオン - Lambda + API Gateway + DynamoDB
Lambdaを実行したタイミングで履歴としてDynamoDBにアイテムをputするように設定します。
Lambdaを修正する
DynamoDBのテーブルの操作をするので、DynamoDB/Resource/Table-Boto3 1.28.51 documentationを参考に、Lambdaに下記を追加していきます。
import boto3
dynamodb = boto3.resource('dynamodb')
table = dynamodb.Table('name')
'name'はDynamoDBのテーブル名です。
さらに、put_itemもドキュメントを参考に追加します。
最終的なコードはこちらです。赤枠の部分を追加しました。
日時を取得するため、datatimeをimportしています。

LambdaのIAMロールを修正する
DynamoDBにputするための権限を追加します。本来はポリシーを必要なものに絞る必要がありますが、今回はDynamoDBFullAccessを追加しました。

Lambdaのテスト
テストを実行すると、このように結果が返ってきました。

テストイベントのjsonのinput_textを「こんばんわ」に変え、再度テストを実行します。

Good Evening と結果が返ってきました。

DynamoDBには下記のようにItemが追加されています。

ここで、timestampの秒の箇所が'%'になっていることに気づき、下記を修正しました。最後の S が足りていませんでした。。(先ほどのLambdaコードは修正後のものです)
(誤)
'timestamp': datetime.datetime.now().strftime("%Y%m%d%H%M%"),
(正)
'timestamp': datetime.datetime.now().strftime("%Y%m%d%H%M%S"),
再度、テストイベントの内容を変更し実行してみました。

DynamoDBのitemに正しく追加されました。

API Gatewayのテスト
API Gatewayの先ほどのURLから、引数を渡します。
 
 DynamoDBに反映されました。
DynamoDBに反映されました。

おわりに
今回のハンズオンを通して、手を動かすことで楽しくサービスの概要や動作の復習をすることができました。また、ハンズオンを1回通すだけではなく、記事にするために何度かやり直したりと、さらに知識を深めることができたと思います。サービスや機能がどんどん増えていくので、今後別のハンズオンにも挑戦し、業務に活かせたらと思います!













