【FastAPI】Pythonのバックエンドフレームワークを学ぶ①

# FastAPIとは？
バックエンドAPIの開発において以下の技術の有難さを痛いほど分かっている人にとっては今更感あります。
この記事はAPIを作った経験がない入門者に向けて、FastAPI[^1]の解説を分かりやすく書いています。
* Python decolator
* Hot Reload
* Swagger
* Dependency機能

### Python decolator
PythonのWebフレームワークでどこでも出てくるデコレータ。
以下のような`@app.<method>(path)`という見た目をしています。

```python
app = FastAPI()

@app.get("/post/")
def getPost(id):
    return {"id": id, "title": "A title has to be bold style."}
```

`@app.get`＝（`app`インスタンスの`get`メソッド）なのでその実装を辿ると、APIルートとしてラップされた関数を追加しているようです。つまり、`app`インスタンスはHTTPのメソッドとパスが一致している場合に、デコレータでラップされた関数を呼び出します。

https://github.com/tiangolo/fastapi/blob/master/fastapi/applications.py

:::note
Pythonのデコレータは単なる糖衣構文です。
関数内の処理結果や関数自体をトラッキングするための方法と考えておけば無難です。
::: 

最初は戸惑いますけどね・・・。

### Hot Reload
ReactやFlutterを触ったことのある人はその時の体験を思い出してみてください。
Hot Reloadはソースコードの変更箇所を検知して、変更前の情報をできるだけ保持したまま再読み込みができる機能です。開発段階で間違ったコードを書いたとしても、修正結果を素早く反映できます。

例えば、投稿型サービスを作る際に、ゲストには投稿権限をつけないとします。
この機能を実装するためには、以下のように現在のユーザに依存(Depends)させます。
```diff_python
from fastapi import Depends

@app.post("/post/")
- def addPost(title, content):
+ def addPost(title, content, current_user: User = Depends(get_current_user)):
      id = Post.add(title, content)
      return {"id": id}
```

この変更を行ってファイルを保存した際、現在ログインしていないユーザの投稿操作が即座にブロックされます。

:::note
IDEに付いてくるRunボタンは最初のステートに戻ってしまいますが、Hot Reloadはステートを保持できるので開発体験が向上します。
:::

### Swagger
SwaggerはAPIのPlayground兼ドキュメントだと思ってください。Gitbookなどのエンタープライズ向け文書化ツールにはAPIエンドポイント専用のテンプレートが存在しますが、自分で書き込む必要があります。

Swaggerでは定義したエンドポイントをすぐに確認できるのでとても便利です。こんな感じに見れるよ。
（とりあえず作ってる途中のやつをあげIとは？
バックエンドAPIの開発において以下の技術の有難さを痛いほど分かっている人にとっては今更感あります。
この記事はAPIを作った経験がない入門者に分かりやすく書いています。
* Python decolator
* Hot Reload
* Swagger
* Dependency機能

### Python decolator
PythonのWebフレームワークでどこでも出てくるデコレータ。
以下のような`@app.<method>(path)`という見た目をしています。

```python
app = FastAPI()

@app.get("/post/")
def getPost(id):
    return {"id": id, "title": "A title has to be bold style."}
```

`@app.get`＝（`app`インスタンスの`get`メソッド）なのでその実装を辿ると、APIルートとしてラップされた関数を追加しているようです。つまり、`app`インスタンスはHTTPのメソッドとパスが一致している場合に、デコレータでラップされた関数を呼び出す処理をします。

https://github.com/tiangolo/fastapi/blob/master/fastapi/applications.py

:::note
Pythonのデコレータは単なる糖衣構文です。
関数内の処理結果や関数自体をトラッキングするための方法と考えておけば無難です。
::: 

最初は戸惑いますけどね・・・。

### Hot Reload
ReactやFlutterを触ったことのある人はその時の体験を思い出してみてください。
Hot Reloadはソースコードの変更箇所を検知して、変更前の情報をできるだけ保持したまま再読み込みができる機能です。開発段階で間違ったコードを書いたとしても、修正結果を素早く反映できます。

