FastAPI Tutorialメモ その1 インスト−ル


## はじめに
FastAPI Souce: https://github.com/tiangolo/fastapi
FastAPI Document: https://fastapi.tiangolo.com

Intro & First Step
FastAPIチュートリアルのメモ。
基本的にはFastAPIの公式チュートリアルを参考にしていますが、自身の学習のため一部分を省略したり順番を前後させています。
正しい詳細な情報は公式ドキュメントを参考いただければと思います。

Web & Python 初心者かつ翻訳はGoogleとDeepL頼りのため、間違い等ありましたらご指摘いただけますと幸いです。

## 開発環境
Ubuntu 20.04 LTS
Python 3.8.2
pipenv 2018.11.26

## 目標
1. [FastAPIのインストール](#FastAPIのインストール)
2. [サーバの起動](#サーバの起動)
3. [Swagger UIの確認](#Swagger-UIの確認)
4. [コードの確認](#コードの確認)

## FastAPIとは

FastAPIは、Pythonの型ヒントに基づいてAPIを構築するための高速・軽量・モダンなWebフレームワーク。
APIのオープンスタンダードであるOpenAPI(Swagger)とJSONスキーマに準拠しています。
詳しくは[公式ドキュメント](https://fastapi.tiangolo.com)をご確認ください。

## 手順

### FastAPIのインストール
FastAPIを`pip`を使用しインストールします。
以下のコマンドでFastAPIで使用するすべての依存関係と機能をインストールできるので、開発環境ではとりあえずこのコマンドでインストールしてみましょう。
サーバとして使用する`uvicorn`も一括でインストールできます。

```sh
$ pip install fastapi[all]

████████████████████████████████████████ 100%
```

pythonのインタラクティブシェルで確認してみます。

```sh
$ python
Python 3.8.2 (default, Apr 21 2020, 18:13:10) 
[GCC 5.4.0 20160609] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> 
>>> from fastapi import FastAPI
>>> 
```

エラーが表示されなければインストールは成功です。
また、私の環境ではpipenvを使用しているため、`pipenv install fastapi[all]`でインストールしましたが、今のところ問題はありません。

ここでは割愛しますが`fastapi`や`uvicorn`を別々にインストールすることも可能です。

### サーバの起動
FastAPIをインストールしたところで、さっそくサーバを起動してみましょう。

まず、`main.py`ファイルに簡単なFastAPIのコードを書きます。
(コードは基本的に公式ドキュメントから引用しています。[参考](#参考)をご確認ください。)

```python:main.py
from fastapi import FastAPI

app = FastAPI()


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

コードを保存したら、サーバを以下のコマンドで起動します。

```sh
$ uvicorn main:app --reload
```

以下のような表示が出力されればサーバが起動しています。

```sh

INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
INFO: Started reloader process [28720]
INFO: Started server process [28722]
INFO: Waiting for application startup.
INFO: Application startup complete.

```

出力に`INFO:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)`という行があります。
ローカルマシンでアプリが起動しているURL( http://127.0.0.1:8000 )とサーバの停止方法(Controlキー + C)を教えてくれているようです。

さっそく http://127.0.0.1:8000 をブラウザで表示してみましょう。
`main.py`の`root`関数の返り値(`return {"message": "Hello World"}`)が表示されるはずです。

![qiita_1_1 2020-07-12 17-03-29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/607514/064cb344-494f-346a-2c59-cb0efb29570a.png)

#### `uvicorn main:app --reload`について
- `main`は`main.py`ファイル(= Pythonモジュール)を参照
    - ファイル名は自由に設定することが可能です。`control.py`などに変更してみましょう。その場合はコマンドも変更する必要があります。
- `app`は`main.py`ファイル内の`app = FastAPI`で生成されたオブジェクトを参照
    - これもファイル名同様に自由に設定することが可能です。
- `--reload`はコードが変更するたびにサーバを再起動するためのオプションです
    - このオプションは開発環境でのみ使用することが推奨されています。

### Swagger UIの確認
FastAPIはOpenAPIに準拠にしており、[Swagger UI](https://fastapi.tiangolo.com/)によるインタラクティブなAPIドキュメントを自動生成してくれます。
http://127.0.0.1:8000/docs にアクセスして確認してみましょう。

![qiita_1_2 2020-07-12 17-15-44.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/607514/47a42442-0282-110f-19f8-1dc6cf051d22.png)

また、その他にもhttp://127.0.0.1:8000/redoc にアクセスすることで[ReDoc](https://github.com/Rebilly/ReDoc)によるドキュメントも確認できます。


### コードの確認
`main.py`の内容を確認してみましょう。このコードは、FastAPIの基本のコードとなっています。

#### FastAPIのインポート
まず、`FastAPI`クラスをインポートします。この`FastAPI`によって作成するAPIのすべての機能が提供されています。

```python
from fastapi import FastAPI
```

#### インスタンスの作成
次に、FastAPIのインスタンスとなる変数を作成します。この変数がFastAPIの実体となります。

```python
from fastapi import FastAPI

app = FastAPI()
```

ここで作成したインスタンス変数`app`が`uvicorn`コマンドのオプション`main:app`に対応しています。
もし、ファイル名を`control.py`、インスタンス変数を`my_instance = FastAPI()`とした場合は`uvicorn`コマンドは以下のようになるでしょう。

```sh
$ uvicorn control:my_instance --reload

INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
```

#### Path Operationの作成
ここでの**Path**とはURLの最後、ドメイン名とポート名以降の`/`から始まる部分を指します。
`https://example.com/items/foo`というURLの場合は`/items/foo`の箇所がFastAPIにおけるPathに該当します。

また、Pathは一般的な**endpoint**や**route**と同じ意味と思っても良いでしょう。
FastAPIでは、**Path**の役割は「API構築における"concerns"(関心)と"resource"(リソース)の分離」とされています。
プログラムを関心(目的、何をしたいか)という単位とリソース(資源、何を使用するか)という単位で分割するため、という意味でしょうか。詳しい方がいれば教えてください。

また、Path Operationの**Operation**はHTTPのメソッドと同義です。
主に使用されるメソッドは以下の通りです。

- POST: データの作成
- GET: データの読み込み
- PUT: データの更新
- DELETE: データの削除

HTTPはこれらのメソッドを使うことでWebサーバの各Pathと通信することができます。
APIを構築する際には、特定の処理を実行するためにこれらのHTTPメソッドを使用しています。

OpenAPIではHTTPメソッドは**operation**と呼ばれており、FastAPIでもそれにならって**operation**という用語が使用されています。

インスタンス変数を使用して **path operation decorator**を定義しましょう。

```python
from fastapi import FastAPI

app = FastAPI()


@app.get("/")

```

デコレータ関数`@app.get("/")`によって、FastAPIは以下のリクエストをすぐ下の関数を使用して処理することができます。

- **path**が`/`、かつ
- **operation**に`get`メソッドを使用

デコレータ関数については他の記事を参照してください。
ここでは、デコレータ関数の直下にある関数が**path`/`**に対応していることをFastAPIに伝えるため使用しています。また、このようなデコレータ関数を**path operation decorator(パス操作デコレータ)**と呼びます。

以下のように`get`以外のoperationも使用することができます。

- @app.post()
- @app.put()
- @app.delete()


#### path operation function(パス操作関数)の定義
コードの確認の最後に、パス操作関数の定義と戻り値の設定を行います。

path operation decorator(パス操作デコレータ)`@app.get("/")`によって処理の起点となるHTTPリクエストを定義することができました。
次に、処理を行う関数をデコレータのすぐ下に定義します。

```python
from fastapi import FastAPI

app = FastAPI()


@app.get("/")
async def root():
```

ここで使われるパス操作関数(`async def root():`)は通常のPython関数と変わりません。
クライアントが`get`operationでURL`/`へリクエストを送信し、サーバがそれを受信する度にFastAPIによってこの関数が呼び出されます。
( http://127.0.0.1:8000 にアクセスした際にも、この関数が呼び出されたいました。)

また、`async def`の代わりに通常の関数を定義することも可能です。

```python
from fastapi import FastAPI

app = FastAPI()


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

`async`(非同期処理)については[コチラ](https://fastapi.tiangolo.com/async/#in-a-hurry)の公式ドキュメントを参照してください。

後は`return`で返り値を設定すれば、最初のコードの確認は終了します。

```python
from fastapi import FastAPI

app = FastAPI()


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

返り値に関して、複数の値では`dict`や`list`、単数の値では`str`、`int`などの型で返り値を設定できます。
その他にも、`Pydantic`モデルを返すことも可能です。
以上の他にもJSONに自動変換されるオブジェクトやモデルは(ORMなども含めて)たくさんあるそうです。ぜひ調べてみてください。


## 終わりに OpenAPIについて

今回はFastAPIの公式チュートリアルのうち、[Intro](https://fastapi.tiangolo.com/tutorial/)と[First Steps](https://fastapi.tiangolo.com/tutorial/first-steps/)を取り上げました。
最後、OpenAPIとSchemaについての記述を取り上げます。

### OpenAPIとは
OpenAPIはREST APIを記述するためのフォーマットのことであり、SwaggerはOpenAPIを記述する際に使用することオープンソースのツールセットのこと。
以下の記事に簡単にまとめられていました。

- [OpenAPI (Swagger) 超入門](https://qiita.com/teinen_qiita/items/e440ca7b1b52ec918f1b)
- [What Is OpenAPI?](https://swagger.io/docs/specification/about/)

FastAPIでは、APIの定義がOpenAPIに準拠しており、すべてのAPIで"スキーマ"が生成されます。

#### スキーマとは
"スキーマ"とは何らかの定義や記述のことです。実装されたコードではなく、抽象的な概念を指しています。

##### APIスキーマ
APIにおける"スキーマ"を考える場合、OpenAPIは作成されたAPIのスキーマ定義の方法を規定する仕様になります。

このスキーマ定義には、APIへのパスやAPIが取得する可能性のあるパラメータなどが含まれます。

#### データスキーマ
"スキーマ"という言葉は、JSONコンテンツなどのような何らかのデータの形を指す場合もあります。

その場合は、JSONの属性やそれらが持つデータ型などを意味します。

#### OpenAPIとJSONスキーマの関係
OpenAPIは作成されたAPIの"APIスキーマ"を定義し、そのスキーマではJSONデータスキーマの標準である"JSONスキーマ"を使用してAPIが送受信するデータの定義(あるいは、その他の"スキーマ")が含まれています。

FastAPIでは、2種類のインタラクティブなドキュメントシステム(Swagger UI, ReDoc)を動かすためにOpenAPIスキーマを使用しています。

## 参考
[FastAPI 公式チュートリアル Intro](https://fastapi.tiangolo.com/tutorial/)
[FastAPI 公式チュートリアル First Steps](https://fastapi.tiangolo.com/tutorial/first-steps/)