Python の Web Framework! FastAPI について調べてみた!
はじめに
Python の Web Framework には、Django や Flask などいくつかあります。
Django は、フロントエンドのコードもバックエンドのコードも1つで管理出来たり
Flask は、簡単にコードを書くことができるなどそれぞれ一長一短の特徴があります。(ここにあげたものだけではありませんが、、)
今回は、まだ比較的新しい FastAPI を使ってみます。
FastAPI とは
FastAPI はその名の通り高速でモダンな Web フレームワークであると謳っています。
特徴としては、
- 高速(NodeJS や Go 並みのとても高いパフォーマンス)
- 高速なコーディング
- 直感的
- 簡単
- 短い
- 堅牢性
とされています。
また、サポートしているのは、Python 3.6 以降になります。
簡単な使い方
環境
今回、紹介するにあたって、私の方で試した環境は以下になります。
- Python: 3.6.8
- fastapi: 0.63.0
- uvicorn: 0.13.3
インストール
$ pip install fastapi uvicorn
Get エントリポイント
from fastapi import FastAPI
app = FastAPI()
@app.get("/items/{item_id}")
async def read_item(item_id: int, q: str = None):
return {"item_id": item_id, "q": q}
動作確認
実行コマンド
$ uvicorn main:app --reload
ブラウザから http://127.0.0.1:8000/items/5?q=somequery にアクセスすると
{ "item_id": 5, "q": "somequery" }
このような値が返ってくるかと思います。
また、http://127.0.0.1:8000/docs にアクセスすると API ドキュメントも確認できます。
Post エントリポイント
from typing import Optional
from fastapi import FastAPI
from pydantic import BaseModel
app = FastAPI()
class Item(BaseModel):
name: str
description: Optional[str] = None
price: float
tax: Optional[float] = None
@app.post("/items/")
async def create_item(item: Item):
return item
動作確認
POST リクエストは、http://127.0.0.1:8000/docs にアクセスし、そこからリクエストを行います。
リクエストした値がそのままレスポンスとして返ってくることが分かると思います。
よく使う機能
クエリパラメータの検証
以下のようにすることでクエリパラメータが 3 文字以上 50 文字以下で ^fixedquery$
にマッチするものだけという
検証を行えます。
また、Query の第一引数は、デフォルトパラメータとなります。
from typing import Optional
from fastapi import FastAPI, Query
app = FastAPI()
@app.get("/items/")
async def read_items(
q: Optional[str] = Query(None, min_length=3, max_length=50, regex="^fixedquery$")
):
results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
if q:
results.update({"q": q})
return results
クッキーの取得
クッキーは、以下のようにして取得できます。Cookie の引数は、デフォルト値です。
from typing import Optional
from fastapi import Cookie, FastAPI
app = FastAPI()
@app.get("/items/")
async def read_items(ads_id: Optional[str] = Cookie(None)):
return {"ads_id": ads_id}
リクエストヘッダの取得
リクエストヘッダは、以下のようにして取得できます。Header の引数は、デフォルト値です。
from typing import Optional
from fastapi import FastAPI, Header
app = FastAPI()
@app.get("/items/")
async def read_items(user_agent: Optional[str] = Header(None)):
return {"User-Agent": user_agent}
エラーハンドリング
エラーを発火させるのは、raise
で HTTPException
を渡すことで実現できます。
from fastapi import FastAPI, HTTPException
app = FastAPI()
items = {"foo": "The Foo Wrestlers"}
@app.get("/items/{item_id}")
async def read_item(item_id: str):
if item_id not in items:
raise HTTPException(status_code=404, detail="Item not found")
return {"item": items[item_id]}
任意のステータスコードで返す
いくつか分岐させて、任意のステータスコードを返したい時もあると思います。
以下のようにすることで任意のステータスコードでレスポンスを返せます。
from typing import Optional
from fastapi import Body, FastAPI, status
from fastapi.responses import JSONResponse
app = FastAPI()
items = {"foo": {"name": "Fighters", "size": 6}, "bar": {"name": "Tenders", "size": 3}}
@app.put("/items/{item_id}")
async def upsert_item(
item_id: str, name: Optional[str] = Body(None), size: Optional[int] = Body(None)
):
if item_id in items:
item = items[item_id]
item["name"] = name
item["size"] = size
return item
else:
item = {"name": name, "size": size}
items[item_id] = item
return JSONResponse(status_code=status.HTTP_201_CREATED, content=item)
バックグラウンドでの処理
重たい処理など API のレスポンスを返した後に処理を行いたいこともあるかと思います。
以下のようにすることでログファイルへの書き出しはバックグラウンドで行えます。
from fastapi import BackgroundTasks, FastAPI
app = FastAPI()
def write_notification(email: str, message=""):
with open("log.txt", mode="w") as email_file:
content = f"notification for {email}: {message}"
email_file.write(content)
@app.post("/send-notification/{email}")
async def send_notification(email: str, background_tasks: BackgroundTasks):
background_tasks.add_task(write_notification, email, message="some notification")
return {"message": "Notification sent in the background"}
おわりに
いかがでしたか。
まだ、新しいのでドキュメントの日本語翻訳も途中のようですが、
FastAPI のドキュメントはとてもわかりやすく書かれていて、学習も容易なので、詳細はそちらをご確認ください。
バックエンドでは、アカウント管理もよくやることの一つかと思いますが、
そこについても書いてしまうととても長くなりそうだったので、そのうち書こうと思います。
お知らせ
Webサイト・ツール・LP作成のご依頼は、
こちらからお問い合わせいただけます。お気軽にご相談ください。
参考
Discussion