DIVX テックブログ

catch-img

Pythonでオリジナルフレームワークをつくろう〜WSGIとは?〜

こんにちは、エンジニアの山坂です。
この記事では、Pythonを使用してオリジナルのフレームワークを作成する方法を紹介します。
フレームワーク作りは非常に楽しく、また学びも深まる活動ですが、一度にすべてを説明すると記事が長くなってしまいます。そこで、数回にわけて段階的に説明していく予定です。
今回はその第一回目です。
まず、フレームワークってそもそもなんでしょうか?
アプリケーションフレームワークについてWikiで調べてみるとこんな感じでした。

アプリケーションフレームワーク (英: application framework) とは、プログラミングにおいて、典型的・定型的なアプリケーションソフトウェアの標準構造を実装するのに使われる枠組みやテンプレートのことであり、ライブラリ(サブルーチンやクラスなど)の集合を含む[1]。ソフトウェアフレームワークの一種であり、単にフレームワークとも呼ぶ。

https://ja.wikipedia.org/wiki/%E3%82%A2%E3%83%97%E3%83%AA%E3%82%B1%E3%83%BC%E3%82%B7%E3%83%A7%E3%83%B3%E3%83%95%E3%83%AC%E3%83%BC%E3%83%A0%E3%83%AF%E3%83%BC%E3%82%AF

要は、アプリを作成するときに骨子となるものですね。
この骨子に当てはめて作成するので、手間が少なく、0から考えなくてもいいのです。
じゃあ、Pythonでフレームワークをつくるときに「よっしゃー、おれおれフレームワークのはじまりだー!まずはルーティングをこう!こう!こうこうこう!」ってやってもいいのですが、実はPython界隈ではフレームワーク作成のときにある程度規格が決まっていて、それに沿って作成することをよしとしています。
なんでそういうことをするのかというと、フレームワークにもある程度規格が定まっていることによって、ウェブサーバーとスムーズに接続できたり、いろいろ良いことがあるんですね。
ここらへんはPEP 333という資料に詳しく載っているので、興味のある方は見てみてください。
このPEP 333によると、PythonのフレームワークはWSGI(ウィズギー)という規格にそってねと書いてあります。
WSGIというのはWeb Server Gateway Interfaceのことです。インターフェースというのは、ものごとの境界となる部分と、その境界での処理方式であるプロトコル(WIKI)のことですから、要はapplicationとwebサーバーの境界となる部分を揃えようねってことですね。
で、WSGIに沿ったものというのはこういうのを指します。

def simple_wsgi_application(environ, start_response):
    response_body = 'Hello, World!'
    
    status = '200 OK'
    response_headers = [('Content-Type', 'text/plain')]
    
    start_response(status, response_headers)
    
    return [response_body.encode('utf-8')]

特徴がいくつかあるので、みていきましょう。


WSGIの特徴1
2つの引数を持った呼び出し可能なオブジェクトである
上のコードでいうと、2つの引数とは、environとstart_responseレスポンスのことです。
environ・・・リクエスト情報が格納された辞書。 HTTPリクエスト(GET、POST)、パス情報、クエリストリングが含まれる
start_response・・・WSGIサーバー(WSGIプロトコルをサポートするWebサーバー、あるいはWSGIアプリケーションサーバー)によって提供され、アプリケーションに渡される関数。 HTTPレスポンスのステータス(200 OK)、レスポンスヘッダー(Content-Type: text/html)をWebサーバーに伝える役割がある。


そして、呼び出し可能とは、以下のようなものを指します。
1 関数

2 メソッド(クラスの中に定義された関数)

3 クラス自身

4 ラムダ式

5 その他


つまり、2つの引数を持った呼び出し可能なオブジェクトである とは、実行や呼び出しが可能で、かつHTTPリクエストとレスポンスを返すための基礎データが入っているオブジェクトのことです。


WSGIの特徴2
第2引数として渡されたオブジェクトにHTTPステータスコードと[(レスポンスヘッダ, 値)]という値を渡して呼び出す
これは、さっきの2つの引数environとstart_responseのうち、start_responseのことを指しています。
start_responseは、例えば以下のようなものでなければいけません。


start_response('200 OK', [('Content-Type', 'text/plain')])


※これは、レスポンスのステータスとヘッダーを定義しているもので、bodyは別物であることに注意が必要です。


WSGIの特徴3
返り値にiterable objectを返す


iterable

その要素を一つずつ繰り返し取り出すことができるオブジェクトのこと。 具体的には、forループや他のイテレーション(反復処理)をサポートする構文において、その要素を順番に処理できるあらゆるオブジェクトが該当する。


Iterableなオブジェクトの例:

リスト: [1, 2, 3]

タプル: (1, 2, 3)

辞書: {"one": 1, "two": 2}

セット: {1, 2, 3}

文字列: "example"

ファイルオブジェクト: テキストファイルや他のストリームを読み込む場合

ジェネレータ: yieldキーワードを使用して個々の要素を逐次生成する関数や式


ここまでをまとめると、 WSGIの規格に沿ったアプリケーションとは、 2つの引数をもった呼び出し可能なオブジェクトのこと 2つの引数によって、リクエストと、レスポンスの骨子が作られる(bodyはつくられない)。
返り値(response_body)は、iterableなオブジェクトである。

iterableとは、要素を一つずつ繰り返し取り出すことが可能なオブジェクトのことです。
WSGIの文脈においては、これが、レスポンスボディにあたります。


話はもう十分や、わかった、つくろうやと思ったそこのあなた!よっしゃ、早速作りましょう。
まずはあなたのオリジナルフレームワーク名でディレクトリを作成しましょう。
そうですね、私の場合は「yamapy」 とでもしましょうか。いいですね。最高にクール!


$ mkdir yamapy

次にそのディレクトリに移動して、仮想環境を有効にします。

$ cd yamapy
$ python3.11 -m venv venv
$ source venv/bin/activate

次にGunicorn のエントリポイントを保存するapp.pyという名前のファイルを作成します。

(venv)$ touch app.py

app.pyの中に次のように書いてください。

app.py
def app(environ, start_response):
response_body = b"Hello, World!"
status = "200 OK"
start_response(status, headers=[])
return iter([response_body])

ここまでかけたら、Gunicorn をインストールしましょう。

(venv)$ pip install gunicorn

Gunicornを実行してみてください。

(venv)$ gunicorn app:app


上記のコマンドでは、最初のapp(コロンの左側) は作成したファイルで、2 番目のapp(コロンの右側) は記述した関数の名前です。
これが表示されたら、ブラウザを開いてhttp://localhost:8000にアクセスしてください。


Hello, World!

メッセージが表示されます。素晴らしいですね!
これで、あなたはオリジナルフレームワークの第一歩を踏み出しました。
次回はルーティングについて取り上げる予定です。お楽しみに!
参考記事
https://testdriven.io/courses/python-web-framework/wsgi/



お悩みご相談ください

  ご相談フォーム | 株式会社divx(ディブエックス) DIVXのご相談フォームページです。 株式会社divx(ディブエックス)


お気軽にご相談ください


ご不明な点はお気軽に
お問い合わせください

サービス資料や
お役立ち資料はこちら

DIVXメディアカテゴリー

テックブログ タグ一覧

採用ブログ タグ一覧

人気記事ランキング

GoTopイメージ