例えば、投稿型サービスを作る際に、ゲストには投稿権限をつけないとします。
この機能を実装するためには、以下のように現在のユーザに依存(Depends)させます。
```diff_python
from fastapi import Depends

@app.post("/post/")
- def addPost(title, content):
+ def addPost(title, content, current_user: User = Depends(get_current_user)):
      id = Post.add(title, content)
      return {"id": id}
```

この変更を行ってファイルを保存した際、現在ログインしていないユーザの投稿操作が即座にブロックされます。

:::note
IDEに付いてくるRunボタンは最初のステートに戻ってしまいますが、Hot Reloadはステートを保持できるので開発体験が向上します。[^2]
:::

### Swagger
SwaggerはAPIのPlayground兼ドキュメントだと思ってください。Gitbookなどのエンタープライズ向け文書化ツールにはAPIエンドポイント専用のテンプレートが存在しますが、自分で書き込む必要があります。

Swaggerでは定義したエンドポイントをすぐに確認できるのでとても便利です。こんな感じに見れるよ。
（とりあえず見栄えが良さそうなものを）

![swaggerui_sample.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3243596/cdef372a-bb23-9867-0345-8b694694eea2.png)

##### Example Valueの参照元
型ヒントで指定します。

まずpydanticやtypingなどのスキーマを定義するモジュールをインポートしましょう。
```python
from pydantic import BaseModel, Field
from typing import List, Dict
```
次にBaseModelを継承しスキーマを定義します。
```python
class Timeline(BaseModel):
    similarityArray: List[int] = Field([],
                                       example=[1, 2],
                                       description='content ranking over the given query')
    dateArray: List[int] = Field([],
                                 example=[2, 1],
                                 description='content timeline')
    metadata: Dict[int, Metadata] = Field({}, example={1: Metadata()})
```

以下の関数において、返り値の型である`Timeline`は`BaseModel`を継承しているので、Swagger UIのExample Valueにスキーマのサンプル値が表示されます。

```python
@app.put("/v1/timeline/")
def get_timeline(query: TimelineQuery) -> Timeline:
    return Timeline()
```

::: note
FastAPIはスキーマや型をきっちり書くことを前提に設計されているような印象を受けます。[^3]
Swagger UIに説明を集約できるメリットはぜひ活用したいですね。
:::

### Dependency機能

新しいポストをデータベースからフェッチしたい場合、どうしたらよいでしょうか？
少し、情報を整理します。

* FastAPIのデコレータを使用すると、ポストを取得するエンドポイントを作成できます。
* 引数には、クエリパラメータを指定します。

では、データベースはどうやって関数に渡すのかというと、FastAPIの`Depends`クラスを利用します。
以下の関数では、ユーザとデータベースをAPIルートに依存させています。

```python
@app.get(path="/users/", tags=["Users"])
async def users(current_user: str = Depends(get_current_user),
                session: Session = Depends(get_db)):
    return User.getUserInfo(session, current_user)
```

こうすることで、

1. ログインが必要であること
2. データベース操作を含むこと

を明示でき、意図がつかみやすいソースコードになっています。

:::note
文字通り、Dependsクラスは依存対象を表現する手段だと考えてください。
:::

# 第一回のまとめ

✅ Pythonのデコレータは関数内の処理結果や関数自体をトラッキングするための表現方法の一つです。
✅ Hot Reloadはステートを保持できるので開発体験が向上します。
✅ 型やスキーマをきっちり書くことで、Swagger UIにドキュメントを集約できます。
✅ Dependsクラスは依存対象を表現する手段です。

[^1]: Pythonはデータサイエンスに強い言語だと言われていますが、バックエンドAPIを実装する言語としても全然いけると思います。
[^2]: FastAPIのHot Reloadは、より正確にはuvicornが担っている役割なので、ビルトインで実装されている機能ではないことに注意しましょう。
[^3]: Pythonは動的型付け言語ですが、型ヒントのニーズがある開発シーンにも対応できます。