🐍

【phython】FastAPI作成

2022/08/21に公開

はじめに

記事を書くのがずいぶん久しぶりになってしまった。
週に一回は記事を書くと決めていたのだが、怠けてしまった。まとめて書こうとしているとついつい先延ばしにしがちです。

今週からは週に一回書くようにします

内容

前回記事を書いたのはだいぶ前になるが、以前の意地ではDBの作成について書きました。
今回は、作ったDBから APIを作るところになる。

結論としては以下のライブラリを使用することにした。

https://fastapi.tiangolo.com/ja/

Docker

フォルダ階層

-- mysql
   ∟ data
   ∟ init.d
   ∟ my.cnf
-- pyhon
   ∟ src
   ∟ Dockerfile
-- root
docker-compose.yml

docker-compose.yml

version: "3.9"
services:
  python3:
    restart: always
    depends_on:
      - db
    build:
      context: ./python
    container_name: "python3"
    ports:
      - "8000:8000"
    volumes:
      - ./python/src:/python
  db:
    image: mysql:latest
    container_name: db
    environment:
      - MYSQL_DATABASE=python_sample
      - MYSQL_USER=docker
      - MYSQL_PASSWORD=docker
      - MYSQL_ROOT_PASSWORD=docker
    volumes:
      - ./mysql/data:/var/lib/mysql
      - ./mysql/my.cnf:/etc/mysql/conf.d/my.cnf
      - ./mysql/init.d:/docker-entrypoint-initdb.d
    ports:
      - target: 3306
        published: 3306
        protocol: tcp
        mode: host
    command: --port 3306
    tty: true

Dockerfile(python)

Dockerfile
FROM python:3.7

WORKDIR /python
ADD requirements.txt .
RUN pip install -r requirements.txt

CMD ["uvicorn", "main:app", "--reload", "--host", "0.0.0.0", "--port", "8000"]
requirements.txt
uvicorn
fastapi
mysqlclient
sqlalchemy

pyhonの内容

まぁ、 Fast APIの公式サイトにも書いてあるがHTTPメソッドごとに機能を切り分けているっぽいです。
HTTPメソッドについては以下の記事をご確認ください。

https://qiita.com/wim/items/dbb6def4e207f6048735

超簡単にいうと以下の表な感じだ。

HTTPメソッド 内容
Get 取得
Post 登録
Put 更新
Delete 削除

まずはSQL接続情報を定義します。(docker-composeで定義した内容)

db.py
from sqlalchemy import create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker, scoped_session

host = "db:3306"
db_name = "python_sample"
user = "docker"
password = "docker"

DATABASE = 'mysql://%s:%s@%s/%s?charset=utf8' % (
    user,
    password,
    host,
    db_name,
)

ENGINE = create_engine(
    DATABASE,
    encoding="utf-8",
    echo=True
)

session = scoped_session(
    sessionmaker(
        autocommit=False,
        autoflush=False,
        bind=ENGINE
    )
)

Base = declarative_base()
Base.query = session.query_property()

次に、SQLで定義されたテーブル構造をPythonのモデルとして再定義します。

model.py
from sqlalchemy import Column, Integer, String
from pydantic import BaseModel
from db import Base
from db import ENGINE

# テーブル定義
class TestUserTable(Base):
    __tablename__ = 'test_user'
    id = Column(Integer, primary_key=True, autoincrement=True)
    name = Column(String(30), nullable=False)
    email = Column(String(128), nullable=False)

# モデル定義 
class TestUser(BaseModel):
    id: int
    name: str
    email: str


def main():
    # テーブル構築
    Base.metadata.create_all(bind=ENGINE)


if __name__ == "__main__":
    main()

最後にAPIを書きます。

main.py
from fastapi import FastAPI
from db import session
from model import TestUserTable, TestUser

app = FastAPI()

# ユーザー情報一覧取得
@app.get("/test_users")
def get_user_list():
    users = session.query(TestUserTable).all()
    return users


# ユーザー情報取得(id指定)
@app.get("/test_users/{user_id}")
def get_user(user_id: int):
    user = session.query(TestUserTable).\
        filter(TestUserTable.id == user_id).first()
    return user


# ユーザ情報登録
@app.post("/test_users")
def post_user(user: TestUser):
    db_test_user = TestUser(name=user.name,
                            email=user.email)
    session.add(db_test_user)
    session.commit()


# ユーザ情報更新
@app.put("/test_users/{user_id}")
def put_users(user: TestUser, user_id: int):
    target_user = session.query(TestUserTable).\
        filter(TestUserTable.id == user_id).first()
    target_user.name = user.name
    target_user.email = user.email
    session.commit()

実行してみた。

実行
# curl -X 'GET'     'http://localhost:8000/test_users'     -H 'accept: application/json'
結果
[{"email":"tanaka.taro@example.com","id":1,"name":"tanaka taro"},{"email":"yamada.hanako@example.com","id":2,"name":"yamada hanako"}]

最後に

あとはポーリングしてDBに突っ込む処理を掛ければ一通り実装が出来そうである。
モチベーションを下げずに来週も書こうかと思います。

Discussion