fastAPI入門

# fastAPI is 何？
- python向けのAPIサーバー構築用ライブラリです。pythonでバックエンドを組むにはDjangoなどが有名ですが、fastAPIは以下のような特徴があります
    - 「**早い**」「**覚えやすい**」「**新しい**（最新python表記を使用）」 の三拍子
  - [参考（fastAPIの特徴）](https://shimi-dai.com/what-fastapi-merit-demerit/)
# この記事 is 何？
- 下記の書籍の内容（１～４章）をベースにfastAPIの使い方をまとめています（必要に応じて書籍外の情報も入れています）
【対象本】「Building Data Science Applications with FastAPI」
  - FastAPI本。ベースライブラリPydanticの使い方や一般的なWebサイト構築に必要な要素等を紹介。「OpenCVを使ったリアルタイム😇認識」など実用的なWebアプリが多いのもうれしいところ
  - 
https://learning.oreilly.com/library/view/building-data-science/9781801079211/


# fastAPI入門
## python環境構築
- 以下のパッケージを入れればfastAPIを使えるようになる
  - `pip install fastapi uvicorn[standard]`
- 動作確認用にHTTPieを使う
  - 他のREST APIツールでもOK
  - テストによる動作確認を行う場合はfastAPIの機能「[TestClient](https://fastapi.tiangolo.com/ja/tutorial/testing/)」を使うのが便利
## FastAPIの基本（RESTfulAPIの開発）
- 【[サーバー起動方法](https://www.uvicorn.org/#quickstart)】`uvicorn ソースファイル名:サーバー変数名 --host 0.0.0.0`
  - host指定しないとリモートからアクセスできない
  - `/docs` にAPIドキュメントページが自動作成される
- ルート変数も型ヒントを使ってサクッと指定可能
  ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/406339/612f2fbf-464b-7d25-944c-57be2d8c00a2.png)
  - 型指定にpythonのEnumクラスを指定すれば値をEnum要素に限定可能
  - `fastapi.Path` (初期値,条件)をルート変数初期値として入れればルート変数の値を制限可能
    - 引数例
        - lt,gt,le,ge (値域)
        - min_length,max_length (最小／最大値)
        - regex(正規表現)
- URLパラメータ
  - URL内に該当変数が無ければURLパラメータ扱いになる
  - PathではなくQuery()を使用。引数は`fastapi.Path`と似た感じ(どちらも内部でpydanticを使っているから)
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/406339/e299abca-5974-fc9a-1ec8-06f12807cd03.png)
- req body
  - Body()を使用（引数はPath()等と同じ）
- Pydantic
  - Path()/Query()/Body()など関数はいずれも内部でPydanticを使っている（型ヒントを拡張したデータチェック）
  - BaseModelによるフィールド定義(下図)
    - TypeScriptの型エイリアス風？
      ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/406339/7e02d5c4-d3e5-37cc-9a1b-dd678a47be3e.png)
- フォーム
  - Body()ではJsonを受け渡してたが、フォームからのエンコードデータを受け取る場合はForm()
- ファイルアップロード:File()
- ファイルアップロード(続き)
  - デフォルトだとアップロードファイルはメモリ内に格納される
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/406339/ce879d8b-9d2f-0529-00c8-460e7c6fc4f7.png)
  - bytesの代わりにUploadFile型ヒントを使うとpython通常のファイルと似た扱いのデータを取得できる(メタデータなどにアクセス可)
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/406339/13fc85b2-b223-0933-6700-8584d689dc11.png)
- HeaderとCookie
  - Header()とCookie()で指定可能(下図コードではクッキーは無指定)
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/406339/85fb347a-2df4-6346-a05b-878d47db2d79.png)
- Requestオブジェクト
  - Header/Cookie/Methodなど、リクエストに関するいろんなデータを取得できる
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/406339/41076110-52b9-c011-8a20-2d303f3561f7.png)
### Responseのカスタマイズ
- これまでは受け取ったオブジェクトをそのまま返していたが、ここからはカスタマイズして返す方法を紹介
- 状態コードの変更
  - postデコレータに引数status_codeを設定
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/406339/bec67a68-8438-4259-76ba-c41e792b80df.png)
    - レスポンス結果例
      ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/406339/9acb96d8-0a39-8b08-461b-5f5d9f7401f2.png)
  - 関数内で変更する場合はResponseオブジェクトのプロパティstatus_codeに設定
