2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

ひとりでやれるかな?Advent Calendar 2022

Day 18

Python初心者がFastAPIでTodo(API)を作ってみた

Posted at

Python初心者がFastAPIでTodo(API)を作ってみた

前提

Python 3.9
FastAPI 0.88
sqlmodel
sqlite3

開発環境
MacBook + VScode

FastAPIについて

特徴

公式より引用

  • 高速: NodeJS や Go 並みのとても高いパフォーマンス (Starlette と Pydantic のおかげです)。 最も高速な Python フレームワークの一つです.
  • 高速なコーディング: 開発速度を約 200%~300%向上させます。
  • 少ないバグ: 開発者起因のヒューマンエラーを約 40%削減します。
  • 直感的: 素晴らしいエディタのサポートや オートコンプリート。 デバッグ時間を削減します。
  • 簡単: 簡単に利用、習得できるようにデザインされています。ドキュメントを読む時間を削減します。
  • 短い: コードの重複を最小限にしています。各パラメータからの複数の機能。少ないバグ。
  • 堅牢性: 自動対話ドキュメントを使用して、本番環境で使用できるコードを取得します。
  • Standards-based: API のオープンスタンダードに基づいており、完全に互換性があります: OpenAPI (以前は Swagger として知られていました)

インストール

pythonは3.9がインストール済みの前提

FastAPIのインストール

pip3 install fastapi

uvicornサーバ

  • httpdライブサーバ
    pip3 install "uvicorn[standard]"

sqlmodelのインストール

  • sqlite3のO/Rマッパー
    pip3 install sqlmodel

開発

初期DBの作成とコネクションクラスの作成

初期DBの作成

models/init.py

from datetime import datetime
from typing import Optional

from sqlmodel import Field, SQLModel, create_engine



class Todo(SQLModel, table=True):
    id: Optional[int] = Field(default=None, primary_key=True)
    content: str

    created_at: datetime = Field(default=datetime.utcnow(), nullable=False)
    updated_at: datetime = Field(default_factory=datetime.utcnow, nullable=False)


# DBへの接続を定義
sqlite_file_name = "todos.sql"
sqlite_url = f"sqlite:///{sqlite_file_name}" # エンジンデータベースのURL

engine = create_engine(sqlite_url, echo=True) # engineを作成
SQLModel.metadata.create_all(engine)  # モデルからテーブルを生成

DB接続クラス

models/db.py

from sqlmodel import create_engine

# DBへの接続を定義
sqlite_file_name = "todos.sql"
sqlite_url = f"sqlite:///{sqlite_file_name}" # エンジンデータベースのURL
engine = create_engine(sqlite_url, echo=True) # engineを作成

メイン処理

main.py

import json
from fastapi import FastAPI
from sqlmodel import Field, SQLModel, create_engine, Session, select
from pydantic import BaseModel
from datetime import datetime
from typing import Optional
import models.db as Db


#SQL MODEL
class Todo(SQLModel, table=True):
    id: Optional[int] = Field(default=None, primary_key=True)
    content: str
    created_at: datetime = Field(default=datetime.utcnow(), nullable=False)
    updated_at: datetime = Field(default_factory=datetime.utcnow, nullable=False)
    
#FORM MODELS
class TodoCreate(BaseModel):
    content: str

class TodoUpdate(BaseModel):
    id: int
    content: str

class TodoDelete(BaseModel):
    id: int


# main
app = FastAPI()

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

# select list
@app.get("/todos/")
async def todo_list():
    with Session(Db.engine) as session:
        stmt = select(Todo)
        results = session.exec(stmt)
        todos = []
        for todo in results:
            todos.append(todo)


    return {"todos": todos}

# select one
@app.get("/todos/{_id}")
async def todo_find(_id:int):
    with Session(Db.engine) as session:
        stmt = select(Todo).where(Todo.id == _id)
        todo = session.exec(stmt).first()

    return {"todo": todo}


# create
@app.post("/todo")
async def todo_create(todo :TodoCreate):
    with Session(Db.engine) as session:        
        todo = Todo(content=todo.content)
        session.add(todo)
        session.commit()

    return True


# update
@app.patch("/todo")
async def todo_update(todoUpdate :TodoUpdate):
    with Session(Db.engine) as session:
        stmt = select(Todo).where(Todo.id == todoUpdate.id)
        todo = session.exec(stmt).first()
        todo.content = todoUpdate.content
        session.add(todo)
        session.commit()
        #更新したレコードの取得
        stmt = select(Todo).where(Todo.id == todoUpdate.id)
        todo = session.exec(stmt).first()

    return todo


# delete
@app.delete("/todo")
async def todo_delete(todoDelete :TodoDelete):
    with Session(Db.engine) as session:
        stmt = select(Todo).where(Todo.id == todoDelete.id)
        todo = session.exec(stmt).first()
        session.delete(todo)
        session.commit()

    return True

動かしてみる

ライブサーバ(uvicorn)を起動
uvicorn main:app --reload

ソースを変更するとホットリロードされます。

Postmanで動作テスト

リストを取得する
todoを追加する
todoを更新する
todoを削除する

OpenAPIのドキュメントも自動生成される

ブラウザでドキュメントのURLにアクセスする
http://127.0.0.1:8000/docs

終わりに

FastAPIは軽くて小さなフレームワークだと思います。
プロトタイプなど、一時的にAPIを開発するには、簡単で軽い反面、いろいろやりたいことがある場合は、ライブラリをインストール必要があるかと思います。なので、依存関係などを管理するのは大変かもしれません。
ドキュメントやエコシステムが未発達なので、やりたいことを検索してもうまく情報が見つからない場合がある気がします。

プロダクションとかはDjangoとか実績のあるフレームワークのほうがいい気がします。

参考ページ

https://fastapi.tiangolo.com/ja/
https://zenn.dev/nameless_sn/articles/why_fastapi_development

2
0
0

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
2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?