Flask + API Gateway + Lambda構成でServerless Frameworkのプラグインを利用せずに画面遷移をさせる方法

記事タイトルとURLをコピーする

こんにちは。サーバーワークスの松井です。

API Gateway + Lambda + Flaskといったwsgiのアプリケーションを構築する際にServerless Frameworkを利用しています。 Serverless Frameworkがv4から有料化するとの情報を得たので、無料で利用できるAWS AWS Serverless Application Model(AWS SAM)などの別のデプロイ用のフレームワークにて同様の構成のアプリケーションが構築できるかを検証してみました。

前提条件

  • Pythonが動作する環境をご用意してください
  • デプロイ用のフレームワークの利用方法については割愛します
  • Flaskが環境にインストールしてください

はじめに

FlaskアプリケーションのようなwsgiのアプリケーションをAPI Gateway + Lambda上で利用できるようにするには、Serverless Frameworkを利用すると、serverless-wsgiというプラグインが、API Gateway + Lambda上で正常に画面遷移が動作するようにプログラムをデプロイ時にラップしてくれるので特に意識することなく画面遷移ができていました。

プラグインなしでライブラリを導入して検証してみる

調べているうちにaws-wsgiというライブラリを利用するとlambda_hundlerをラップしてAPI Gateway + Lambda上でwsgiアプリケーションが動作するようにしてくれることがわかりましたが、画面遷移をするとURIからAPI Gatewayのステージ名のパスが抜け落ちてしまうことがわかりました。

ソースコードと画面遷移結果を以下に記載します。

app.py

import awsgi
from flask import Flask, render_template

app = Flask(__name__)

@app.route("/")
def index():
    return render_template("index.html")

@app.route("/hello", methods=["GET", "POST"])
def hello():
    return render_template("hello.html")

def lambda_handler(event, context):
    return awsgi.response(app, event, context)


templates/index.html

<!DOCTYPE html>
<html lang="ja">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <h1>Index</h1>
    <a href="{{url_for('hello')}}">Hello</a>
</body>

</html>

templates/hello.html

<!DOCTYPE html>
<html lang="ja">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <h1>Hello</h1>
    <a href="{{url_for('index')}}">Main</a>
</body>

</html>

serverless-wsgiのプラグインの処理を確認する

プラグインのソースコードを調べるとどうやらステージ名のパスを後付けする処理をしているようでした。

https://github.com/logandk/serverless-wsgi/blob/d0dca874ebd692849739800d5c47099291d895ea/serverless_wsgi.py#L109

API Gatewayのステージ名のパスを付与するようにコード内でラップする

先ほどのapp.pyにAPI Gatewayのステージ名のパスを付与するようにラップしてみます。

app.py

import awsgi
from flask import Flask, render_template

app = Flask(__name__)

@app.route("/")
def index():
    return render_template("index.html")

@app.route("/hello", methods=["GET", "POST"])
def hello():
    return render_template("hello.html")


def lambda_handler(event, context):
    event['headers']['X-Forwarded-Prefix'] = "/" + event['requestContext']['stage']

    def wrap_app(environ, sr):
        environ['SCRIPT_NAME'] = "/" + event['requestContext']['stage']
        return app(environ, sr)
    return awsgi.response(wrap_app, event, context)

if __name__ == '__main__':
    app.run(debug=True)

今度は正常にステージ名のパスが追加され、正常に画面遷移がされることが確認できました。

まとめ

Serverless Frameworkのプラグインを利用しなくてもFlask + API Gateway + Lambda構成を使えることがわかりました。 是非参考にしてみてください。