Google Cloudの新DBMS、AlloyDB for PostgreSQLを触ってみた Vol.5

Google Cloudの新DBMS、AlloyDB for PostgreSQLを触ってみた Vol.5

まえがき

こんにちは。開発部の高井(Peacock)です。

今回はアプリケーション編として、より実際の利用例に近い形のものを紹介していきます。

(第1回よりテストデータとして使用している)英国不動産取引データを読み書きするWeb APIアプリケーションを作成してみました。

単純なCRUD操作のみを実装してみましたがPostgreSQL互換ということもあり、難なく実装出来たかと思います。

アプリケーション概要

使用したライブラリ・フレームワークについて

Python 3.11系をベースに構築しました。

WebフレームワークにFastAPI, ORMとしてSQLAlchemyを使用しています。今回、大規模ではないのでAlembicのようなマイグレーション用ツールは使用しませんでした。

ディレクトリ構成

gcloud.py としてGoogle Cloud SDKのヘルパーモジュールを置いていますが、それ以外は一般的な構成かと思います。

以下のようなディレクトリ構成にしています。パッケージ内は概ね責務で分割しています。

.
├── alloydb_demo     # FastAPI Webアプリケーションになるパッケージ
│  ├── __init__.py  # アプリケーションルート( app = FastAPI() モジュール)
│  ├── crud.py      # SQLAlchemyのクエリヘルパー(後述)
│  ├── db.py        # SQLAlchemyでデータベースセッションを作成するためのヘルパー
│  ├── gcloud.py    # AlloyDBへ接続するためGoogle Cloud SDKを使用したヘルパー(後述)
│  ├── models.py    # SQLAlchemyのモデル情報(今回は1テーブルのみ)
│  ├── routers.py   # FastAPIのルーティング関数群(エンドポイント一覧は後述)
│  └── schemas.py   # FastAPIが返すレスポンスのスキーマ定義
├── compose.yml      # Docker compose定義(後述)
├── constraints.txt  # 依存ライブラリのバージョン情報
├── Dockerfile       # FastAPI用Docker Image定義
├── entrypoint.py    # 起動時に実行するUvicorn(ASGIサーバー)とFastAPIの起動用スクリプト
├── pyproject.toml   # Pythonパッケージのメタデータ記述用
└── migrate.py       # SQLAlchemyでの簡単なマイグレーション用スクリプト

実際の動作例

FastAPIを使用しているのでSwagger UI( /docs )からテストなどが出来ます。以下のような画面になります。

エンドポイント一覧を確認できたので、実際にHTTPクライアント(今回はHTTPie)でテストしてみます。

まずはヘルスチェックでアクセスできることを確認します。

$ http get :8000/_genki
HTTP/1.1 200 OK
content-length: 27
content-type: application/json
date: xxx
server: uvicorn

{
    "code": 200,
    "message": "OK"
}

/list で取引のキーを取得してみます。取得できたキーのリストをコピーしておきます。

$ http get :8000/list?limit=5
HTTP/1.1 200 OK
content-length: 196
content-type: application/json
date: xxx
server: uvicorn

[
    "20e2441a-0f16-49ab-97d4-8737e62a5d93",
    "d893ee64-4464-44b5-b01b-8e62403ed83c",
    "f9f753a8-e56a-4ecc-9927-8e626a471a92",
    "e166398a-a19e-470e-bb5a-83b4c254cf6d",
    "a9a3c463-3ca0-4d71-8cf9-83b4d0536eea"
]

そのうちの1つを /read を叩いて詳細を取得してみます。

$ http get :8000/read/3311b7f4-5d50-43bc-90a6-83b6b7d522c8
HTTP/1.1 200 OK
content-length: 359
content-type: application/json
date: xxx
server: uvicorn

{
    "city": "NOTTINGHAM",
    "county": "NOTTINGHAMSHIRE",
    "district": "NOTTINGHAM",
    "duration": "F",
    "locality": "NOTTINGHAM",
    "newly_built": false,
    "paon": "11",
    "postcode": "NG5 9BJ",
    "ppd_category_type": "A",
    "price": "46000",
    "property_type": "D",
    "record_status": "A",
    "saon": null,
    "street": "SYKE ROAD",
    "transaction": "3311b7f4-5d50-43bc-90a6-83b6b7d522c8",
    "transfer_date": "1995-08-24"
}

/update で適当な値を入れて変更してみます。

$ echo '{
    "city": "NOTTINGHAM",
    "county": "NOTTINGHAMSHIRE",
    "district": "UPDATED DISTRICT",
    "duration": "F",
    "locality": "NOTTINGHAM",
    "newly_built": false,
    "paon": "11",
    "postcode": "NG5 9BJ",
    "ppd_category_type": "A",
    "price": "99000",
    "property_type": "D",
    "record_status": "A",
    "saon": null,
    "street": "SYKE ROAD",
    "transaction": "3311b7f4-5d50-43bc-90a6-83b6b7d522c8",
    "transfer_date": "1995-08-24"
}' | jq --indent 0 |
  http post :8000/update/3311b7f4-5d50-43bc-90a6-83b6b7d522c8