- エラーコードのraise
  - 関数内でエラーと判定した際に[HTTPException()](https://fastapi.tiangolo.com/tutorial/handling-errors/)によりエラーを発生
- Responseデータの種別
  - JSONResponse : Responseのサブクラス通常はシリアライズするデータをこれに入れるだけ
  - HTMLResponse : HTMLを返す場合はこちら
  - PlainTextResponse(生文字)
  - RedirectResponse(リダイレクト用)
  - StreamingResponse(ストリームバイトデータ)
  - FileResponse(自動でファイル返信用パスの生成)
- Responseクラスの使い方
  - メソッドデコレータの引数response_classに上記クラス指定
  - HTMLとPlainTextは文字列を返すだけ
  - RedirectはRedirectResponse(リダイレクト先)を返す
  - FileはFileResponse(返すファイルのローカルパス)を返す
  - それ以外にもカスタマイズしたデータをResponse()で返す事も可能
### 複数ルーターの設定
- [ルーターファイルを 複数用意し、アプリ側で統合可能](https://fastapi.tiangolo.com/tutorial/bigger-applications/)。
  - まず、ルーターファイルを複数作成（それぞれパスは"/"から指定)
  -  アプリ側で ”FastAPIインスタンス”.include_router(”importしたルーター”, prefix="/URLプレフィックス")
## pydanticデータモデル
### 概要
- ここまででFastAPI様々なRestAPI要求を処理する例を見てきた
- 以降、fastAPIの屋台骨でもあるpydanticモデル(BaseModelを継承したクラスによるデータ構造定義)について詳しい使い方を紹介する
  ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/406339/747c275c-cb06-a4da-b49b-649aa8aa0178.png)
- [復習] 基本はBaseModelを継承したクラスのメンバーに型ヒントを付けるだけ。型の自由度は高い（プリミティブ型だけでなくEnumやListやdateなども入れられる)
  - 違反したデータを入れるとエラーとともに違反した内容を返してくれる
- さらには、他のpydanicモデルをメンバーとして登録可能
  ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/406339/4aef8a54-c495-d7f0-4499-6b9ad66a7ed7.png)
- 必須ではないフィールドにはOptional型を指定
  - python3.10以降では[Union型ヒント(|表記)](https://fastapi.tiangolo.com/tutorial/extra-models/#multiple-models)でNoneと併記する方を推奨
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/406339/e9d96c6b-472d-0090-920a-6da47e5b2e0d.png)
- デフォルト値を設定することも可能
  - 当然ながらデフォルト値は初期化したタイミングの値を保持し続ける。動的に値を生成する方法は後述
- Field検証
  - 第3章ではAPI関数の引数の型ヒントで文字列長や値の検証を行ったが、モデルフィールドでField()を使って同様の検証を行う事が可能
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/406339/f87fd074-6c14-ef3e-6895-f6e6a321bb80.png)
  - Fieldで使える検証項目は[こちらを参照](https://pydantic-docs.helpmanual.io/usage/schema/#field-customisation)

- 動的なデフォルト値
  - Field(default_factory=関数) で指定可能
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/406339/5635ebf7-6ff1-18d8-705e-7d11f5946177.png)
- URLやEmailアドレス型
  - pydanticにはEmail文字列型(EmailStr)、URL文字列型(HttpUrl)があり手動でのsyntaxチェック不要
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/406339/da19ef78-df4a-d7c2-14a3-ac6fa8898970.png)

- 継承
  - 作ったpydanticモデルを継承し拡張可能

### カスタムデータ検証
- フィールド：Field()による簡易検証でなく独自の検証メソッドで検証可能(@ validator())
  ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/406339/78aba16c-05a5-2265-4100-ac5a6622c094.png)
- オブジェクト：@ root_validatorで受け取った複数の値を使って検証実施可能
  ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/406339/d449086c-adb3-b1c5-58ac-14e219a58bc1.png)
### Pydanticオブジェクト操作
- インスタンス.dict()で辞書に変換可能
  - .dict(include={含めるフィールド名}) や
     .dict(exclude={除外するフィールド名}) なども可能
- 一部のフィールドのみ送信未送信フィールドは更新しない）ことも可能（詳細省略）
# まとめ
- 本記事のもととなった書籍以外の参考書籍としては、Zennの「[fastAPI入門](https://zenn.dev/sh0nk/books/537bb028709ab9)」がいい感じにまとまっています
- この記事で書かれている項目で以外のfastAPIの機能としては「[依存性注入](https://python-dependency-injector.ets-labs.org/examples/fastapi.html)(5章)」「[テスト機能(TestClient)](https://zenn.dev/sh0nk/books/537bb028709ab9/viewer/d3f074)(9章)」などがあります。