Cassandra + Python + FastAPIによるREST API開発実践ことはじめ

# はじめに

## Apache Cassandraについて

Apache Cassandraとは、一言でいうなら、オープンソースの分散データベース管理システムです。

他の分散データベース管理システム同様、複数の汎用サーバーを用いて、ひとつのデータベースを構築します（開発などの目的のため、一つのサーバーのみで構成することも可能です）。

ここでは、詳しい説明は割愛し、興味のある方へのご紹介の役割は、公式サイトやWikipediaに譲ります。

https://cassandra.apache.org/_/index.html

https://en.wikipedia.org/wiki/Apache_Cassandra


# Cassandra + Python + FastAPIによるREST API開発

この記事では、開発者が定義したテーブルへのCRUD操作をカバーするカスタムREST APIを開発します。

コードはこちらでも公開しています。

https://github.com/YoshiyukiKono/datastax-astra-python-fastapi

上記リポジトリ内の説明は英文で記しましたが、ここでは日本語で解説を記します。

## 前置き：DataStax Astra DBについて

このプログラムでは、接続先のCassandraデータベースとして、DataStaxが提供するDBaaSである、AstraDBを利用します。

DataStax AstraDBを利用する開発者は、AstraDBコントロールプレーン(のデータベースダッシュボードのコネクトタブ)で提供される具体的な手順に従って、 各種プログラミング言語からの接続を簡単に確認することができます。 そこで利用されているサンプルプログラムは、データベースへ接続しシステムテーブル(system.local)の情報表示までを行う、疎通確認用のものとなっています(例えばPythonの場合、`connect_database.py`という名称にも表れているように)。

なお、AstraDBは、Cassandraテーブルに対するCRUD操作のためのREST APIをデフォルトで提供します。 そのため、ここで扱うコードは一見、車輪の再発明のようにみえるかもしれません。 しかし、実プロジェクトにおいては必ずしもテーブルへのデータ操作そのものをAPIとして提供・利用するというケースばかりではなく、なんらかのビジネスロジックを伴うことが珍しくありません。 例えば、一つのAPIコールは、複数のテーブルに対する操作を含むかもしれません。 ここで提供しているコードは、特定のロジックこそ実装されていませんが、ビジネスロジックを伴うAPIを想定したシミュレーション、またはそのようなAPI開発のためのひな型として、考えることができます。

## 開発するもの

サンプルプログラムは、REST APIを提供します。
また、Open APIに準拠したWeb UIを提供します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/176567/4110b60d-d4ad-f08c-5dca-4b4ca957806c.png)

## 開発手順

## 準備

ここでは、AstraDB上で、データベースを作成済みであることを前提としています。

https://www.datastax.com/lp/astra-registration?redirect_uri=https://astra.datastax.com/welcome&

また、AstraDB コントロール プレーン (データベース ダッシュボードの [接続] タブ) で提供される手順をすでに把握されていることを前提としています。

上記の準備は、決して難しくないはずです。サインアップにクレジットカード情報の入力が求められることもありません。是非、利用してみてください。

また、データベースへの接続部分を別とすれば、OSSのApache Cassandraに応用することもできます。

## Python環境

Pythonの環境を用意します。ここでは、Windowsで作業した際の記録を示します。

```
conda create -n datastax -y python=3 pip
conda activate datastax
```

```
python --version
Python 3.10.4
pip --version
pip 21.2.4 from C:\Users\yoshi\Anaconda3\envs\datastax\lib\site-packages\pip (python 3.10)
```

## Pythonパッケージ

必要なパッケージをインストールします。

```
pip install fastapi
pip install uvicorn[standard]
```

```
pip install cassandra-driver
```

## データモデル

Cassandra(AstraDB)に以下のキースペースとテーブルを作成します。

### keyspace: `test`

### Table: `member`
```
CREATE TABLE test.member (
    id text PRIMARY KEY,
    first_name text,
    last_name text
) 
```


## コード

AstraDB コントロール プレーン (データベース ダッシュボードの [接続] タブ) で提供される指示に従って、以下のコード（`astra_main.py`）を編集してください。

```python
from fastapi import FastAPI
from pydantic import BaseModel

from cassandra.cluster import Cluster
from cassandra.auth import PlainTextAuthProvider

cloud_config= {
        'secure_connect_bundle': './exclude/secure-connect-<<YOUR DB NAME>>.zip'
}
auth_provider = PlainTextAuthProvider('<<CLIENT ID>>', '<<CLIENT SECRET>>')
cluster = Cluster(cloud=cloud_config, auth_provider=auth_provider)
session = cluster.connect()

app = FastAPI()

class Member(BaseModel):
    first_name: str
    last_name: str
    id: str

@app.get("/")
async def read_root():
    return {"Status": "On"}


@app.get("/members/{member_id}")
async def read_member(member_id: str):

    row = session.execute("select first_name, last_name from test.member where id = %s",[member_id]).one()

    if row:
        return {"member_id": member_id, "first_name":row[0], "last_name": row[1]}
    else:
        return {"member_id": member_id}

@app.put("/members/upsert/{member_id}")
def upsert_member(member_id: str, member: Member):

    session.execute("""
        insert into test.member (id, first_name, last_name)
        values (%s, %s, %s)
        """,
        (member_id, member.first_name, member.last_name)
    )
    return {"member_id": member_id}

@app.get("/members/delete/{member_id}")
async def delete_member(member_id: str):

    row = session.execute("delete from test.member where id = %s",[member_id]).one()

    return {"deleted": member_id}
```


## 利用法

下記のコマンドで実行します。

```
uvicorn astra_main:app --reload
```

次のリンクで確認します。 

http://127.0.0.1/8000/docs


# 最後に

CassandraとPythonの組み合わせによるREST APIの作成方法を見てきました。
FastAPIの詳細については、別途以下のドキュメントなどを参照いただければと思います。

CassandraとのCRUD処理部分のコーディングについて、今回紹介したサンプルコードを見ることでイメージを掴んでいただければ幸いです。

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