こんにちは、暑い日が続きますね。 こんな日はライムがキリッと効いた一杯でキメたいところです、エキスパート/lite開発の下山です。
今回は自身が担当しているサービスのバックエンドであるFastAPIについてお話ししたいと思います。
FastAPIってなに
FastAPI は、Pythonの標準である型ヒントに基づいてPython 以降でAPI を構築するための、モダンで、高速(高パフォーマンス)な、Web フレームワークです。
はい。
型ヒントあるし、モダンで高速なんですね。
ところでページ下部になんか書いてました。
FastAPI は巨人の肩の上に立っています。
・Web の部分はStarlette
・データの部分はPydantic
巨人の肩………………気になったのはもちろんWeb部分のStarletteです。
Starletteってなに
Starlette is a lightweight ASGI framework/toolkit, which is ideal for building async web services in Python.
Starlettは軽量なASGI framework/toolkitで、Pythonで非同期webサービスを構築するのに理想的です。(訳・下山)
つまり、ASGI (Asynchronous Server Gateway Interface) 、非同期処理による高い並行処理能力と様々な通信プロトコルのサポートという柔軟性を備えたフレームワーク/ツールキットってことですね。
これがFastAPIの高速(高パフォーマンス)を実現しているようです。
コードを見ていく
コードはFastAPIのチュートリアルから引用します。 importされたFastAPIクラスを掘っていくと、、、
from starlette.applications import Starlette from starlette.datastructures import State from starlette.exceptions import HTTPException from starlette.middleware import Middleware from starlette.middleware.base import BaseHTTPMiddleware from starlette.middleware.errors import ServerErrorMiddleware from starlette.middleware.exceptions import ExceptionMiddleware from starlette.requests import Request from starlette.responses import HTMLResponse, JSONResponse, Response from starlette.routing import BaseRoute from starlette.types import ASGIApp, Lifespan, Receive, Scope, Send class FastAPI(Starlette):
FastAPIクラス自体がStarletteを継承しています、この時点でStarletteの肩に乗る意味を理解。
ザッとクラスを整理すると、
はStarletteの機能、
- 型ヒント
- ドキュメント生成
- データバリデーション(Pydantic)
はFastAPIの拡張機能のようです。
importから分かる通りStarletteは様々なミドルウェア機能が充実しています。既存のミドルウェアをそのまま使うもよし、既存のミドルウェアをカスタマイズして新しいミドルウェアを作るもよし。これらの機能をFastAPI上で利用できることが、高い拡張性や柔軟性を実現しているようです。早速ミドルウェアをカスタマイズして、レスポンスにカスタムヘッダを追加してみました、いやはや便利。
from fastapi import FastAPI, Request from starlette.middleware.base import BaseHTTPMiddleware class AddHeaderResponse(BaseHTTPMiddleware): async def dispatch(self, request: Request, call_next): response = await call_next(request) response.headers["Hello_world"] = "(^o^)/~ thanks for reading" return response app = FastAPI() app.add_middleware(AddHeaderResponse) @app.get("/") async def root(): return {"message": "Awesome FastAPI !!!"}
巨人の両肩
純粋にStarletteで以下のコードを実装します。
from starlette.applications import Starlette from starlette.responses import JSONResponse from starlette.requests import Request from starlette.routing import Route async def cook_curry(request: Request): curry = await request.json() return JSONResponse(curry) async def root(request: Request): return JSONResponse({"message": "Hello, Starlette"}) routes = [ Route("/", endpoint=root, methods=["GET"]), Route("/curry/", endpoint=cook_curry, methods=["POST"]), ] app = Starlette(debug=True, routes=routes)
このコードでは/curry/
エンドポイントに対してPOSTリクエストを送信する際に、リクエストボディをそのままレスポンスとして返します。リクエストはカレーであってほしいのですが、このままだとカレーじゃなくてシチューでも受け入れ可能です。では絶対にリクエストがカレーであることを担保したコードに修正してみます。
from starlette.applications import Starlette from starlette.responses import JSONResponse from starlette.requests import Request from starlette.routing import Route from pydantic import BaseModel, ValidationError import json class Curry(BaseModel): spiciness: int topping: bool price: float async def cook_curry(request: Request): try: # リクエストボディをJSONとしてパース body = await request.json() # Pydanticモデルを使ってバリデーションする curry = Curry(**body) except ValidationError as e: # バリデーションエラー時のレスポンス return JSONResponse(status_code=422, content=json.loads(e.json())) return JSONResponse(curry.dict()) (略)
リクエストボディがPydanticモデルでバリデーションされるよう修正しました。このようにStarlette自体にはデータバリデーションの機能は組み込まれておらず、開発者が独自にバリデーションのロジックを用意する必要があります。ここをFastAPIではもう1つの巨人の肩であるPydanticによって担保しています。
両肩が揃いました。
FastAPIだと以下のようになります、とってもシンプル。
from fastapi import FastAPI from pydantic import BaseModel, ValidationError from starlette.responses import JSONResponse from starlette.requests import Request class Curry(BaseModel): spiciness: int topping: bool price: float app = FastAPI() @app.post("/curry/") async def cook_curry(menu: Curry): return menu @app.get("/") async def root(): return {"message": "Hello, FastAPI!”}
終わりに
やっとFastAPIの巨人の肩の意味がわかりました。 次回はルーティング処理についてもっと詳しく調べてみたいと思います。
皆さんもぜひFastAPIを使って、効率的なAPI開発を体験してみてください!