【Supabase】フロントエンドでDB操作する際に注意すべきことの自分ルールがまとまってきた
Next.js + Supabase で個人開発しています。
通常であれば、PHPやNode.js(API Routes)などを仲介してデータベースのCRUDを行うかと思いますが、サーバーコスト(主に金銭的)を削減するため、フロントエンドから直接DBを操作するようにしています。
バックエンド言語っぽい処理がほとんど無いので、気軽に実装できて便利なのですが、フロントエンドから直接DBを操作するが故に気にしなければならないことがいくつかありました。
その問題点と解決策が自分なりにルールがまとまってきたので記事化します。
.rpc()
を経由して取得する。
SELECTは基本的に使わず、
詳細は上記の記事をご覧ください。
簡単に紹介しますと、
何も対策しないとテーブルのカラム名すらも丸見えになってしまいます。
カラム名が見えること自体は何も問題ありませんが、offsetやらorderなど自由にクエリを投げられてしまい、スクレイピングに優しい環境になっています。
最終的にWebページに出力するのでスクレイピングされるのも時間の問題ではありますが、可能な限りの抵抗として多少なりともハードルを高くしておきたいです。
そこで、SELECTのリクエストはFALSEとしておき、SQL関数化してrpc()経由でデータを取得するという手段を取る方がマシだろうという結論に至りました。
文字数制限を付ける際はフロントエンド側の文字数カウントの精度を落とす妥協が必要
こちらも上記の記事をご覧ください。
DB側で絵文字やサロゲートペアのカウントを正確に行うのが難しいです。フロントエンド側ではわりと正確なカウントが可能なのですが、DBのCHECK制約との整合性が合わなくなり、UX的に問題が出てくることでしょう。
そこで妥協案として、
- DBのCHECK制約の
char_length()
による文字数カウント - JavaScriptの文字数カウント
を一致させることを優先させることにしました。
const strings = "😀👨👩👧👦👨𨨞𨨞𨨞👩👧𧾷👦😀𨸶𨸶😀";
const count = Array.from(strings).length;
// 出力
console.log(count);
このように書くと char_length()
とほぼ同じカウント結果になります。
フロント側の文字数制限とDB側の文字数制限がほぼ一致するので、ユーザー目線では意味不明なエラーによる投稿失敗を回避でき、UXが守られるだろうという判断になりました。
auto_incrementの性質を悪用したイタズラ対策
こちらも上記の記事をご覧ください。
auto_increment は1から順番に数字が割り振られていきます。
この性質を利用したイタズラが考えられます。
具体的には、未来の数字を自由入力して先取りして確保してしまうというもの。例えば、現時点でid番号300が割り振られている状態で、330番~1000番がイタズラによって取られていると、auto_incrementで生成される番号が1001を超えないとDBにデータ挿入できず、エラーが起きてしまうというものが考えられます。
これではユーザーは投稿する意欲を失い、サービスが衰退する原因になると考えられます。
この対策としてPostgreSQLのトリガー機能で、入力された値と今回auto_incrementで生成された値との一致の確認で回避することにしました。
一致しない場合はRAISE EXCEPTIONで例外エラーを発生させ、クエリの実行を中断させています。
まとめ
まだまだ何かありそうですが、現時点で思いつくものはこれだけです。
CHECK制約だけでは解決できない部分は、トリガーを使えば値チェックにも使える上、エラーとして返してくれるので実装がとても楽です。
SupabaseはSQL(plpgsql)を極めないと辛い印象がありますが、GUIやCLIなどのツールが十分に整っているので怖がる必要はありません。(ChatGPTさんも居ますし!)何か1つプロダクトが完成したら、それ以降はとんでもなく爆速で個人開発ができそうな匂いがプンプンしています!
個人開発勢こそSupabaseは絶対に触れておきたいBaaSだと思います!
告知
2023年12月15日までに個人開発のプロダクトをリリース予定です!
個人開発 Advent Calendar 2023の15日目の記事として書きます。よろしくお願いします!
▼チラ見せ
Discussion