はじめに
私は個人開発でNext.jsとSupabaseを利用したWebアプリ開発をしているのですが、
Supabaseを使っていると、「これがしたい!」と思ったときにちょっと困ることがあったので、その時の記録を残しておこうと思います。
それぞれの問題に対しての解決策は各々の状況によって異なると思うので、特に触れていません。
「こういうことがあったよ」という情報共有にとどめていますので、個人開発の技術選定の際に参考になれば嬉しいです。
どんな苦労があったの?
「RLSを通したい」と「ORMを使いたい」のトレードオフ
私は RLS を経由させたいという思いが強かったので、データの取得や登録は Supabase JS の .select() や .insert() のようなチェーン形式の API(PostgREST 経由)で書いています。ORM は使っていません。
PostgreSQL の RLS が効くかどうかは、ORM かどうかではなく DB に接続しているロール/キーで決まります。たとえばサーバー側で SERVICE_KEY(service_role) を使って ORM などから DB に直接触ると、設計上 RLS をバイパスします。RLS を「通常の読み書きの前提」にしたい私には、その経路をメインにしない方がしっくりきました。
その一方で、複雑な取得や登録を DB 関数(RPC)やビューに寄せる場面は増えがちで、型やクエリの組み立てを ORM でまとめたいという気持ちとはトレードオフになるな、と感じています(JWT 付き接続で RLS を効かせたまま ORM を使う道もありますが、私はそこまで踏み込んでいません)。
権限ロジックが「RLS(DB側)」と「アプリケーションコード」に分散してしまう
RLSとソースの二箇所でユーザー周りの権限を意識する必要があるため、認知負荷が高いと感じました。
RLSで制御できるとはいえ、ある程度ソース側で制御も必要ですし、RLSにはドメインの最重要砦としての役割を担わせたかったという思いがあります。
「自分が登録したデータのみを表示する」だけなら簡単な設定で済みますが、「同じグループのユーザーがそれを表示できるようにする」といった要件が出てくると、管理が煩雑になってきます。テスト範囲と境界を意識しないとセキュリティ事故につながりかねないため、実は難しい領域だなと感じました。
モックでの単体テストと相性が悪い
単体テストだと、基本的に実際のDBを使うのではなく、モックを使ったテストをしているのですが、実際のDBを使ったテストも必要になってくるため、少し面倒でした。
もちろん後工程では実際のDBを使ったテストをするのですが、ユーザー権限周りの重要な不具合をはやめにキャッチしたいと考えていた私にとっては「合わないな」と感じたポイントでした。
まとめ
- RLSを通る経路と RLS をバイパスする経路の役割分担を意識する
- テストの範囲・境界を意識する
- モックだけのテストで終わらせない(RLS 前提の挙動はDBに近いテストが必要)