データを保存するFastAPIアプリを公開するときは、APIを動かすサーバーに加えて、保存先も用意します。PostgreSQLを使う構成なら、URLへアクセスできても、DBにつながっていなければ保存はできません。アプリ内の一時ファイルへ保存していると、再デプロイでデータを失うこともあります。
この記事では、短いメモを保存・一覧表示するAPIを作り、起動・DB接続・保存を順に確認します。公開先の具体例には、東京リージョンのPaaSであるKamuiDashを使います。要点は、依存関係の準備、テーブルの初期化、APIの起動を分けることです。
サンプルはソース一式をダウンロードできます。PythonのコードとGitの基本操作が分かる方を想定しています。手順の確認には実在の個人情報を使わず、短いテスト用メモだけを保存してください。
この記事の内容
APIを動かす場所と、データを残す場所を分ける
FastAPIはリクエストを受けて処理し、PostgreSQLがメモを保存します。ブラウザやクライアントからDBへ直接つなぐ構成にはしません。
アプリ内の変数はプロセスの終了で消えます。KamuiDashのアプリのディスクも一時領域なので、再起動やデプロイをまたいで残したいデータはDBへ、アップロード画像などはオブジェクトストレージへ保存します。料金・仕様の「一時ディスク」の説明も確認してください。
ここでは1アプリ・1プロセスの小さな例に絞ります。初期化用のSQLは用意しますが、既存テーブルの変更を追跡する仕組みは含みません。機能を継続して増やす段階ではAlembicなどによるマイグレーション管理へ進めます。
最小のFastAPIサンプルを用意する
ダウンロードしたフォルダーには、次のファイルが入っています。GitHubには、このフォルダーの中身をリポジトリのルートとして保存する想定です。
requirements.txt Pythonパッケージ
main.py APIと起動処理
init_db.py 初回のテーブル作成
.gitignore .envなどの除外
依存関係をrequirements.txtに固定する
fastapi==0.128.8
uvicorn==0.39.0
psycopg[binary]==3.2.13
FastAPIはAPI、UvicornはHTTPサーバー、PsycopgはPostgreSQLへの接続に使います。掲載版の組み合わせでローカル確認しています。将来更新するときは、バージョンを変えた後に保存・読み取りまで再確認してください。
PORTを使って起動し、保存APIには認証を付ける
import hmac
import os
from typing import Optional
import psycopg
import uvicorn
from fastapi import Depends, FastAPI, Header, HTTPException
from pydantic import BaseModel, Field
from psycopg.rows import dict_row
app = FastAPI(title="Small Notes API")
def connection():
# Context managers commit on success, roll back on error, and close.
return psycopg.connect(os.environ["DATABASE_URL"], connect_timeout=5,
row_factory=dict_row)
def authorize(authorization: Optional[str] = Header(default=None)):
token = os.environ.get("DEMO_API_TOKEN", "")
if not token:
raise HTTPException(status_code=503, detail="API token is not configured")
expected = "Bearer " + token
if not hmac.compare_digest((authorization or "").encode(), expected.encode()):
raise HTTPException(status_code=401, detail="Authentication required")
class Note(BaseModel):
body: str = Field(min_length=1, max_length=500)
@app.get("/healthz")
def health():
return {"ok": True}
@app.get("/readyz", dependencies=[Depends(authorize)])
def ready():
with connection() as conn:
conn.execute("SELECT 1")
return {"database": "ok"}
@app.get("/notes", dependencies=[Depends(authorize)])
def list_notes():
with connection() as conn:
return conn.execute("SELECT id, body FROM notes ORDER BY id DESC LIMIT 50").fetchall()
@app.post("/notes", status_code=201, dependencies=[Depends(authorize)])
def create_note(note: Note):
with connection() as conn:
return conn.execute("INSERT INTO notes (body) VALUES (%s) RETURNING id, body",
(note.body,)).fetchone()
if __name__ == "__main__":
uvicorn.run("main:app", host="0.0.0.0", port=int(os.getenv("PORT", "8000")))
0.0.0.0で待ち受け、プラットフォームから渡されるPORTを読みます。127.0.0.1だけで待ち受けると、アプリの外から接続できません。KamuiDashのPython設定でも、PORTの利用とセットアップコマンドの明示が案内されています。
/healthzはAPIプロセスの応答だけを確認します。DBへの接続は認証付きの/readyzで別に確認します。こうすると、サーバーが起動しないのか、DBが使えないのかを分けて調べられます。
この例は1つの共通トークンを使う学習用APIです。利用者ごとのアカウントや権限管理はありません。一般利用者向けに公開する場合は、用途に合う認証とレート制限を加えてください。トークンをブラウザ配信するJavaScriptへ書き込んで秘密を保つことはできません。
初回作成用のSQLを分ける
from main import connection
with connection() as conn:
conn.execute("""
CREATE TABLE IF NOT EXISTS notes (
id bigint GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
body text NOT NULL CHECK (length(body) BETWEEN 1 AND 500)
)
""")
print("notes table is ready")
IF NOT EXISTSなので、同じスクリプトを再実行しても既存のメモは削除しません。ただし、テーブルが存在するときに列の定義を更新する機能もありません。既存のDBへ流用せず、専用の空DBから始めます。
ローカルで保存と読み取りを確認する
まず、自分が用意したローカルPostgreSQLに、サンプル専用の空DBを作成します。以下の接続先・ユーザー名は例です。外部の本番DBをこの動作確認に使う必要はありません。
python3 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
export DATABASE_URL='postgresql://demo_user:local_password@127.0.0.1:5432/notes_demo'
export DEMO_API_TOKEN='local-demo-only-change-before-publication'
python init_db.py
python main.py
別のターミナルでも同じDEMO_API_TOKENを設定し、次を実行します。
curl --fail http://127.0.0.1:8000/healthz
curl --fail http://127.0.0.1:8000/readyz \
-H "Authorization: Bearer $DEMO_API_TOKEN"
curl --fail http://127.0.0.1:8000/notes \
-H "Authorization: Bearer $DEMO_API_TOKEN" \
-H 'Content-Type: application/json' \
-d '{"body":"最初の保存テスト"}'
curl --fail http://127.0.0.1:8000/notes \
-H "Authorization: Bearer $DEMO_API_TOKEN"
保存時はHTTP 201、一覧はHTTP 200で、保存した本文を含むJSONが返る想定です。認証ヘッダーを外した/notesへのアクセスは401になります。DBの接続URLやトークンをログに出さずに、ここまで確認してからGitHubへ保存します。
KamuiDashでDBとPythonアプリを設定する
KamuiDashのプロジェクトにPostgreSQLを作成し、そのDBをアプリ作成時に選びます。DB接続の公式ガイドによると、DATABASE_URLなどの接続情報が環境変数として設定されます。ローカル用のURLをそのままコピーする必要はありません。

