スクリプトのお勉強

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

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

執筆者:

関連記事

PythonでAESを使用して暗号/復号する

1.つづき Pythonで、PKCS#12の公開鍵で暗号、秘密鍵で復号するプログラムの続きです。 今回はAESで暗号化/復号を行い、通信しながらRSA暗号/復号,AES暗号/復号を組み合わせたいと思い …

seaborn + Pandas + Python によるグラフ描画(その1: 準備編)

グラフ描画してみよう 今現在の仕事で、グラフ描画する可能性があるので、少し練習してみようと思います。 題材について 突然ですが、私は確定拠出型年金に加入しています。証券会社はSBI証券 にしています。 …

Selenium + Python によるアップロードアプリの動作確認プログラム作成

私の周りでは、なぜかSeleniumが流行っている模様です。 私自身は、Webアプリ的なのも作ってますが、あまり使ってなかったので、使ってみようと思います。 前回作成した、Djangoのupload_ …

unconstant – perlライブラリ

ちょっとだけperlの機能修正をしたので、そのときに使用したライブラリについて書こうと思います。 perlのunconstant です。 use constantの解除 use constantとは固 …

Pythonのmock.patchを使ってみる

単体テストによく使われるMockライブラリ Pythonで単体テストを行う際、実際のライブラリを使用してしまうと、実際の環境を用意しなければいけません。 例えば、データベースのテストをする際に、データ …