ボイラープレートの罠
何度も週末をループの中で無駄にしてきた。きれいなPostgreSQLスキーマを設計した後、Node.jsやPythonで冗長なCRUD(Create、Read、Update、Delete)ロジックを書くだけで次の3日間が吹き飛ぶ。コントローラーを作り、DTOを定義し、すべてのデータベースカラムをAPIエンドポイントに手作業でマッピングする。単調で、エラーが起きやすく、プロジェクトの勢いを完全に削いでしまう。
このような摩擦が生じるのは、私たちが巨大なアーキテクチャのギャップを当たり前として受け入れてきたからだ。データベースを受動的なストレージバケット、バックエンドを唯一の知性の源として扱っている。しかし、PostgreSQLはすでに驚くほど高度な機能を備えている。堅牢な型システム、複雑な制約、そして実績のある権限モデルを持っている。その同じロジックをミドル層で書き直すのは、多くの場合、冗長な作業に過ぎない。
PostgRESTはこの中間層を排除し、スキーマから直接RESTful APIを提供する。データベースの構造を検査し、エンドポイントをオンザフライで生成する。バックエンドコードを1行も書くことなく、本番環境対応のAPIが手に入る。
クイックスタート:5分でゼロからAPIへ
邪魔にならないツールが好きだ。PostgRESTはHaskellでコンパイルされた単一のバイナリだ。驚くほど軽量で、通常はRAMを30MB未満しか消費しないにもかかわらず、月5ドルの基本的なVPSで毎秒2,000以上のリクエストを処理できる。新しいマシンでライブAPIをセットアップする方法を紹介しよう。
1. データベースの準備
セキュリティは分離から始まる。publicスキーマは決して公開しない。代わりに、専用のapiスキーマを作成して、Webに公開するものを厳密にコントロールする。シンプルなタスクマネージャーを作ってみよう。
-- Postgresインスタンスに接続する
CREATE SCHEMA api;
CREATE TABLE api.todos (
id SERIAL PRIMARY KEY,
done BOOLEAN DEFAULT false,
task TEXT NOT NULL,
due TIMESTAMPTZ
);
-- 匿名Webリクエスト用のロールを作成する
CREATE ROLE web_anon NOLOGIN;
GRANT USAGE ON SCHEMA api TO web_anon;
GRANT SELECT ON api.todos TO web_anon;
2. PostgRESTのインストールと起動
インストールは簡単だ。Dockerを使うこともできるが、ローカル開発ではバイナリの方が速い。OS用の最新リリースをダウンロードして展開しよう。
# Linuxユーザー向けの例
wget https://github.com/PostgREST/postgrest/releases/download/v12.0.2/postgrest-v12.0.2-linux-static-x64.tar.xz
tar xf postgrest-v12.0.2-linux-static-x64.tar.xz
次に、PostgRESTがデータベースと通信する方法を設定するためのtutorial.confファイルを作成する:
db-uri = "postgres://authenticator:mysecretpassword@localhost:5432/postgres"
db-schema = "api"
db-anon-role = "web_anon"
./postgrest tutorial.confで起動しよう。APIは今すぐhttp://localhost:3000/todosで利用可能だ。シンプルなGETリクエストで、データがきれいなJSON配列として即座に返ってくる。
詳細解説:JWTとRLSによるセキュリティ
最もよく聞かれる懸念は「ユーザー権限はどう処理するのか?」というものだ。PostgRESTはカスタムログインロジックを必要としない。セキュリティをJSON Web Tokens(JWT)とPostgreSQLネイティブのRow Level Security(RLS)に委任する。このアプローチは従来のアプリケーションレベルのチェックよりも大幅に安全だ。
Authenticatorパターン
authenticatorロールは信頼されたプロキシとして考えよう。データベースに接続するが、それ自体には権限がない。その唯一の仕事は、JWTに含まれるクレームに基づいて特定のユーザーロールに切り替えることだ。
-- ログイン済みユーザー用のロールを作成する
CREATE ROLE todo_user NOLOGIN;
GRANT USAGE ON SCHEMA api TO todo_user;
GRANT ALL ON api.todos TO todo_user;
GRANT USAGE, SELECT ON SEQUENCE api.todos_id_seq TO todo_user;
-- authenticatorがtodo_userに切り替えられるようにする
GRANT todo_user TO authenticator;
JWTシークレットの設定
tutorial.confにjwt-secretを追加しよう。このキーはブルートフォース攻撃を防ぐために、少なくとも32文字以上でなければならない。
jwt-secret = "a-very-secure-32-character-secret-key"
クライアントがAuthorization: Bearer <token>ヘッダーを送信すると、PostgRESTがそれを検証する。トークンに"role": "todo_user"が含まれていれば、データベースはそのユーザーとしてクエリを実行する。Node.jsコードでif (user.id === record.owner_id)を手動でチェックする必要はもうない。
応用:シンプルなCRUDを超えて
PostgRESTは単なる基本的なラッパーではない。通常なら何百行ものコードを必要とする複雑なデータ要件を処理できる。
強力なフィルタリング
検索エンジンを構築する必要はない。PostgRESTはURLパラメーターをSQL条件にマッピングする。「coffee」に関連する未完了のタスクで、期限が近いものを検索するには、次のように使うだけだ:
GET /todos?done=is.false&task=like.*coffee*&limit=10
リソースの埋め込み(JOIN)
関連データの取得は、よく「N+1クエリ」というパフォーマンスの罠につながる。PostgRESTはリソースの埋め込みでこの問題を解決する。usersテーブルとtodosテーブルが外部キーで紐付けられていれば、1つのリクエストで一緒に取得できる:
GET /users?select=name,todos(*)
効率的なデータインポート
大量データの処理は共通の悩みどころだ。レガシーなスプレッドシートを移行する際、toolcraft.app/ja/tools/data/csv-to-jsonを使ってローカルで行をJSON配列に変換している。そのあと、その配列をPostgRESTエンドポイントに直接POSTする。データベースが単一トランザクションで一括挿入を処理し、データの整合性を確保してくれる。
本番環境の強化
高トラフィックのプロジェクトにPostgRESTを何度かデプロイした経験から、次の3つのプラクティスが不可欠だとわかった:
- SQLビューを使う:テーブルはプライベートとして扱おう。代わりにビューをAPIに公開する。これにより、フロントエンドのAPIコントラクトを壊さずにデータベーススキーマを変更できる。
- RLSを強制する:常にRow Level Securityを有効にしよう。これはセーフティネットとして機能し、APIエンドポイントが誤って設定された場合でも、ユーザーが他の人の行にアクセスできないようにする。
- ロジックにはストアドプロシージャを:ウェルカムメールの送信などのアクションには、PostgreSQLトリガーまたは関数を使おう。
POST /rpc/send_welcome_emailでこれらを呼び出せる。
ロジックをデータベースに移すことで、「信頼できる唯一の情報源」を作れる。ユーザーがWebアプリ、モバイルアプリ、CLIツールのどれで接続しても、ビジネスルールは一貫している。これはSQLをマスターすることを強いるが、それは今日のトレンドなバックエンドフレームワークが消えた後も長く役立つスキルだ。

