Amazon API GatewayとAWS Lambdaを組み合わせてみた

## はじめに
こんにちは。
今回はAPI Gateway、Lambda、Translateを連携させてみました。

本記事は以下記事の続編です。

https://qiita.com/uccy/items/33ffdcc855e54e1ba1fe

↓参考にしたハンズオンはこちら。

https://pages.awscloud.com/JAPAN-event-OE-Hands-on-for-Beginners-Serverless-1-2022-confirmation_422.html

↓今回のゴール
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3848705/0de145b5-a874-2b2b-e1d5-4d7af67de0cb.png)

## やってみた
マネジメントコンソールにアクセスし、API Gatewayのページにアクセスします。
前回作成したtranslate-apiをクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3848705/72f0f0ed-59f6-cfc5-d5c1-fe1abcba5aa8.png)

「リソースを作成」をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3848705/946070aa-515f-b4f2-ac99-5b7ac5ea95b5.png)

リソース名はtranslateとして「リソースを作成」をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3848705/3284ab45-27eb-f05a-a1f6-6abc5b54113f.png)

「メソッドを作成」をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3848705/127cabd3-ad77-b103-da80-85ca89b363c4.png)

メソッドタイプは「GET」、Lambda関数と連携するので、統合タイプは「Lambda統合」、「Lambdaプロキシ統合」をONにし、Lambda関数には「translate-function（Translateを呼び出す関数）」を指定します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3848705/f8712024-ba82-9aef-45fd-cfc88912890f.png)

下にスクロールして「メソッドを作成」をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3848705/9f3e4531-7f9a-eecc-e429-e0cabe156e06.png)

メソッドリクエストタブを開き、「編集」をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3848705/4ea9536e-fc8a-303b-aa9f-f7320a1844e9.png)

URLクエリ文字列パラメータをクリックし、「クエリ文字列を追加」をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3848705/64d3a2a3-4e04-3787-b03e-3e2f30880088.png)

名前はinput_text、必須にチェックを入れます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3848705/096883cd-3be6-7e4a-4e1f-24cd1632e3f3.png)

「Lambda統合」をクリックし、「translate-function」をクリックします。
Lambdaのページが別タブで開きます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3848705/dfeeab49-29f1-d916-803c-cef34d1b2edf.png)

API Gateway側のルールに従って、Lambda関数の出力を修正します。
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
}
```

[以前作ったLambda関数](https://qiita.com/uccy/items/24dba8396bccb7a2684d)には、statusCodeやbodyは既にreturnに含まれていますので、headersとisBase64Encodedを追加します。
下から2~3行目の部分ですね。
```
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   
        }),
        'isBase64Encoded': False,
        'headers': {}
    }