| 項目 | このサンプルの設定 | 確認すること |
|---|---|---|
| 種類・言語 | Webサーバー/Python | 静的なWebページとして作らない |
| ソース | 対象のGitHubリポジトリとブランチ | サンプル一式が入ったコミットを選ぶ |
| ルートディレクトリ | 空欄 | main.pyがリポジトリ直下にある前提 |
| セットアップコマンド | pip install -r requirements.txt |
依存関係をインストールする |
| 起動前コマンド | python init_db.py |
専用DBに初回テーブルを用意する |
| 起動コマンド | python main.py |
PORTで待ち受ける |
| ヘルスチェック | /healthz |
認証不要で200を返す |
| データベース | 作成したPostgreSQL | DATABASE_URLが設定される |
| 追加の環境変数 | DEMO_API_TOKEN |
ローカルと異なる十分長い値を設定する |
サンプルを既存リポジトリのサブフォルダーへ入れた場合は、そのフォルダーをルートディレクトリに指定します。コマンドは選択したディレクトリからの相対位置で考えます。
公開後は、URL・保存・更新を別々に確認する
デプロイが成功したら、発行されたHTTPSのURLに対してローカルと同じ順序で確認します。最初に/healthz、次に/readyz、メモの作成、一覧取得です。
続けて、メモを1件残したままソースを小さく修正して再デプロイし、同じメモを読めるか確認します。これで、APIのプロセスが入れ替わってもデータがDBに残る構成かを確かめられます。

起動しないときに見る場所
| 症状 | 先に確認する項目 |
|---|---|
ModuleNotFoundError |
セットアップのログとrequirements.txtの位置 |
| 公開URLへ接続できない | 起動ログ、0.0.0.0、PORT、ヘルスチェックのパス |
/healthzは200、/readyzは失敗 |
DBの稼働状態、アプリへのDB接続設定 |
relation "notes" does not exist |
起動前コマンドの実行結果と、接続しているDB |
/notesが401 |
本番のトークンとリクエストの認証ヘッダー |
| アクセスが増えるとDB接続で失敗 | 同時接続数、プロセス数、DBプランの接続上限 |
サンプルは1リクエストごとに接続を開き、処理の終了時に閉じます。常に接続を保持する方式ではありませんが、同時アクセスが多ければ接続上限には達します。本番では接続プールの上限を、DBの上限とプロセス・レプリカ数を含めて決めます。接続数を増やしたときの検証記事も判断材料になります。
よくある疑問
無料でずっと公開できますか?
KamuiDashには対象アプリ・DBの基本料金が30日間無料のトライアルがあります。継続利用は有料です。個人プランのNanoアプリ1台とNano DBを30日使う場合、基本料金の合計は税抜$9で、利用量に応じた料金などは別途です。詳しい条件は公式の料金・仕様で確認できます。
SQLAlchemyやAlembicは必須ですか?
この小さな例の起動には必須ではありません。テーブルの変更や複数環境の運用が始まったら、変更履歴を管理する仕組みが必要です。CREATE TABLE IF NOT EXISTSだけで継続運用を済ませないようにします。
DBも日本にあるなら、すべてのデータが国内だけで処理されますか?
外部認証、メール、監視、AI APIなどを組み合わせると、それぞれへの送信が発生します。東京リージョンでアプリとDBを動かすことと、システム全体のデータ所在は分けて確認します。
次の機能を足す前に、保存できる最小構成を残す
ここまでで用意するのは、起動・DB接続・保存・一覧取得・再デプロイ後の読み取りを確かめられる構成です。この状態をGitに残しておけば、機能追加で問題が出たときにも、どこから変わったかを比較できます。
検証範囲:添付サンプルのAPIとDB操作はローカルで確認しています。KamuiDashの設定は2026年11月2日の公式資料に基づき、このサンプルの新規クラウドデプロイは実施していません。
参考:FastAPIのサーバー起動、Psycopgの接続とトランザクション。
あわせて読みたい
KamuiDashは、GitHubやAI連携からWebアプリを公開できる東京リージョンのPaaSです。