【AWS初学者向け】翻訳WEB APIを作成してみた（ハンズオン）

# 注釈
[こちら](https://technowanko.com/posts/aws/translate_web_api/)に移動しました。



# はじめに
AWSハンズオン資料集の中から「サーバーレスアーキテクチャで翻訳 Web API を構築する」を試してみて結構楽しかったので

1. **AWS初学者向けに構築フロー**
2. **つまずきポイント**
3. **個人的に修正してみた箇所**

の３点を共有します。


https://pages.awscloud.com/event_JAPAN_Hands-on-for-Beginners-Serverless-2019_LP.html?trk=aws_introduction_page


上記、URLからAWS初学者の方はぜひトライしてみてください。


#参考ドキュメント

https://boto3.amazonaws.com/v1/documentation/api/latest/index.html

https://docs.aws.amazon.com/ja_jp/apigateway/latest/developerguide/api-gateway-integration-settings-integration-response.html

#構成
![スクリーンショット 2021-11-14 15.12.10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2097948/f72876f3-e529-f071-710f-d377af5cd223.png)（ハンズオン資料より抜粋）

#####ブラウザで翻訳語の文字列が返ってくれば完成
![スクリーンショット 2021-11-28 12.25.55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2097948/ebfd7237-05ac-2cf3-5555-225f6928ed57.png)
![スクリーンショット 2021-11-28 12.26.00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2097948/d87e89ad-aa0e-412f-5e8b-2ba1400acfe6.png)




#LambdaからAWS Translateを呼び出す
LambdaからAWS Translateを呼び出すためには、python SDK のboto3を使用します。

https://boto3.amazonaws.com/v1/documentation/api/latest/index.html

公式ドキュメントからtranslateの項目を確認し、使い方を参照します。

![スクリーンショット 2021-11-28 12.03.24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2097948/fe4483d3-a814-787b-bbcf-aec390ac7809.png)

![スクリーンショット 2021-11-28 12.04.18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2097948/86d5d856-a5e1-c2af-64de-edc32affe81d.png)

必須パラメータは、下記の通り

```python
response = client.translate_text(
    Text='string',
    SourceLanguageCode='string',
    TargetLanguageCode='string',
    }
)
```

レスポンスは下記のように返ってくるとのこと
![スクリーンショット 2021-11-28 12.54.37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2097948/c658be40-c420-107a-51f6-c72b581d6f41.png)




```python
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
        }),
    }
```


#API Gatewayを設定し、Lambdaのソースコードを修正する

アクションからリソースの作成→メソッドの作成を行う
![スクリーンショット 2021-11-28 13.04.33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2097948/5be9ba77-de92-af7e-a402-183b3e1ba695.png)


![スクリーンショット 2021-11-28 13.06.04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2097948/ac63aa5d-d3ae-27fc-ed83-f9d35a498e09.png)


クエリ文字列パラメータの設定
![スクリーンショット 2021-11-28 13.10.43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2097948/ed9a0f32-cc16-1701-a083-dcfe1a587f14.png)


API Gateway統合レスポンスで検索すると、
Lambda プロキシ統合で、Lambda 関数は以下の形式で出力を返す必要があることがわかります。

https://docs.aws.amazon.com/ja_jp/apigateway/latest/developerguide/api-gateway-integration-settings-integration-response.html


```
{
    statusCode: "...",            // a valid HTTP status code
    headers: { 
        custom-header: "..."      // any API-specific custom header
    },
    body: "...",                  // a JSON string.
    isBase64Encoded:  true|false  // for binary support
}
```



###コード修正

```python

import boto3

translate = boto3.client('translate')

input_text = event['queryStringParameters']['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
        }),
        'isBase64Encoded': False,
        'headers': {}
    }
```



#DynamoDBに入力テキストと変換後テキストを格納する

事前にテーブルを作成する必要あり

修正箇所


```python
import datetime

dynamodb = boto3.resource('dynamodb')
translate_history_table = dynamodb.Table('tranlate-history')

translate_history_table.put_item(
        Item = {
            'timestamp': datetime.datetime.now().strftime("%Y%m%d%H%M%S"),
            'input_text': input_text,
            'output_text': output_text
        }
    )
```



#Lambda関数全体
```python
import json
import boto3
import datetime

translate = boto3.client('translate')

dynamodb = boto3.resource('dynamodb')
translate_history_table = dynamodb.Table('translate-history')

def lambda_handler(event, context):
    
    input_text = event['queryStringParameters']['input_text']

    response = translate.translate_text(
        Text=input_text,
        SourceLanguageCode='ja',
        TargetLanguageCode='en'
    )
    output_text = response.get('TranslatedText')
    
    translate_history_table.put_item(
        Item = {
            'timestamp': datetime.datetime.now().strftime("%Y%m%d%H%M%S"),
            'input_text': input_text,
            'output_text': output_text
        }
    )
    
    return {
        'statusCode': 200,
        'body': json.dumps({
            'output_text': output_text
        }),
        'isBase64Encoded': False,
        'headers': {}
    }
```




#つまずきポイント

`https://*******.execute-api.ap-northeast-1.amazonaws.com/Stage/translate?input_text=こんにちは`

![スクリーンショット 2021-11-28 14.44.35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2097948/204f3e54-f21a-9261-b793-b1133a7c9597.png)

あれ、返ってこない、、、


####結論：dynamoDBへの実行ロールを付与し忘れ
![スクリーンショット 2021-11-28 14.51.58.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2097948/6b3f5741-bc00-5cbe-08ee-74be38f7ab02.png)


####余談
api gatewayは、作成するときに自動的にロール付与してくれたな。。
![スクリーンショット 2021-11-28 14.54.52.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2097948/f7e9df8d-cb85-3e84-8033-bb23bdcb7021.png)


#個人的に工夫した点

####任意のステータスコードを返すようにLambda関数にエラーハンドリングを実装

```python
import json
import boto3
import datetime
import logging

translate = boto3.client('translate')

dynamodb = boto3.resource('dynamodb')
translate_history_table = dynamodb.Table('tranlate-history')

def lambda_handler(event, context):
    
    input_text = event['queryStringParameters']['input_text']

#追加箇所
    try:
        response = translate.translate_text(
            Text=input_text,
            SourceLanguageCode='ja',
            TargetLanguageCode='en'
        )
    except Exception　:
        raise ExtendException(400, "Bad Request")

        
    output_text = response.get('TranslatedText')
    
    translate_history_table.put_item(
        Item = {
            'timestamp': datetime.datetime.now().strftime("%Y%m%d%H%M%S"),
            'input_text': input_text,
            'output_text': output_text
        }
    )
    
    return {
        'statusCode': 200,
        'body': json.dumps({
            'output_text': output_text
        }),
        'isBase64Encoded': False,
        'headers': {}
    }

#追加箇所
class ExtendException(Exception):
    def __init__(self, statusCode, description):
        self.statusCode = statusCode
        self.description = description

    def __str__(self):
        obj = {
            "statusCode": self.statusCode,
            "description": self.description
        }
        return json.dumps(obj)

```

#まとめ
SAA資格勉強での知識しかなかった私にはとても有用なハンズオンでした。
次は、SAMでデプロイの自動化を実装したいと思います。