AI

簡単3ステップ FAST APIで簡単にREST APIを構築しよう!

黄色が好きな広稀です。AMBLでシステムエンジニアをしています。
本記事では、Python 3.6 以降でAPI を構築するための、モダンで高速(高パフォーマンス)な、Web フレームワークであるFAST APIを用いて、簡単にREST APIを構築する方法を紹介します!この記事のREST APIの構築は中級者向けで、2時間位で作れるものとなっています!読み物としては約15分となります。

はじめに

本記事の対象者

  • Pythonを触ったことがある
  • curlコマンドを使ったことがある
  • REST APIを簡単に作ってみたい
  • REST APIの概要を既に知っている
  • Dockerで構築してみたい
  • Docker Composeをある程度は使ったことがある

本記事を作成する際に用いた開発環境

記載しているバージョンは記事作成当時(2022/07/09)のものです。

  • macOS 12.4
  • VSCode 1.69.0
  • Python 3.10.5
  • fastapi 0.78.0
  • MySQL 8.0.29
  • Docker 20.10.16
  • Docker compose 1.29.2

FAST APIとは

FastAPI は、API を構築するための、モダンで高速なWeb フレームワークです。
高速で、学習コストも低いため、手軽に導入することができます。
またSwagger UIで手軽に構築したAPIを試すこともできます。

この記事で構築するもの

この記事ではREST APIを用いてアイテム情報の新規作成、参照、更新、削除を行うことができるようなシステムを構築していきます。

環境構築

今回はDockerを用いて開発環境を構築します。

ファイル構成

ファイル構成は以下になります。

各ファイルはこのディレクトリ構成で配置してください。

├── docker-compose.yml
├── mysql
│   ├── conf
│   │   └── my.conf
│   ├── db
│   │   └── create_data.sql
└── src
    ├── Dockerfile
    ├── app
    │   ├── db.py
    │   ├── log
    │   ├── main.py
    │   └── model.py
    └── requirements.txt




Docker関連のファイル作成

FAST APIの説明なので、Docker関連の説明は省きます。

まずはdocker-compose.ymlファイルを作成します。

version: '3'
services:
  api:
    build: ./src
    container_name: api
    restart: always
    ports:
      - 8080:8080
    depends_on:
      - 'db'
    environment:
      - TZ=Asia/Tokyo

  db:
    image: mysql:oracle
    container_name: fastapi_mysql
    ports:
      - 3306:3306
    volumes:
      - ./mysql/conf/my.conf:/etc/mysql/conf.d/my.cnf
      - ./mysql/store:/var/lib/mysql
      - ./mysql/db:/docker-entrypoint-initdb.d
    environment:
      - MYSQL_ROOT_PASSWORD=root
      - MYSQL_USER=fastapi
      - MYSQL_PASSWORD=passw0rd
      - MYSQL_DATABASE=fastapi
      - TZ=Asia/Tokyo
    restart: always

Dockerfileを作成します。

FROM python:latest

WORKDIR /fast_api_app/src

COPY requirements.txt .
# コンテナ内で必要なパッケージをインストール
RUN pip install --no-cache-dir --trusted-host pypi.python.org -r requirements.txt

COPY app/main.py ./app/
COPY app/model.py ./app/
COPY app/db.py ./app/

ENV PYTHONPATH /fast_api_app

EXPOSE 8080
# FastAPIを8080ポートで待機
WORKDIR /fast_api_app/src/app
CMD ["uvicorn", "main:app", "--reload", "--host", "0.0.0.0", "--port", "8080"]

テーブルの初期データ(create_data.sql)を作成します。

CREATE TABLE fastapi.items
(
    id INT NOT NULL
    AUTO_INCREMENT,
    item_name text NOT NULL,
    created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
    updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON
    UPDATE CURRENT_TIMESTAMP,
    PRIMARY KEY
    (id)
);

-- サンプルレコード作成
INSERT INTO fastapi.items
    ( -- columns to insert data into
    item_name
    )
VALUES
    ( -- first row: values for the columns in the list above
        'item1'
),
    ( -- second row: values for the columns in the list above
        'item2'
),
    ( -- third row: values for the columns in the list above
        'item3'
);

my.confファイルを作成します。

[mysqld]
character-set-server=utf8

[mysql]
default-character-set=utf8

[client]
default-character-set=utf8

requrements.txtを作成します。

uvicorn
fastapi




DB関連の処理実装

db.pyを作成します。

ここにはDBに接続するための情報を書きます。

"""
create db transaction
"""
from sqlalchemy import create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import scoped_session, sessionmaker

host: str = 'db'
port: int = 3306
db_name: str = 'fastapi'
user = 'fastapi'
password = 'passw0rd'

uri = f'mysql://{user}:{password}@{host}:{port}/{db_name}?charset=utf8'
engine = create_engine(uri, encoding='utf8', echo=True)

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

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

