この記事は、「Serverless Advent Calendar 2018」の2日目の記事です。
Zappaを利用して、できるだけシンプルにかつDBもパッケージしたサーバーレスAPIを構築してみました!
Zappaとは、AWSのLambdaやAPI Gateway等のサービスを利用して、アプリを構築するPythonのサーバーレスフレームワークです。Zappaを利用することにより、各サービスの細かい設定をしなくても手軽にサーバーレスアプリをデプロイできます。
今回は、サンプルで住所検索APIをサーバーレスアプリとして構築してみました。
Zappaでサーバーレスアプリを構築するために
① ローカル環境構築
② アプリ機能構築
③ AWSにデプロイ
の順番で進めていきます。
① ローカル環境構築
ローカル環境を構築する前に、pyenvとvirtualenvとAWS CLIの設定を事前にしておく必要があります。
この辺の記事を参考に進めると準備可能です。
事前準備が完了したら、実際にローカル環境を構築していきます。まずは、仮想環境を構築します。
仮想環境作成
pyenv virtualenv 3.6.0 sample181202
仮想環境切り替え
pyenv local sample181202
次に、今回構築するアプリに必要なパッケージとZappaを仮想環境にインストールします。
Flaskインストール
pip install Flask
peeweeインストール
pip install peewee
Zappaインストール
pip install zappa
② アプリ機能構築
アプリ構築用に準備するファイル一覧
db.sqlite: 住所検索用のSQLiteファイル
app.py: Flask、peewee等を盛り込んだPythonファイル
zappa_settings.json: Zappaの設定ファイル
今回は、DBもパッケージしたサーバーレスアプリを構築するためDBはSQLiteを利用します。
SQLiteの中には、国土地理院の電子国土基本図(地名情報)「住居表示住所」データを取り込み利用します。サンプルでは、札幌市のデータを取り込みました。
※電子国土基本図(地名情報)「住居表示住所」データを利用するためには、国土地理院へ利用申請が必要です。
db.sqlite
次に、APIを構築してみます。
app.py
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#モジュールインポート
from flask import Flask, jsonify, abort, make_response, request
from peewee import *
#SQLite読み込み
database = SqliteDatabase("db.sqlite")
#ベースModel作成
class BaseModel(Model):
class Meta:
database = database
#addressテーブルのModel作成
class address(BaseModel):
id = TextField()
code = TextField()
prefectures = TextField()
city = TextField()
ward = TextField()
address = TextField()
number01 = TextField()
number02 = TextField()
url01 = TextField()
url02 = TextField()
lon = TextField()
lat = TextField()
level = TextField()
address_all = TextField()
#flaskのインスタンス作成
app = Flask(__name__)
#日本語表示対応
app.config['JSON_AS_ASCII'] = False
#JSON取得処理
@app.route('/', methods=['GET'])
def get_m():
#URLのKeyとDBのKeyを比較
try:
#クエリパラメータを取得
m_address = request.args.get('address_all')
if m_address is not None:
#like演算子追加
m_address_all = str("*" + m_address +"*")
#検索結果を取得
query = address.select().where(address.address_all % m_address_all)
#変数初期化
result = {}
count = 0
#検索結果でJSON作成
for m in query:
count = count + 1
result[str(count)] = {
"data":{
"lon":m.lon,
"lat":m.lat,
"level":m.level,
"address_all":m.address_all
},
"result":True
}
#結果は100件まで
if count == 100:
break
#最後にカウントをJSONに追加
result["count"] = count
else:
#エラーJSON作成
result = {
"error": "クエリ文字列を設定してください。",
"result":False
}
#JSONを出力
return make_response(jsonify(result))
except address.DoesNotExist:
abort(404)
#エラー処理
@app.errorhandler(404)
def not_found(error):
#エラーJSON作成
result = {
"error": "存在しません。",
"result":False
}
#エラーJSONを出力
return make_response(jsonify(result), 404)
#app実行
if __name__ == '__main__':
app.run()
ローカル環境でアプリを確認してみます。
ローカルサーバー起動
python app.py
クエリパラメータで検索したい住所を指定します。
「 http://127.0.0.1:5000/?address_all=北海道札幌市中央区 」
ローカル環境で問題なければ、Zappaの設定ファイルを作成します。
設定ファイル作成
zappa init
作成された設定ファイルを適宜修正します。
zappa_settings.json
{
"api": {
"app_function": "app.app",
"aws_region": "ap-northeast-1",
"project_name": "zappa_sample",
"runtime": "python3.6",
"s3_bucket": "zappa-iqubzbin5"
}
}
③ AWSにデプロイ
最後にZappaでアプリをデプロイします。
デプロイ
zappa deploy
デプロイ以外にもコマンドがあります。
削除
zappa undeploy
アップデート
zappa update
ログ確認
zappa tail
AWSのコンソールで確認してみます。
Lambda
API Gateway
公開されたAPIで動作確認してみます。
「 https://xxxxxxx.amazonaws.com/api/?address_all=北海道札幌市中央区 」
※Zappaにアップするとパスにapiが追加されます。
これでDBもパッケージしたサーバーレスAPIの公開ができますね!
今回のサンプルでは経緯度も取得できるので、LeafletやMapbox GL JS等のマップライブラリと組み合わせると、地図上に結果を可視化するアプリを構築することも可能になります!
※「このアプリケーションの作成に当たっては、国土地理院長の承認を得て、同院発行の電子国土基本図(地名情報)住居表示住所を使用した。(承認番号 平30情使、第928号)」