DB

DockerとMySQLとFastAPIの連携

MySQLをDockerコンテナ上に立てて、FastAPIからSQLAlchemyを使って接続します。

前回の記事でPostgreSQLで同じようなことをしましたが、Dockerを使うとローカルにインストールする必要がないので色々と楽になります。

前提として、dockerはインストール済みと想定しています。

まず初めに、dockerでMySQLのコンテナをpullしてきて起動させます。

データベース名とパスワードは任意でつけているので、変更したい方は変更して問題ありません。

docker run --name mysqldb -e MYSQL_DATABASE=test -e MYSQL_ROOT_PASSWORD=password -d -p 3306:3306 mysql:latest

エラーなく実行できたら、コンテナが立ち上がっているか確認しておきます。

docker ps

コンテナを立ち上げられたら、FastAPI側で必要なモジュールをインストールしていきます。

PostgreSQLの時と違うのはMySQL用のライブラリであるpymysqlが必要な点です。

MySQLに接続するためのドライバはいくつかありますが、現時点ではpymysqlが安定だと思います。

pip install pymysql sqlalchemy fastapi uvicorn

はじめに、MySQLと接続するための情報を書き込みます。

データベース名とパスワードを変更した方は適宜変更してください。

db.py

from sqlalchemy import create_engine, MetaData

engine = create_engine('mysql+pymysql://root:password@localhost:3306/test')
meta = MetaData()
conn = engine.connect()

続いて、テーブルを作成するためのクラスを定義していきます。

PostgreSQLの時と若干違う点(declarative_baseを使っていない)がありますが、こういった書き方もできるのでやり方はいくつかあります。

model.py

from sqlalchemy import Table, Column, Integer, String
from db import meta, engine

users = Table('users', meta,
              Column('id', Integer, primary_key=True, autoincrement=True),
              Column('name', String(255)),
              Column('email', String(255)),
              Column('password', String(255)))

meta.create_all(engine)

スキーマを別ファイルに定義しておくとテーブルが複数できてきた時とかに便利なので、こういった書き方にも慣れておいてください。

schemas.py

from pydantic import BaseModel

class User(BaseModel):
    name: str
    email: str
    password: str

いつも通りに、FastAPIのインスタンスを作ってエンドポイントを作成してもいいのですが、中規模以上のアプリケーションになった時に便利な記法で書いていきます。

fastapiをインポートしてインスタンス化するのではなく、APIRouterをインポートしてインスタンス化します。後は、いつも通りにエンドポイントを作成していきます。

user.py

from fastapi import APIRouter
from model import users
from db import conn
from schemas import User

user = APIRouter()

@user.get('/')
async def fetch_users():
    return conn.execute(users.select()).fetchall()

実際にアプリケーションとして起動するには、FastAPIのインスタンスが必要なので別途作成します。

そして、先程作成したエンドポイントを読み込んであげれば可読性が上がったコードを作成できます。

Djangoを触ったことがある方であれば似たようなコードになっているのが感じられるはずです。

main.py

from fastapi import FastAPI
from user import user

app = FastAPI()

app.include_route(user)

下記のコマンドでサーバーを立ち上げてみます。

uvicorn main:app --reload

もし次のようなエラーが出る場合には追加で暗号化ライブラリをインストールする必要があります。

RuntimeError: ‘cryptography’ package is required for sha256_password or caching_sha2_password auth methods

pip install cryptography

エラーがなくなれば、http://localhost:8000/ にアクセスしてみます。

次のように何も表示されなければMySQLと問題なく接続されています。

internal server errorが表示される場合には、コードを見直してください。

最後に、CRUD操作のエンドポイントを追加して終わります。

user.py

from fastapi import APIRouter
from model import users
from db import conn
from schemas import User

user = APIRouter()

@user.get('/')
async def fetch_users():
    return conn.execute(users.select()).fetchall()

@user.get('/{id}')
async def fetch_user(id: int):
    return conn.execute(users.select().where(users.c.id == id)).first()


@user.post('/')
async def create_user(user: User):
    conn.execute(users.insert().values(
        name = user.name,
        email = user.email,
        password = user.password
    ))

    return conn.execute(users.select()).fetchall()

@user.put('/{id}')
async def update_user(id: int, user: User):
    conn.execute(users.update().values(
        name = user.name,
        email = user.email,
        password = user.password
    ).where(users.c.id == id))

    return conn.execute(users.select()).fetchall()

@user.delete('/{id}')
async def delete_user(id: int):
    conn.execute(users.delete().where(users.c.id == id))
    return conn.execute(users.select()).fetchall()

swaggerUIから試して、動作するか試して見てください。

以上で、Dockerを使用したMySQLとFastAPIの連携について完成です。