```

次にテストタブを開きます。
「新しいイベントを作成」をクリックし、イベント名を入力します。
テンプレートにはapigateway-aws-proxyを選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3848705/dc70b0cd-952f-22fe-60f0-fd6c61ebd235.png)

以下がそのテンプレートです。
API Gatewayからどのように情報が渡ってくるかを示しています。
```
{
  "body": "eyJ0ZXN0IjoiYm9keSJ9",
  "resource": "/{proxy+}",
  "path": "/path/to/resource",
  "httpMethod": "POST",
  "isBase64Encoded": true,
  "queryStringParameters": {
    "foo": "bar"
  },
  "multiValueQueryStringParameters": {
    "foo": [
      "bar"
    ]
  },
  "pathParameters": {
    "proxy": "/path/to/resource"
  },
  "stageVariables": {
    "baz": "qux"
  },
  "headers": {
    "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8",
    "Accept-Encoding": "gzip, deflate, sdch",
    "Accept-Language": "en-US,en;q=0.8",
    "Cache-Control": "max-age=0",
    "CloudFront-Forwarded-Proto": "https",
    "CloudFront-Is-Desktop-Viewer": "true",
    "CloudFront-Is-Mobile-Viewer": "false",
    "CloudFront-Is-SmartTV-Viewer": "false",
    "CloudFront-Is-Tablet-Viewer": "false",
    "CloudFront-Viewer-Country": "US",
    "Host": "1234567890.execute-api.us-east-1.amazonaws.com",
    "Upgrade-Insecure-Requests": "1",
    "User-Agent": "Custom User Agent String",
    "Via": "1.1 08f323deadbeefa7af34d5feb414ce27.cloudfront.net (CloudFront)",
    "X-Amz-Cf-Id": "cDehVQoZnx43VYQb9j2-nvCh-9z396Uhbp027Y2JvkCPNLmGJHqlaA==",
    "X-Forwarded-For": "127.0.0.1, 127.0.0.2",
    "X-Forwarded-Port": "443",
    "X-Forwarded-Proto": "https"
  },
  "multiValueHeaders": {
    "Accept": [
      "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8"
    ],
    "Accept-Encoding": [
      "gzip, deflate, sdch"
    ],
    "Accept-Language": [
      "en-US,en;q=0.8"
    ],
    "Cache-Control": [
      "max-age=0"
    ],
    "CloudFront-Forwarded-Proto": [
      "https"
    ],
    "CloudFront-Is-Desktop-Viewer": [
      "true"
    ],
    "CloudFront-Is-Mobile-Viewer": [
      "false"
    ],
    "CloudFront-Is-SmartTV-Viewer": [
      "false"
    ],
    "CloudFront-Is-Tablet-Viewer": [
      "false"
    ],
    "CloudFront-Viewer-Country": [
      "US"
    ],
    "Host": [
      "0123456789.execute-api.us-east-1.amazonaws.com"
    ],
    "Upgrade-Insecure-Requests": [
      "1"
    ],
    "User-Agent": [
      "Custom User Agent String"
    ],
    "Via": [
      "1.1 08f323deadbeefa7af34d5feb414ce27.cloudfront.net (CloudFront)"
    ],
    "X-Amz-Cf-Id": [
      "cDehVQoZnx43VYQb9j2-nvCh-9z396Uhbp027Y2JvkCPNLmGJHqlaA=="
    ],
    "X-Forwarded-For": [
      "127.0.0.1, 127.0.0.2"
    ],
    "X-Forwarded-Port": [
      "443"
    ],
    "X-Forwarded-Proto": [
      "https"
    ]
  },
  "requestContext": {
    "accountId": "123456789012",
    "resourceId": "123456",
    "stage": "prod",
    "requestId": "c6af9ac6-7b61-11e6-9a41-93e8deadbeef",
    "requestTime": "09/Apr/2015:12:34:56 +0000",
    "requestTimeEpoch": 1428582896000,
    "identity": {
      "cognitoIdentityPoolId": null,
      "accountId": null,
      "cognitoIdentityId": null,
      "caller": null,
      "accessKey": null,
      "sourceIp": "127.0.0.1",
      "cognitoAuthenticationType": null,
      "cognitoAuthenticationProvider": null,
      "userArn": null,
      "userAgent": "Custom User Agent String",
      "user": null
    },
    "path": "/prod/path/to/resource",
    "resourcePath": "/{proxy+}",
    "httpMethod": "POST",
    "apiId": "1234567890",
    "protocol": "HTTP/1.1"
  }
}
```
このコードの7行目に記載されているQueryStringParametersの部分を使います。
8行目（"foo": "bar"）の部分をinput_textに修正します。
```
  "queryStringParameters": {
    "input_text": "こんにちは"
  },
```

修正後、上にスクロールして「保存」をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3848705/74e05271-da00-aa8d-cc3f-bd76fcffedbd.png)

Lambda関数に戻ります。
input_textの部分にテキストがハードコーディングされているので、この部分を修正します。
```
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   
        }),
        'isBase64Encoded': False,
        'headers': {}
    }
```

event['queryStringParameters']['input_text']とし、イベントから文字列を受け取れるようにします。
```
import json
import boto3

translate = boto3.client('translate')

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')

    return {
        'statusCode': 200,
        'body': json.dumps({
            'output_text': output_text   
        }),
        'isBase64Encoded': False,
        'headers': {}
    }
```

「Deploy」をクリックし、「Test」をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3848705/838e0146-ce99-568e-4656-271cba2c011c.png)

Lambda関数が実行され、returnが返ってきました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3848705/5776a3b0-38fd-fc46-5f97-2cee9547bb81.png)

上にスクロールして「APIをデプロイ」をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3848705/3b910f04-46a2-fbcb-b488-fb5262fb8b2d.png)

ステージ欄にdevと入力し、「デプロイ」をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3848705/132ba2c5-6e25-3304-b30e-79fa428e3d4c.png)

URLをコピーします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3848705/5c0ac2a6-caef-f4d3-5e35-1dc6ae2f6d12.png)

コピーしたURLをブラウザで叩きます。
しかしエラーが返されました。
input_textを渡していないためです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3848705/91cbf033-d528-2f09-e137-4cb139251028.png)

URLの後ろに「?input_text=${翻訳したいテキスト}」を入力します。
今回は「お酒を飲みたい」としました。
すると、outputとして、英語に翻訳された文章が表示されました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3848705/73f35ac0-91b8-b061-79e2-2d67ddef01b1.png)

## おわりに
最近帰りが遅くなってきて平日にあまりアウトプットできなくなってきましたが、自分のペースで継続していこうと思います。
今度はdynaboDBと連携させていただきです。