スクリプトのお勉強

fastapi + SQLAlchemy で CRUDアプリケーションを作ってみる

投稿日:2020年11月15日 更新日:

概要

勉強用に、PythonでPostgresqlを制御しようと思います。の続きです。

前回でPostgreSQLと、データベース/テーブルまでは用意したので、今回はAPIを作成しようと思います。

実行環境

実行環境は以下の通りです。

  • ubuntu 20.04
  • python 3.8
  • postgresql: v13
  • pipenv 2020.06

使用ライブラリ

以下をインストールしています。

pipenv install sqlalchemy
pipenv install Fastapi==0.61.2
pipenv install psycopg2==2.8.6
pipenv install fastapi-sqlalchemy
pipenv install pydantic[dotenv]

対象ソース

GitHubにあります。

ソース説明

以下がソース内容です。

|-- Pipfile
|-- Pipfile.lock
|-- README.md
|-- app
|   |-- run.py   <--------- ここから起動開始
|   |-- settings
|   |   `-- settings.py <-- 設定ファイル(.env)を読む
|   |-- urls.py  <--------- 受信するURLを記述
|-- layer
|   |-- __init__.py
|   |-- infra
|   |   |-- __init__.py
|   |   `-- db <-------- DB関連の内容
|   |       |-- __init__.py
|   |       |-- action.py  <--- CRUD処理を記述
|   |       |-- db.py      <--- engine
|   |       |-- models.py  <--- ORM
|   |       `-- schemas.py <--- 受送信のスキーマ
|   `-- present
`-- migration    <----- マイグレーション(yoyo-migrations)
    |-- migrations
    |   `-- 0001_create_addr.py
    `-- yoyo.ini

データベース環境の指定方法

.envファイルに置くことにしました。
.envに以下のように記述すると、アクセスできるようにしてあります。

DATABASE_URI = 'postgresql://testuser:testuserp@localhost/testdb'

起動

以下で起動します。

$ pipenv run uvicorn app.run:app --reload --host 0.0.0.0 --port 18000

SQLAlchemyの使用方法

大まかにSQLAlchemyの使い方は2つあります。

  • SQLAlchemy Core(主にSQLを素で使用する)
  • SQLAlchemy ORM(modelを作成し、modelで制御する)

また、使用する際は、以下のような考慮点を自分で組み合わせて開発する必要があります。

  • engine(DB接続先)をどのように管理するか
  • ORMの場合、modelをどのように作成するか
  • sessionをどのように管理するか

今回は、ORMを使用する方針にしました。

そして実質上”fastapi-sqlalchemy”にお任せになってしまいました。
今回のプログラムでは、以下のように使用しています。

DB(engine): layer/infra/db/db.py内で作成(DATABASE_URIもここで指定)する。
model: SQLAlchemy ORMを、layer/infra/db/models.pyで定義する。
session: “fastapi-sqlalchemy”内(DBSessionMiddleware)で作成する。session取得は以下のように行う。

from fastapi_sqlalchemy import db

fastAPI + SQLAlchemyの実現方法はいろいろあると思いますが、現時点では、これが一番お手軽な方法だと思います。

動作確認

作成は以下のようになります。

$ curl -X POST -H "Content-Type: application/json" -d '{"name":"ttttt83iksks", "addr":"100", "ipaddr":"192.168.0.0/16"}' http://localhost:18000/addrs/create

作成したデータは以下のように取得できます。

$ curl http://localhost:18000/addrs/find/4 | jq .
{
  "StatusCode": 200,
  "ErrorCode": "",
  "Result": {
    "update_time": "2020-11-15T14:29:15.784526+09:00",
    "create_time": "2020-11-15T14:29:15.784509+09:00",
    "addr": "100",
    "id": 4,
    "ipaddr": "192.168.0.0/16",
    "name": "ttttt83iksks"
  }
}

全体が以下です。

$ curl http://localhost:18000/addrs | jq .
{
  "StatusCode": 200,
  "ErrorCode": "",
  "Result": [
    {
      "update_time": "2020-11-15T14:15:58.246082+09:00",
      "create_time": "2020-11-15T14:15:58.246061+09:00",
      "addr": "100",
      "id": 1,
      "ipaddr": "192.168.0.0/16",
      "name": "ttttt83iksks"
    },
    {
      "update_time": "2020-11-15T14:23:10.404737+09:00",
      "create_time": "2020-11-15T14:23:10.404714+09:00",
      "addr": "100",
      "id": 2,
      "ipaddr": "192.168.0.0/16",
      "name": "ttttt83iksks"
    },
    {
      "update_time": "2020-11-15T14:26:29.539578+09:00",
      "create_time": "2020-11-15T14:26:29.539551+09:00",
      "addr": "100",
      "id": 3,
      "ipaddr": "192.168.0.0/16",
      "name": "ttttt83iksks"
    },
    {
      "update_time": "2020-11-15T14:29:15.784526+09:00",
      "create_time": "2020-11-15T14:29:15.784509+09:00",
      "addr": "100",
      "id": 4,
      "ipaddr": "192.168.0.0/16",
      "name": "ttttt83iksks"
    }
  ]
}

updateは以下の通りです。

$ curl -X POST -H "Content-Type: application/json" -d '{"id":4 , "name":"ttttt83iksks", "addr":"住んでいるところ", "ipaddr":"192.168.1.0/16"}' http://localhost:18000/addrs/update
{"StatusCode":200,"ErrorCode":"","Result":{}}
$ curl "http://localhost:18000/addrs/find/4" | jq .
{
  "StatusCode": 200,
  "ErrorCode": "",
  "Result": {
    "update_time": "2020-11-15T16:21:48.230994+09:00",
    "create_time": "2020-11-15T14:29:15.784509+09:00",
    "addr": "住んでいるところ",
    "id": 4,
    "ipaddr": "192.168.1.0/16",
    "name": "ttttt83iksks"
  }
}

削除は以下の通りです。

$ curl -X POST -H "Content-Type: application/json" -d '{"id":4}' http://localhost:18000/addrs/delete
{"StatusCode":200,"ErrorCode":"","Result":"delete success"}
$ curl "http://localhost:18000/addrs/find/4" | jq .
{
  "StatusCode": 200,
  "ErrorCode": "",
  "Result": null
}

OpenAPI(/docs)

この時点で自動作成した/docsは以下の通りです。

終わりに

APIを作成するだけなら結構簡単に作れました。
次は(出来たら) Nuxt.jsか何かで、これらAPIを使用して入出力を行う画面を作成したいと思います。

参考

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

https://qiita.com/t-iguchi/items/d01b24fed05db43fd0b8

-スクリプトのお勉強
-,

執筆者:

関連記事

Python3 – django-webtest

忙しいので断片だけ。。 DjangoでWebブラウザからアクセスする感じでテストする、やり方の一つです。以前にやったように、 Seleniumからやってもいいのすが、そこまでじゃない場合の単体テスト方 …

Pipenv vs Poetry

1. はじめに Pythonでお仕事していると、どうしても、環境設定を行う必要があります。 本番環境で動作するように、設定しなければいけないからです。 いろんな状況はあるでしょうが、私がかかわるプロジ …

svelteをチュートリアルしてみる

年末の休みは、svelteのチュートリアルをしてみました。なんとなくやはりそう?なので。 svelteとは Webアプリのフロントエンド(UI)用フレームワークです。要するにReactみたいなもんです …

SPAMチェック for OCN の開発

前回、Thunderbirdプラグインの概要を書いたので、今回は開発したプラグインについて書きます。 SPAMチェック for OCNとは 以下の機能を持ったThunderbirdのアドオン(プラグイ …

IPS/IDS(Suricata)のインストール

とても遅まきながら、暇なのでIPS/IDSをこのサイトに組み込んでみます。 Suricata SuricataというOSSのIPSがあるそうなのでインストールしてみます。 環境 CentOS7(7.9 …

google オプトアウト Click here to opt-out.