「バックエンド」と聞くと身構える。けれど正体は単純だ——誰かのリクエストを受け取り、データを出し入れして、返す。
Python の FastAPI と、ファイル1つで動くデータベース SQLite があれば、
サーバもクラウドも要らず、手元のPCで「動くAPI」が今日作れる。この一枚で、その全体像を掴む。
ブラウザやアプリからの HTTP リクエスト
→URLごとに Python 関数へ振り分け
→1ファイルの DB に読み書き
→結果を JSON にして応答
最初のバックエンドに「本格的な構成」は不要。学習の摩擦を最小にする2つを選ぶ。
FastAPI — Python の Web フレームワーク。関数の上に @app.get("/…") と一行書くだけで、その URL が API になる。
型ヒントを書けば入力チェックと API ドキュメントが自動生成される。速く、学びやすく、いま最も勢いがある。
SQLite — サーバ不要のデータベース。Python に最初から同梱されていて、インストールも起動もいらない。
データは app.db という1個のファイルに溜まる。プログラムを止めても消えない=これが「永続化」。
理屈より先に動かす。ターミナルで3ステップ。Python が入っていれば数分で /docs が開く。
# 仮想環境を作って有効化(推奨) python3 -m venv venv source venv/bin/activate # Windows は venv\Scripts\activate # FastAPI 本体と、開発サーバ uvicorn を入れる pip install "fastapi[standard]"
from fastapi import FastAPI app = FastAPI() @app.get("/") def read_root(): return {"message": "こんにちは、バックエンド"} @app.get("/hello/{name}") def hello(name: str): return {"hello": name}
{name} はそのまま関数の引数に届く。: str が型ヒント。fastapi dev main.py
http://127.0.0.1:8000 を開くと JSON が返る。http://127.0.0.1:8000/docs を開くと、触れる API ドキュメント(Swagger UI)が自動で完成している。
型ヒントから生成されたもので、その場でリクエストを送って動作確認できる。
REST API は「何を(URL)」×「どうする(HTTPメソッド)」で表す。 データの基本操作 CRUD(作成・読取・更新・削除)が、4つの動詞にきれいに対応する。
| メソッド | 意味 (CRUD) | URL の例 | 裏で走る SQL |
|---|---|---|---|
| POST | Create 作成 | /items | INSERT |
| GET | Read 読取 | /items · /items/3 | SELECT |
| PUT | Update 更新 | /items/3 | UPDATE |
| DELETE | Delete 削除 | /items/3 | DELETE |
↓ 下のシミュレータで、動詞を選ぶと リクエスト → FastAPI のコード → 走る SQL → 返る JSON がまとめて見える。 バックエンドの中で「同じ流れ」が繰り返されているだけ、というのが体で分かる。
上のシミュレータの「裏側」を最小コードで。Python 標準の sqlite3 だけで、テーブル作成から CRUD まで一通り動く。
import sqlite3 from fastapi import FastAPI, HTTPException from pydantic import BaseModel app = FastAPI() def db(): # 1ファイル app.db に繋ぐ。無ければ自動で作られる con = sqlite3.connect("app.db") con.row_factory = sqlite3.Row # 列名でアクセスできる return con # 起動時に一度だけ:テーブルが無ければ作る with db() as con: con.execute("""CREATE TABLE IF NOT EXISTS items( id INTEGER PRIMARY KEY AUTOINCREMENT, title TEXT NOT NULL, done INTEGER DEFAULT 0)""")
# POST で受け取る JSON の形。型に反したら FastAPI が自動で 422 を返す class ItemIn(BaseModel): title: str done: bool = False
# CREATE @app.post("/items") def create(item: ItemIn): with db() as con: cur = con.execute( "INSERT INTO items(title, done) VALUES(?, ?)", (item.title, int(item.done))) return {"id": cur.lastrowid, "title": item.title, "done": item.done} # READ(一覧) @app.get("/items") def list_items(): with db() as con: rows = con.execute("SELECT * FROM items").fetchall() return [dict(r) for r in rows] # UPDATE @app.put("/items/{item_id}") def update(item_id: int, item: ItemIn): with db() as con: cur = con.execute( "UPDATE items SET title=?, done=? WHERE id=?", (item.title, int(item.done), item_id)) if cur.rowcount == 0: raise HTTPException(404, "見つかりません") return {"id": item_id, "title": item.title, "done": item.done} # DELETE @app.delete("/items/{item_id}") def delete(item_id: int): with db() as con: con.execute("DELETE FROM items WHERE id=?", (item_id,)) return {"deleted": item_id}
? プレースホルダを使い、
文字列連結(f"… {title}")で組み立てない。連結すると SQL インジェクション——外部からの入力で DB を乗っ取られる典型的な穴——ができる。
上のコードが全部 ? と (値,) のタプルで渡しているのはそのため。
① データが消える? → 消えていない。 SQLite は app.db ファイルに書く。サーバを再起動しても残る。
逆に「消したい」ときはこのファイルを消すだけ。.gitignore に app.db を入れて、DBファイルはコミットしないのが定石。
② ブラウザから叩けない(CORS)。 別ドメインのフロントから呼ぶと弾かれることがある。
その時は CORSMiddleware を1ブロック足す。まずは /docs から試せば CORS は関係ないので、切り分けが楽。
③ 本番で SQLite のまま? → 個人・小規模なら十分。 同時書き込みが激しくなったら PostgreSQL 等へ。
sqlite3 を SQLAlchemy(ORM)に替えておくと、その乗り換えが設定1行で済む。次の学習の入口はここ。
この一枚は「地図」。実際に手を動かす番地は、本家の Tutorial が世界一よくできている(日本語訳あり)。
main.py を1行ずつ。今日つまずいたらここに戻る。/docs で触る →
④第4章の CRUD を写経 → ⑤公式 Tutorial へ。ここまでで「自分専用の ToDo API」が手元に残る。AIエージェントに繋ぐ土台にもなる。