AWS lambda + API Gateway で郵便番号検索APIを作った


## はじめに
勉強目的で、AWS lambdaを使って郵便番号検索APIを作ってみました。

## 概要
任意の郵便番号をURLに含めてアクセスすると、該当する住所の情報が取得できるようにします。

### 構成図
ざっくりとした全体の構成は下図のとおりです。

![jp-zip-api.png](https://qiita-image-store.s3.amazonaws.com/0/26422/93415300-eafd-de23-e504-7724dfbd41ff.png "jp-zip-api.png")

## lambdaの作成
`Edit code inline`を選択し、テキストエリアにコードを貼り付けます。

```python
from __future__ import print_function

import json
import os
import boto3
from botocore.exceptions import ClientError

print('Loading function')


def respond(content=None, status_code=200):
    return {
        'statusCode': status_code,
        'body': content,
        'headers': {
            'Content-Type': 'application/json',
        },
    }


def lambda_handler(event, context):

    zip_code = event['zip_code']
    kana_type = event['kana_type']
    version = event['version']
    key = os.path.join(kana_type, version, zip_code[0:3] + '.json')
    
    try:
        s3 = boto3.client('s3')
        response = s3.get_object(Bucket='jp-zip', Key=key)
        json_data = json.load(response['Body'])
        if zip_code in json_data:
            return respond({'address': json_data[zip_code]})
    except ClientError:
        return respond('Zip code (' + zip_code + ') is invalid.', 404)

    return respond('Address is not found by zip code (' + zip_code + ').', 404)
```

関数内でやっていることは下記のとおりです。

- event変数から、必要なパラメータを取り出す
- S3の`jp-zip`バケットに郵便番号先頭3桁ごとにjsonファイルが格納されているので、取得する
  - jsonファイルをどう作成したのかは、別の機会に投稿することにします
- 取得した内容をjsonとして読み込む
- jsonデータの中から目的の郵便番号が存在するかチェックし、存在すれば内容を返す

### 設定
いくつかポイントを列挙します。

- Handler
  - {ファイル名}.{関数名}を入力します
  - `Edit code inline`の場合は、ファイル名は特にチェックしていない気がします
- Existing Role
  - lambda関数内でAWSのサービス（例: S3）を利用する場合は、アクセス権限が必要になるので、`IAM`で適切に設定します

![Lambda_config.png](https://qiita-image-store.s3.amazonaws.com/0/26422/baa8f671-3e91-3904-07c8-f7178d9e5934.png "Lambda_config.png")

### トリガーの設定
API Gatewayをトリガーに設定します。

![Lambda_triggers.png](https://qiita-image-store.s3.amazonaws.com/0/26422/31439692-bcb4-6c62-bc3b-2201e886372a.png "Lambda_triggers.png")

### lambdaのテスト
`Actions`のプルダウンメニューから`Configure test event`を選択し、必要なパラメーターをjson形式で設定し、`Save and test`ボタンをクリックします。

![Lambda_test_parameters.png](https://qiita-image-store.s3.amazonaws.com/0/26422/93967dd0-0b32-7cbe-1e17-1b3a0f6ea9e6.png "Lambda_test_parameters.png")

テストに成功すると、下記のようにログが出力されます。

![Lambda_test_result.png](https://qiita-image-store.s3.amazonaws.com/0/26422/644095e2-db08-3238-a4e3-05f30d39dc9a.png "Lambda_test_result.png")


### 参考URL
- [Amazon API Gateway での AWS Lambda の使用 (オンデマンド HTTPS 経由)](https://docs.aws.amazon.com/ja_jp/lambda/latest/dg/with-on-demand-https.html)

## APIの作成
郵便番号をパラメータとして、住所を検索するAPIを作成します。

### リソースの作成
API Gatewayにて、`/jp-zip/{zip_code}`というリソースを作成し、{zip_code}に任意の郵便番号を指定するようにします。
パラメータは中括弧（{}）で囲うようにします。

### メソッドの作成
`/jp-zip/{zip_code}`にGETメソッドを作成します。

![API_Gateway.png](https://qiita-image-store.s3.amazonaws.com/0/26422/9ab15c96-19b8-a1d7-c8ae-ce8bf409afba.png "API_Gateway.png")

### 本文マッピングテンプレート
統合リクエストのリンクから、本文マッピングテンプレートの設定をします。
メソッドリクエストパラメータをlambda関数に引き渡します。

![API_Gateway_lambda.png](https://qiita-image-store.s3.amazonaws.com/0/26422/f6f20406-8c31-50c6-7931-2b2aa159285d.png "API_Gateway_lambda.png")


- $input.params(x)
  - パラメータ名文字列 x が指定された場合に、パス、クエリ文字列、またはヘッダー値から（この順番で）メソッドリクエストパラメータの値を返します。

### ステージの作成
ステージを作成し、必要なパラメータをステージ変数に追加します。
郵便番号データの読み仮名の種別と更新年月日をステージ変数にセットしました。

- kana_code
  - oogaki
      - [読み仮名データの促音・拗音を小書きで表記しないもの](http://www.post.japanpost.jp/zipcode/dl/oogaki-zip.html)

  - kogaki
      - [読み仮名データの促音・拗音を小書きで表記するもの](http://www.post.japanpost.jp/zipcode/dl/kogaki-zip.html)
- version
  - 郵便番号データの更新日付

### API Gatewayのテスト
パス、ステージ変数にテストしたい内容を入力し、テストすると、レスポンスが出力されます。
![API_Gateway_test_result.png](https://qiita-image-store.s3.amazonaws.com/0/26422/5984090b-e3bf-6143-2371-40d0262e8129.png "API_Gateway_test_result.png")

### 参考URL
- [API Gateway API のリクエストパラメーターをマッピングする](https://docs.aws.amazon.com/ja_jp/apigateway/latest/developerguide/getting-started-mappings.html)
- [API Gateway API リクエストとレスポンスペイロードのマッピングテンプレートのリファレンス](https://docs.aws.amazon.com/ja_jp/apigateway/latest/developerguide/api-gateway-mapping-template-reference.html)
- [Amazon API Gateway ステージ変数の使用](https://docs.aws.amazon.com/ja_jp/apigateway/latest/developerguide/amazon-api-gateway-using-stage-variables.html)

## おわりに
サーバーを常設することなく、データベースも使わずに実装できたので、非常に安価に運用できる気がしてます。
様子をみてAPI公開するかもしれません。
Google Map APIも制限がキツくなったみたいですし。
[Google Maps Geocoding API Usage Limits  |  Google Maps Geocoding API](https://developers.google.com/maps/documentation/geocoding/usage-limits)
それでは、また。