【Python】Fast APIをざっくり紹介【Webフレームワーク】

Python

皆さんこんにちは。大学のレポート課題に殺されかけているmk419です。

今回はFast APIについてざっくり紹介していきます。

スポンサーリンク

Fast APIとは?

APIとかWebアプリを構築出来る、Pythonで書かれたWebフレームワークです。

Fast APIの特徴

とても速い

Fast APIはNode JSやGoと真正面から殴り合えます。DjangoやFlaskより、ずっとはやい!!

コード量が少ない

下記の例を見れば分かると思いますが、Flask並の記述量で動かせます。

セットアップ

sudo pacman -S python-fastapi uvicorn

お好みでpython-jinjaとかpython-aiofilesとか入れてください。

注意: 今回のコードはPython 3.9以上の環境で動きます!!!

例1

JSONを返す単純なものです。

from fastapi import FastAPI

app = FastAPI()

@app.get("/")
async def root():
    return {"message": "Hello World!"}

main.pyで保存してください。

実行

uvicorn main:app --reload

結果

デフォルトのURLはhttp://127.0.0.1:8000/となっています。

{"message":"Hello World!"}

上記と同じものが帰ってきたら成功です。

解説

@app.getでパスの指定を行っています。

Dict型を返すと自動的にJSONに変換してくれます。

例2

パスパラメータを使用したものです。

from fastapi import FastAPI

app = FastAPI()

@app.get("/")
async def root():
    return {"message": "Hello World!"}

@app.get("/name/{name}")
async def hello_name(name: str):
    return {"message": f"Hello {name}!"}

実行等は例1と同様なので省略。

結果

http://127.0.0.1:8000/name/mk419にアクセスすると、下記のようになります。

{"message":"Hello mk419!"}

解説

@app.getでパスパラメータnameの値が引数nameに代入されます。

型の変換は自動でやってくれます。

例3

例2にクエリパラメータを付けたものです。

from fastapi import FastAPI

app = FastAPI()

@app.get("/")
async def root():
    return {"message": "Hello World!"}

@app.get("/name/{name}")
async def hello_name(name: str, year: int = 18):
    return {"message": f"Hello {name}! I am {year} years old."}

結果

http://127.0.0.1:8000/name/mk419?year=10にアクセスすると、下記のようになります。

{"message":"Hello mk419! I am 10 years old."}

例4

POSTを使えるようにしたものです。

from fastapi import FastAPI
from pydantic import BaseModel

class Data(BaseModel):
    name: str
    year: int = 18

app = FastAPI()

@app.get("/")
async def root():
    return {"message": "Hello World!"}

@app.get("/name/{name}")
async def hello_name(name: str, year: int = 18):
    return {"message": f"Hello {name}! I am {year} years old."}

@app.post("/name")
async def hello_name_post(data: Data):
    return {"message": f"Hello {data.name}! I am {data.year} years old."}

結果

curl -X POST -H "Content-Type: application/json" -d '{"name":"mk419", "year": 10}' http://127.0.0.1:8000/name

例3と同じ結果になります。

解説

Fast APIはリクエストボディをPydanticで定義します。

型のチェックに引っかかるとエラーを吐いてくれます。

例5

チャットアプリ的な何かです。

from fastapi import FastAPI, WebSocket, WebSocketDisconnect
from fastapi.responses import HTMLResponse
from pydantic import BaseModel

HTML = """
<!DOCTYPE html>
<html>
<head>
    <title>Fast API</title>
</head>
<body>
    <form action="" onsubmit="sendMessage(event)">
        <label>Name: <input type="text" id="name" autocomplete="off" /></label>
        <hr>
        <label>Message: <input type="text" id="message" autocomplete="off" /></label>
        <button>Send</button>
    </form>
    <ul id="messageList">
    </ul>
    <script>
        let websocket = new WebSocket("ws://127.0.0.1:8000/websocket");

        websocket.onmessage = function (event) {
            let messageList = document.getElementById("messageList")
            let item = document.createElement("li")
            let content = document.createTextNode(event.data)

            item.appendChild(content)
            messageList.appendChild(item)
        };

        function sendMessage(event) {
            let name = document.getElementById("name")
            let message = document.getElementById("message")
            let data = {
                "name": name.value,
                "message": message.value
            };

            let json = JSON.stringify(data);

            websocket.send(json)
            message.value = ""
            event.preventDefault()
        }
    </script>
</body>
</html>
"""

app = FastAPI()
connection_list: list[WebSocket] = []
message_list: list[str] = []

class Data(BaseModel):
    name: str = "匿名"
    message: str

@app.get("/", response_class=HTMLResponse)
async def root():
    return HTMLResponse(HTML)

@app.websocket("/websocket")
async def websocket_connection(websocket: WebSocket):
    await websocket.accept()
    connection_list.append(websocket)

    for message in message_list:
        await websocket.send_text(message)

    try:
        while True:
            data = await websocket.receive_json()
            name = "匿名"  if data['name'] == "" else data['name']
            message = f"{name}: {data['message']}"
            message_list.append(message)

            for connection in connection_list:
                await connection.send_text(message)
    except WebSocketDisconnect:
        connection_list.remove(websocket)

色々ツッコミ所はあると思いますが、許してください()

結果

http://127.0.0.1:8000/にアクセスすると、下記のように動きます。

解説

HTML

<!DOCTYPE html>
<html>
<head>
    <title>Fast API</title>
</head>
<body>
    <form action="" onsubmit="sendMessage(event)">
        <label>Name: <input type="text" id="name" autocomplete="off" /></label>
        <hr>
        <label>Message: <input type="text" id="message" autocomplete="off" /></label>
        <button>Send</button>
    </form>
    <ul id="messageList">
    </ul>
    <script>
        let websocket = new WebSocket("ws://127.0.0.1:8000/websocket");

        websocket.onmessage = function (event) {
            let messageList = document.getElementById("messageList")
            let item = document.createElement("li")
            let content = document.createTextNode(event.data)

            item.appendChild(content)
            messageList.appendChild(item)
        };

        function sendMessage(event) {
            let name = document.getElementById("name")
            let message = document.getElementById("message")
            let data = {
                "name": name.value,
                "message": message.value
            };

            let json = JSON.stringify(data);

            websocket.send(json)
            message.value = ""
            event.preventDefault()
        }
    </script>
</body>
</html>

WebSocketを使用してサーバー側と通信しています。

Python

HTMLResponseでHTMLを返すことが出来ます。@app.getのresponse_classで返すレスポンスの型を指定します。

for message in message_list:
    await websocket.send_text(message)

初回アクセス時に過去のメッセージをクライアントに送信します。

for connection in connection_list:
    await connection.send_text(message)

送ったメッセージを現在接続中の全てのクライアントに送信します。

まとめ

今回はFast APIをちょっとだけ紹介しました。

今回は紹介しませんでしたが、SQLとの連携とかGraphQLの実装とか色々な用途で使えます。

自分はサーバーよわよわ人間なので、これぐらいの例しか挙げられませんでした()

Fast APIは良いぞ!!!

コメント

タイトルとURLをコピーしました