HTTP/1.1 200 OK
content-length: 365
content-type: application/json
date: xxx
server: uvicorn

{
    "city": "NOTTINGHAM",
    "county": "NOTTINGHAMSHIRE",
    "district": "UPDATED DISTRICT",
    "duration": "F",
    "locality": "NOTTINGHAM",
    "newly_built": false,
    "paon": "11",
    "postcode": "NG5 9BJ",
    "ppd_category_type": "A",
    "price": "99000",
    "property_type": "D",
    "record_status": "A",
    "saon": null,
    "street": "SYKE ROAD",
    "transaction": "3311b7f4-5d50-43bc-90a6-83b6b7d522c8",
    "transfer_date": "1995-08-24"
}

削除も /delete で実行してみます。

$ http delete :8000/delete/3311b7f4-5d50-43bc-90a6-83b6b7d522c8
HTTP/1.1 200 OK
content-length: 32
content-type: application/json
date: xxx
server: uvicorn

{
    "code": 200,
    "message": "Deleted"
}

同じキーで /read が404エラーになることも確認できます。

$ http get :8000/read/3311b7f4-5d50-43bc-90a6-83b6b7d522c8
HTTP/1.1 200 OK
content-length: 88
content-type: application/json
date: Fri, 18 Aug 2023 01:31:00 GMT
server: uvicorn

{
    "code": 404,
    "message": "Not found for transaction: 3311b7f4-5d50-43bc-90a6-83b6b7d522c8"
}

最後に削除したデータを /create で追加します。今回は自動生成キーと先程コピーしたキーの2種類のデータを追加してみます。

$ echo '[
        {
                "city": "GRAYS",
                "county": "THURROCK",
                "district": "THURROCK",
                "duration": "F",
                "locality": "GRAYS",
                "newly_built": true,
                "paon": "100000",
                "postcode": "RM16 4UR",
                "ppd_category_type": "B",
                "price": "50",
                "property_type": "D",
                "record_status": "A",
                "saon": null,
                "street": "HEATH ROAD",
                "transfer_date": "2023-08-17"
        },
        {
                "city": "NOTTINGHAM",
                "county": "NOTTINGHAMSHIRE",
                "district": "UPDATED DISTRICT",
                "duration": "F",
                "locality": "NOTTINGHAM",
                "newly_built": false,
                "paon": "11",
                "postcode": "NG5 9BJ",
                "ppd_category_type": "A",
                "price": "99000",
                "property_type": "D",
                "record_status": "A",
                "saon": null,
                "street": "SYKE ROAD",
                "transaction": "3311b7f4-5d50-43bc-90a6-83b6b7d522c8",
                "transfer_date": "1995-08-24"
        }
]' | jq --indent 0 |  \
  http put http://localhost:8000/create
HTTP/1.1 200 OK
content-length: 710
content-type: application/json
date: xxx
server: uvicorn

[
    {
        "city": "GRAYS",
        "county": "THURROCK",
        "district": "THURROCK",
        "duration": "F",
        "locality": "GRAYS",
        "newly_built": true,
        "paon": "100000",
        "postcode": "RM16 4UR",
        "ppd_category_type": "B",
        "price": "50",
        "property_type": "D",
        "record_status": "A",
        "saon": null,
        "street": "HEATH ROAD",
        "transaction": "1d60f8be-ceb5-4da1-ad97-de34dc8c2dbd",  // 生成されたキー
        "transfer_date": "2023-08-17"
    },
    {
        "city": "NOTTINGHAM",
        "county": "NOTTINGHAMSHIRE",
        "district": "UPDATED DISTRICT",
        "duration": "F",
        "locality": "NOTTINGHAM",
        "newly_built": false,
        "paon": "11",
        "postcode": "NG5 9BJ",
        "ppd_category_type": "A",
        "price": "99000",
        "property_type": "D",
        "record_status": "A",
        "saon": null,
        "street": "SYKE ROAD",
        "transaction": "3311b7f4-5d50-43bc-90a6-83b6b7d522c8",
        "transfer_date": "1995-08-24"
    }
]

まとめ

今回はPythonのORMであるSQLAlchemyで単純なCRUD操作を行うWeb APIを作成して、実際に動かしてみました。

他のRDBMSを使用したアプリケーションと同じように開発でき、不自由なく動かすことが出来ました。

他のORMでも使用でき、特にent(Go言語)では実際の案件での使用実績もあります。(ご興味あればお問い合わせください)

次回はこの連載の最後として、発展編としてPythonでStreamlitによるデータ分析アプリとしてのサンプルを紹介できればと思います。

関連記事

Contactお問い合わせ

Google Cloud / Google Workspace導入に関するお問い合わせ

03-6387-9250 10:00〜19:00(土日祝は除く)
Top