utamaro’s blog

誰かの役に立つ情報を発信するブログ

Flaskで共通的なpath変数を検証する方法

/api/<lang_code>/sampleのようなurlが用意されている場合、lang_codeはすべてのurlで利用する場合を想定します。

このとき、controller側でパタメータを取得し、検証する方法もあります。

ただし、すべてのcontrollerで同じ処理を書いてしまうのは避けるべきことです。

また、うっかり実装を忘れてしまうこともあります。

apiを用意する

class basedapiを用意しています。

本題と逸れる実装については解説を省きます。

今回はSampleApiを用意しました。

class SampleApi(ApiResource):
    endpoint = 'SampleApi'
    url_prefix = '/api/<lang_code>/sample'
    methods = ['POST']
    url_rules = [
        UrlRule(
            endpoint='sample',
            rule='index',
            methods=['POST'],
        )
    ]

    def post(self, lang_code):
        body = request.json
        print("called sample api.", body)
        return jsonify(body)

このapicurlを使って実行すると以下のようになります。

curl -X POST -H "Content-Type: application/json" -d '{
    "title": "sample title"
}' http://127.0.0.1:8080/api/ja/sign-in/index

このときの/ja/の部分を取得して、DBからデータを取得するなどできるようにします。

他にも、アプリケーションコンテキスト中にデータを格納できるgに値を入れるなどできます。

url_value_preprocessorの設定を行う

Flaskを拡張して、独自の設定を追加できるclassを作成します。

from app.request_module.pre_processors import language_code

class AppFlask(Flask):
    """Extended version of `Flask` that implements custom config class"""

    def init_url_value_preprocessor(self):
        self.url_value_preprocessor(language_code)

url_value_preprocessorlanguage_codeという関数を設定しています。

url_value_preprocessorFlask.before_request(f)の後に実行されます。

https://flask.palletsprojects.com/en/1.1.x/api/#flask.Flask.url_value_preprocessor

language_code関数を用意する

url_value_preprocessorで登録する関数にはendpointvaluesが必要です。

def language_code(endpoint, values):
    api_class = url_for(endpoint, lang_code="ja")
    if 'lang_code' in values or not g.lang_code:
        return

今回のSampleApiを実行した場合、endpointvaluesにはそれぞれ以下のようになります。

endpoint: SampleApi.sample
values:
  lang_code: ja

yamlで書いていますが、yamlが値に入るわけではありません。

endpointurl_forで使用可能な値です。

あとはapiを実行するだけで、先程作成したlanguage_code関数が実行されます。