はじめに
これは②の続きです。
バックエンド開発環境の作成
バックエンドはfastapiで動かす。fastapiはpythonで書くものなのでライブラリ関連は pip
というPythonパッケージ管理ツールを使用して入れる。
これはDockerfileで CMD
コマンドを使用して pip install -r requirements.txt
と書いておき、母艦で requirements.txt
に使用したいライブラリ一覧を記述し、 CMD
コマンドの前に COPY
コマンドを書いて母艦からコンテナに requirements.txt
をコピーするようにして置けばDockerイメージをビルドする際に自動的に使用するライブラリが入ることになる。
しかしこのままだとVSCodeで編集する際に requirements.txt
を記述したライブラリを使用しようとしたときに性的解析ツールが『そんなライブラリは知らん!!』とキレてくる。
何故Dockerfileに書いたのにVSCode上で怒られるかというと、あくまでコンテナ上にライブラリをインストールさせるようにしただけで、あくまでVSCodeで編集するのは母艦のpythonだからである。母艦にはライブラリを pip install
していないので当然VSCode上の静的解析ツールはライブラリを認識しない。
脳筋であれば母艦上で pip install
させれば解決することができるが、母艦の環境を汚すのは後々別のコンテナでホストを作成しようとしたときにライブラリが干渉する可能性がありダルい。
そこでpyenvというものを使用する。また、pyenv-installerというものを使用すればpyenvインストール時にpyenv-virtualenvというものも一緒に付いてきて、project毎、さらにはディレクトリ毎にpythonの環境を分けることができて便利である。
APIの定義
fastapiはHTTPリクエストのエンドポイントを定義することができる。
ざっくりHTTPについて説明すると Hyper Text Transfer Protocol
の略で、サーバとブラウザ間でテキストベースに通信するための各コンピュータ間のお約束事(プロトコル)である。
HTTPには代表的には以下4種のメソッドがある。
-
GET
- 単にサーバから情報を得る
-
POST
- サーバに情報を送信する
-
PUT
- サーバにある情報を更新する(正直
POST
と区別がつかない)
- サーバにある情報を更新する(正直
-
DELETE
- サーバにある情報を削除する
旧ロイヤルフレアでは、クライアントはcgiに対してリプレイをPOSTしたり削除パスワードを使用してDELETEし、それに対してcgiはhtmlファイルを生成して、記録を見たい人はcgiが作成したHTMLファイルをGETすることによって実現していた。
しかし今回はフロントエンドによってウェブページを動的に生成するものとした。よってクライアント側にはフロントエンドサーバから与えられたJavaScriptによる画面生成環境があり、JavaScriptに対してHTMLではなくJavaScriptが解釈できるようなフォーマットのテキストデータを送るだけで良くなり、画面生成の責任はない。
ここでフロントエンドの定義するJavaScriptがバックエンドに通信する出入口、及びそこから入出力されるデータを定義する必要が出てくる。このような出入り口をAPI
(Application Programmable Interface
)と呼ぶ。
今回のAPIは以下のように定義した。
-
GET /replays/sort={AA}&order={BB}&offset={CC}&limit={DD}
- リプレイの一覧を取得する
- sort以降のパラメータで取得できる情報を調整できる
- もしかしたらデプロイまでに変えるかも
-
GET /replays/{replay_id}
-
replay_id
に相当するリプレイ1件のメタデータを取得する - 今回は使用しないが便宜上作成する
- 誰かが自分のページをもとに便利アプリ作りたければ使ってください
-
-
GET /replays/{replay_id}/file
-
replay_id
に相当するリプレイファイルをダウンロードする
-
-
POST /replays
- ユーザ名や投稿コメント、及び削除パスワードとともにリプレイをアップロードする
-
DELETE /replays/{replay_id}
- 削除パスワードとともにリクエストすると
replay_id
に相当するリプレイを削除できる
- 削除パスワードとともにリクエストすると
-
GET /cocktail
GET /wine
GET /sake
GET /beer
GET /alcohol
-
/teapot
というエンドポイントにリダイレクトする
-
-
GET /teapot
- RFC2324に従って
418 I'm a teapot
エラーを返す
- RFC2324に従って
ここまでで出入り口について定義できたが入出力されるデータフォーマットについて定義しなければならない。
特にHTTPはあくまでテキスト送受信の約束事なので通常であればリプレイファイルのようなバイナリファイルを送受信することはできない
そこでMIMEというものがRFC2045等で定義されており、これでテキスト送受信という建前を保ったままバイナリファイル等を送受信することができる。
MIMEで送れるフォーマットはIANAという組織で管理されており、 application/form-data
や、 application/json
等がある。
jsonはキーバリューのデータ型で非常に扱いやすい。よって基本的に入出力はjsonで定義したがここで問題が起きた。
jsonのバリューにバイナリは入れられない1ので POST /replays
でjsonが使えない。
そこで全てのエンドポイントで入力を揃えるためにform-dataの方を使おうとしたが今度は DELETE /replays/{replay_id}
にてform-data形式でパスワードを送信することができない。
というのもform-dataはHTTPが定義された初期からあり、HTTPのできた当初は『DELETEはあくまでリソースの削除であるから、サーバに送信するデータはない』と考えていたようで、form-dataの送信は禁止されているそう。
そこで一応ギリセーフである application/json
でDELETE時のパスワードを送信することにした。
GET /alcohol
などのエンドポイントは『黄昏酒場のスコアボードだし、お酒をGETリクエストしたらくれるのか?』と思わせて実はサーバ自体がティーポットで出来ているためお酒を渡すことは出来ないというエラーである2。リターナー3で我慢しろ。
次回
作る環境が出来、エンドポイントも定義できたので内部を実装していく。
-
文字列へBase64エンコードすれば入れることも技術的には可能だがそれやってる暇あったら
application/form-data
を使った方が良い。 ↩ -
HTTP応答の
418 I'm a teapot
は1998年のエイプリルフールに発表されたRFC2324にて定義された、サーバにコーヒーを入れてもらうためのプロトコルであるHTCPCP
(Hyper Text Coffee Pot Control Protocol
)で制定されたエラー応答である。
このエラー応答は本来、サーバにコーヒーを入れてもらうように頼んだところ実はサーバはティーポットだったのでコーヒーは注げないというエラーである。
しかし今回はお酒に関するサービスを提供するサーバなので、コーヒーの部分をお酒に変えて実装した。RFC違反とみなされてもしょうがないがそもそもHTCPCP
はなんちゃってプロトコルだから許してくれ。 ↩ -
紅茶のお酒。 ↩