215
239

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

FastAPIを用いたAPI開発テンプレート

Last updated at Posted at 2023-10-13

はじめに

FastAPIはPythonのWEBフレームワークで、同じ分類のフレームワークとしてFlaskやDjangoなどが挙げられます。FlaskとDjangoはよく比較され、Flaskが最小限のコードで書き始められるシンプルなマイクロフレームワークと呼ばれるのに対し、Djangoはログイン機能、データベース管理などが初めから備わっておりフルスタックフレームワークと呼ばれています。

FastAPIはFlaskと似ているマイクロフレームワークで公式ドキュメントでは次のように紹介されています。FastAPI は、Pythonの標準である型ヒントに基づいてPython 3.6 以降でAPI を構築するためのモダンで高速(高パフォーマンス)な、Web フレームワークです。[1]

本記事では、以下の内容を扱います。

  • 特徴である型ヒントとそれにより実現できるAPIドキュメントの自動生成
  • SQLAlchemyを用いたデータベース操作
  • alembicを用いたデータベースマイグレーション

以上の内容を、GitHubが提供するクラウド開発環境Codesapceで行います。GitHubアカウントがあれば無料で、クレジットカード登録不要です。内容は違いますが、Codesapceについては以下の記事で扱っています。

開発環境の起動

CodesapceのPython環境テンプレートにアクセスします。そしてUser this templateからOpen in a codespaceを選択します。

image.png

すると以下の様にブラウザでVSCode互換の環境が起動します。詳細は解説しませんが、今回の記事で扱う内容はこの環境で実行することができます。

image.png

個人的にダークテーマに変更しています。以降、記事のスクリーンショットはダークテーマとなっています。

image.png

FastAPIのインストール

Codesapceの下部にあるターミナルで以下のコマンドを実行します。以降、コマンドの実行はこちらで同様に実行していきます。

pip install "fastapi[all]"

FastAPI hello world

既にあるapp.pyファイルを編集します。

image.png

コードは以下になります。

from fastapi import FastAPI
import uvicorn

app = FastAPI()


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

if __name__ == "__main__":
    uvicorn.run(app, host="0.0.0.0", port=8000, log_level="debug")

FastAPIを起動します。

python3 app.py

すると右下にポップアップが表示されるのでブラウザで開くを選択します。

image.png

ブラウザの別タブで動作を確認できます。

image.png

データベースの利用

サンプルアプリとしてToDoアプリを扱います。

必要なパッケージをインストール。

pip install alembic SQLAlchemy

データベースの管理情報を初期化します。

alembic init migrations

今回はMySQLなどのデータベースサーバなどを用いずに、単一ファイルでデータベースを扱えるSqliteを利用します。alembic.inisqlalchemy.urlを以下の様に編集します。

sqlalchemy.url = sqlite:///sample.sqlite

settings.pyを作成しデータベースの接続情報などを記載します。

from sqlalchemy import create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker

SQLALCHEMY_DATABASE_URL = 'sqlite:///sample.sqlite'

engine = create_engine(
    SQLALCHEMY_DATABASE_URL, connect_args={"check_same_thread": False}
)
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)

Base = declarative_base()

models.pyを作成し、データベースのテーブルを定義します。idは数値でプライマリーキーとし、titleは文字列型としています。

from sqlalchemy import Column, Integer, String, DateTime
from datetime import datetime
from settings import Base


class TodoModel(Base):
    __tablename__ = 'todo'

    id = Column(Integer, primary_key=True)
    title = Column(String)
    created_date = Column(DateTime, default=datetime.utcnow)

migrations/env.pyを以下のように編集し、定義したモデルをAlembicに伝えます。

1 既にあるimport文の下に以下を追加する。

from settings import Base
from models import *

2 target_metadataグローバル変数を以下のように編集する。

target_metadata = Base.metadata

Pythonコードで定義したモデルを元に、テーブルやカラムをデータベースに作成するコードを生成します。

alembic revision --autogenerate -m "create todo table"

実行すると、migrations/versions/XXXXXXXXXXXX_create_todo_table.pyが生成されます。以下の様に、テーブルを作成し、カラムを追加するコードが確認できます。

def upgrade() -> None:
    # ### commands auto generated by Alembic - please adjust! ###
    op.create_table('todo',
    sa.Column('id', sa.Integer(), nullable=False),
    sa.Column('title', sa.String(), nullable=True),
    sa.Column('created_date', sa.DateTime(), nullable=True),
    sa.PrimaryKeyConstraint('id')
    )

以下のコマンドを実行してデータベースに上記のコードを適用させます。

alembic upgrade head

エンドポイントの作成

app.pyを以下の様に編集します。それぞれどのような処理を行っているかはコメントに記載しています。

from fastapi import FastAPI, Depends
import uvicorn

from schemas import PostTodo
from models import TodoModel
from settings import SessionLocal

from sqlalchemy.orm import Session


app = FastAPI()

def get_db():
    db = SessionLocal()
    try:
        yield db
    finally:
        db.close()


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


# データベースからToDo一覧を取得するAPI
@app.get("/todo")
def get_todo(
        db: Session = Depends(get_db)
    ):
    # query関数でmodels.pyで定義したモデルを指定し、.all()関数ですべてのレコードを取得
    return db.query(TodoModel).all()

# ToDoを作成するAPI
@app.post("/todo")
def post_todo(
        todo: PostTodo, 
        db: Session = Depends(get_db)
    ):
    # 受け取ったtitleからモデルを作成
    db_model = TodoModel(title = todo.title)
    # データベースに登録(インサート)
    db.add(db_model)
    # 変更内容を確定
    db.commit()

    return {"message": "success"}

# ToDoを削除するAPI
@app.delete("/todo/{id}")
def delete_todo(
        id: int,
        db: Session = Depends(get_db)
    ):
    delete_todo = db.query(TodoModel).filter(TodoModel.id==id).one()
    db.delete(delete_todo)
    db.commit()

    return {"message": "success"}


if __name__ == "__main__":
    uvicorn.run(app, host="0.0.0.0", port=8000, log_level="debug")

ブラウザからデータを受け取る型を定義するためschemas.pyを作成します。

from typing import List, Optional
from pydantic import BaseModel


class PostTodo(BaseModel):
    title: str

動作確認とAPIドキュメントの自動生成

FastAPIを起動します。

python3 app.py 

ブラウザを開き、https://○○○○.app.github.dev/docsにアクセスします。するとFastAPIの特徴である自動生成されたAPIドキュメントを開くことができます。

image.png

このページでは簡単にAPIを試すことができます。ToDoを作成してみます。Request body内に、予め用意されてるサンプルデータを書き換え、ToDoのタイトルを記入します。ExceuteをクリックするとAPIを実行できます。

image.png

作成したToDoを取得してみます。GETメソッドの/todoを実行します。先ほど作成したタイトルが取得できていることを確認できます。

image.png

ToDoの削除に関しても確認します。idを指定してToDoを削除できます。

image.png

おわりに

FastAPIを用いて以下の機能を利用しました。これらの機能は様々なプロジェクトで利用するかと思います。

  • 特徴である型ヒントとそれにより実現できるAPIドキュメントの自動生成
  • SQLAlchemyを用いたデータベース操作
  • alembicを用いたデータベースマイグレーション

本記事で作成したファイル群をテンプレートとして活用するとMock作成など素早く実施できるかと思います。特に自動生成されたAPIドキュメントは、WEBダッシュボードを提供し、APIを試すことができるため、開発効率の向上も期待できます。

参考

215
239
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
215
239

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?