model.pyの作成をします。

ここではテーブルの情報や、モデルを定義します。

"""
model.
"""
from datetime import datetime

from pydantic import BaseModel
from sqlalchemy import Column, DATETIME, FetchedValue, Integer, Text

from src.app.db import base


class ItemsTable(base):
    """
    table.
    """
    __tablename__ = 'items'
    id = Column(Integer, primary_key=True, autoincrement=True)
    item_name = Column(Text, nullable=False)
    created_at = Column(DATETIME, FetchedValue())
    updated_at = Column(DATETIME, FetchedValue())


class Item(BaseModel):
    """
    Item model.
    """
    id: int
    item_name: str
    created_at: datetime
    updated_at: datetime


class ItemCreate(BaseModel):
    """
    Item create
    """
    item_name: str

REST APIの実装

ここからは、FAST APIを用いてAPIを実装していきます。

  • 全てのItemを取得する処理
  • 1つのItemを取得する処理
  • Itemを新規作成する処理
  • 既にあるItemを更新する処理
  • 既にあるItemを削除する処理

これら5つの処理をmain.pyに実装していきます。

まずは前段で作成したDBやモデルのインポートを行います。

from fastapi import FastAPI

from src.app.db import session
from src.app.model import ItemCreate, ItemsTable

全てのItemを取得する処理は次になります。

@app.get("/items")
def get_items():
    """
    get all items
    :return:
    """
    items = session.query(ItemsTable).all()
    return items

1つのItemを取得する処理は次のようになります。

idを元に参照します。

@app.get("/items/{_id}")
def get_item(_id: int):
    """
    get an item.
    :param _id:
    :return:
    """
    item = session.query(ItemsTable).filter(ItemsTable.id == _id).first()
    return item

Itemを新規作成する処理は次のようになります。

@app.post("/items")
def create_item(item: ItemCreate):
    """
    create an item
    :param item:
    :return:
    """
    item_ = ItemsTable(item_name=item.item_name)
    session.add(item_)
    session.commit()
    item = session.query(ItemsTable) \
        .filter(ItemsTable.item_name == item.item_name) \
        .first()
    return item

既に存在するItemを更新する処理はこのようになります。

idを元に更新を行います。

@app.put("/items/{_id}")
def update_item(item: ItemCreate, _id: int):
    """

    :param item:
    :param _id:
    :return:
    """
    target_item: ItemsTable = session.query(ItemsTable) \
        .filter(ItemsTable.id == _id) \
        .first()
    target_item.item_name = item.item_name
    session.commit()
    new_item = session.query(ItemsTable) \
        .filter(ItemsTable.id == _id) \
        .first()
    return new_item

既に存在するItemを削除する処理はこのようになります。

idを元に削除を行います。

@app.delete("/items/{_id}")
def delete_item(_id: int):
    """
    delete item.
    :return: 
    """
    item = session.query(ItemsTable).filter(ItemsTable.id == _id).first()
    session.delete(item)
    session.commit()
    return item

実行してみよう!

docker-compose.ymlがあるディレクトリでDocker Composeのコマンドを実行します。

$ docker-compose up -d --build

以下が表示されたら、起動完了です。

Creating fastapi_mysql ... done
Creating api           ... done

http://localhost:8080/docs をブラウザで開きます。

すると、画像のようなページが表示されます。

右端の下三角をクリックします。

すると、メニューが展開されます。
表示された、「try it out」をクリックして「Execute」をクリックしてみましょう。
するとこのようなレスポンスが返ってきます(画面は一例で異なる場合があります)。

新規作成、更新、削除も実行してみてください。

【新規作成の実行結果】

【更新の実行結果】

【削除の実行結果】

まとめ

いかがでしたでしょうか!?
容易にREST APIを実装することができました。
Swagger UIがあるので、実行確認もwebページを開くことで
簡単に確認することができました。
次回の記事もお楽しみに!



あなたもAMBLで働いてみませんか?

AMBLは事業拡大に伴い、一緒に働く仲間を通年で募集しています。

データサイエンティスト、Webアプリケーションエンジニア、AWSエンジニア、ITコンサルタント、サービス運用エンジニアなどさまざまな職種とポジションで、自分の色を出してくださる方をお待ちしています。ご興味のある方は、採用サイトもご覧ください。

●AMBL採用ページ
-メンバーインタビュー (1日の仕事の流れ/やりがい/仕事内容)
-プロジェクトストーリー (プロジェクトでの実績/苦労エピソード)

●募集ページ
プリセールス/ エンジニア/ クリエイター/ データサイエンティスト /営業・コンサルタント /コーポレート /サービス企画 /教育担当

ABOUT ME
萱沼 広稀
Webアプリケーションエンジニア。 日々、新しい技術のキャッチアップに邁進しています!