🥑

FastAPIを利用してAPIサーバを作る2- プロジェクトの作成-

2023/02/16に公開

この記事ではFastAPI を利用してAPIサーバを作る1 - 前提知識編-の内容で実装を進めて行くにあたり、ベースとなるFastAPIの初期プロジェクトを作成していきます。

プロジェクトの作成で行った作業一覧

  1. 開発環境および本番環境の環境構築方法の検討
  2. パッケージ管理の検討および導入
  3. プロジェクトフォルダ構成の検討

作業手順

1. 開発環境および本番環境の環境構築方法の検討

下記FastAPI公式ドキュメントに公式Dockerイメージを利用した環境構築方法の記載があるため基本的にそちらに沿って進めていきます。
https://fastapi.tiangolo.com/ja/deployment/docker/
プロジェクト作成用に任意のディレクトリを作成し、Dockerfileおよびdocker-compose.ymlを作成します。
デバック用のツールなど開発時には必要だが本番環境のDockerイメージには入れたくないものを分けつつ、本番および開発環境どちらにも必要なものは一元的に管理できるように、マルチステージングビルドを使用しています。
Dockerfileにはパッケージ管理ツールのインストールなども記載してますが、詳細については後続にて記載いたします。

  • Dockerfileの作成
# 本番・開発共通ベースステージ
FROM tiangolo/uvicorn-gunicorn-fastapi:python3.8 AS base

COPY . /app
WORKDIR /app/app
RUN pip install --upgrade pip
RUN pip install --upgrade poetry
RUN poetry config virtualenvs.create false
RUN poetry install --no-root

EXPOSE 80
ENV HOST=0.0.0.0
ENV PYTHONPATH "${PYTHONPATH}:/usr/local/lib/python3.8/site-packages"

# 開発環境用ステージ
FROM base AS develop

RUN pip install debugpy
ENV PYTHONDONTWRITEBYTECODE 1
ENV PYTHONUNBUFFERED 1

CMD ["python3", "-m", "debugpy", "--listen", "0.0.0.0:5678", "-m", "uvicorn", "main:app", "--reload", "--host", "0.0.0.0", "--port", "80", "--forwarded-allow-ips", "*"]

# 本番環境用ステージ
FROM base AS production

FastAPI公式ドキュメント推奨のDockerイメージを使用。「AS ~」と指定することにより別名を付与する

FROM tiangolo/uvicorn-gunicorn-fastapi:python3.8 AS base

ローカルのフォルダをイメージにコピーする。
コピー先については公式イメージに下記の通りのフォルダ構成となるよう記載されているためそれに従う。

COPY ./app /app
  • docker-compose.ymlの作成
version: "3.0"
services:
  # FastAPI
  api:
    container_name: "api"
    build: 
      context: .
      target: develop
    restart: always
    tty: true
    volumes:
      - .:/app
    ports:
      - 8008:80
      - 5678:5678
    env_file:
      - ./sample.env
    expose:
      - "5678"
  redis:
    image: "redis:latest"
    ports:
      - "6379:6379"

ローカルのappディレクトリ配下をイメージのappディレクトリは配下にマウントすることで、
開発時の新規ファイル作成や変更がリアルタイムにイメージに適用される。
ちなみにDockerfileのRUN、CMDとdocker-compose.ymlのvolumeの実行タイミングは

RUN → volumes → CMD

の順番で実行されるため、マウントしたファイルを対象に何か処理を実行する場合はRUNではなくCMDを使わないとファイルが存在しないためエラーになる

volumes:
  - ./app:/app

2. パッケージ管理の検討および導入

調べてみると、pythonパッケージ管理ツールの選択肢としてpip、Pipenv、poetryなどが選択肢として見つかり、色々な記事を見て比較しましたが、下記の点でpoetryにメリットを感じ、導入することにしました。

  1. pipだとpip install でパッケージ名で導入した際にrequirements.txtへの記載漏れまたはバージョン記載漏れが発生する。
  2. pipでのパッケージ間の依存関係解決は弱く、インストールの順序関係によってはエラーが発生する。
  3. Pipenvに比べて動作が高速

3. プロジェクトフォルダ構成の検討

.
├── app
│   ├── cruds
│   ├── logs
│   ├── models
│   ├── routers
│   ├── schemas
│   ├── util
│   ├── db.py
│   └── main.py
├── Dockerfile
├── docker-compose.yml
├── docker-compose.prod.yml
├── poetry.lock
├── Makefile
├── .env
└── pyproject.toml

FastAPIはDjungoやphpのLaravelなどのフレームワークと異なり、比較的プロジェクト構成の決まり事が少ないフレームワークのため、各プロジェクトによって自由に設計すれば良いかとは思いますが、今回は公式ドキュメントの構成をベースにしました。
変更点としては、既存のphpでのシステムを見返したときに、更なる拡張性が必要だったためappディレクトリ配下をディレクトリとして、ビジネスロジックごとにファイルを分けられる用にしています。

  1. mainファイル(app/main.py/)
    ルートディレクトリに作成し、FastAPIのエンドポイントにアクセスされた際に、最初に必ず実行される。
    Routerクラスをimportすることで、Routerクラスで定義したエンドポイントを公開できるようになる。

  2. Routerクラスディレクトリ(app/routers/)
    MVCで言うところのC(コントローラー)。エンドポイントの定義(URLなど)とDB操作以外の処理を書いていく。

  3. Modelクラスディレクトリ(app/models/)
    MVCで言うところのM(モデル)。DBテーブルからDBモデルクラスを作成するためのファイル群。

  4. CRUDクラスディレクトリ(app/cruds/)
    基本的にはルーターに処理を書くが、肥大化するのを避けるため、DB操作の処理はここに集約する。

  5. Shemaファイルディレクトリ(app/schemas/)
    APIの入出力のバリデーションを行う。APIのリクエストとレスポンスに型定義をする。

Discussion