第10章:入力検証① 必須フィールドと型(まず事故を止める)🧠🧱
この章は「変なデータをDBに入れさせない」がテーマだよ😊✨ Firestoreは“スキーマなし(何でも入る)”だから、Rulesで最低限のスキーマを作るのが超大事🔥 (Firebase)

1) まずココだけ覚える!🎯(今日の武器🗡️)

入力検証の基本セットはこれ👇
- ✅ 必須フィールドが揃ってる? →
keys().hasAll([...]) - ✅ 余計なフィールドが紛れ込んでない? →
keys().hasOnly([...])(ホワイトリスト方式) - ✅ 型が合ってる? →
is string / is int / is timestamp ...
Firestoreはスキーマレスだから、これをやらないと 「title が配列だった😇」「isAdmin を勝手に付けられた😇」みたいな事故が起きがち💥 (Firebase)
2) 例題:AIメモアプリの aiNotes を守る📝🤖

AI系(FirebaseのAI機能やGeminiなど)を絡めると、Firestoreには例えばこんなデータを入れたくなるよね👇
prompt(ユーザーの入力)answer(AIの返答)ownerUid(持ち主)createdAt(作成日時)
ここで入力検証を入れないと、悪意ある人が👇みたいな“混入”を狙える😱

isAdmin: trueを勝手に書くcreatedAtに文字列を入れる(timestampじゃない)- 必須フィールド無しで壊れたドキュメントを量産する
3) ルール実装(読む→手を動かす🧑💻✨)
3-1. ルールの考え方(超ざっくり)🧠
-
必須:
keys().hasAll([...])で「最低限これが無いとダメ!」 -
許可リスト:
keys().hasOnly([...])で「これ以外は一切ダメ!」- これが強い🔥(“新しいフィールド”はデフォで拒否できる) (Firebase)
-
型:
isで型を固定(string,int,timestampなど) (Firebase)
3-2. firestore.rules サンプル🛡️✨

rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
function isSignedIn() {
return request.auth != null;
}
// ✅ 必須フィールド(最低限これが無いと拒否)
function hasRequiredFields(d) {
return d.keys().hasAll(['prompt', 'answer', 'ownerUid', 'createdAt']);
}
// ✅ 許可フィールド(これ以外の“余計なキー”が来たら拒否)
function hasOnlyAllowedFields(d) {
return d.keys().hasOnly([
'prompt', 'answer', 'ownerUid', 'createdAt',
'updatedAt', 'model' // ← 任意(後で増やしたいならここに追加)
]);
}
// ✅ 型チェック(“っぽい”じゃなく、ちゃんと型で止める)
function hasValidTypes(d) {
return d.prompt is string
&& d.answer is string
&& d.ownerUid is string
&& d.createdAt is timestamp
// optional: updatedAt(無ければOK、あればtimestamp)
&& (d.get('updatedAt', null) == null || d.get('updatedAt', null) is timestamp)
// optional: model(無ければOK、あればstring)
&& (d.get('model', null) == null || d.get('model', null) is string);
}
// ✅ ちょいUX:空文字は拒否(最低限)
function notEmptyStrings(d) {
return d.prompt != "" && d.answer != "";
}
match /aiNotes/{noteId} {
// 読みは一旦「本人だけ」にしておく(安全寄り)
allow get, list: if isSignedIn() && resource.data.ownerUid == request.auth.uid;
// 作成:本人のデータ + 必須 + 許可リスト + 型 + 空文字NG
allow create: if isSignedIn()
&& request.resource.data.ownerUid == request.auth.uid
&& hasRequiredFields(request.resource.data)
&& hasOnlyAllowedFields(request.resource.data)
&& hasValidTypes(request.resource.data)
&& notEmptyStrings(request.resource.data);
// 更新:基本は create と同じ検証を“もう一回”
// (update は request.resource が「更新後の完成形」になるので、必須チェックも効く)
allow update: if isSignedIn()
&& request.resource.data.ownerUid == request.auth.uid
&& hasRequiredFields(request.resource.data)
&& hasOnlyAllowedFields(request.resource.data)
&& hasValidTypes(request.resource.data)
&& notEmptyStrings(request.resource.data);
// 削除:本人のみ(ここは第9章の復習)
allow delete: if isSignedIn() && resource.data.ownerUid == request.auth.uid;
}
}
}
ポイント解説😊👇
keys().hasAll([...])で必須項目を強制できるよ ✅ (Firebase)keys().hasOnly([...])は「許可リスト」方式なので強い🔥(余計なフィールドをデフォ拒否) (Firebase)- 型チェックは
isを使う(string,int,timestampなど) (Firebase) - optional フィールドは
d.fooって直に触ると「無い時にエラー→即拒否」になりがち。get('foo', default)が安全✅ (Firebase) updateのときrequest.resourceは「更新後のドキュメント状態」になるよ(だから必須チェックも効く) (Firebase)
4) 手を動かす(3分でOK)🧪✨

✅ 試したい“ダメ入力”3連発💣
-
必須不足(
createdAtなし) → ❌ 作成できない -
型ミス(
createdAt: "2026-02-16"みたいに文字列) → ❌ 作成できない(timestampじゃない) -
余計なフィールド混入(
isAdmin: true) → ❌ 作成できない(hasOnlyで止まる🔥)
5) ミニ課題🎯(章のゴールに直結✨)
次の条件を満たすように、上のルールを微調整してね😊🛠️
promptは必須&空文字NG ✅answerは必須&空文字NG ✅modelは任意(無くてOK、あればstring) ✅- 余計なフィールドは全部拒否 ✅
6) チェック✅(できたら勝ち!🏆)
- 必須フィールドが欠けると弾ける?😎
- 型がおかしいと弾ける?😎(
timestampが超重要) -
isAdminみたいな“混入フィールド”を止められる?😎 - optional は
get()を使って安全に書けた?😊 (Firebase)
7) AIで加速するやり方(ただし“最後は人間が責任”🤖🧑⚖️)
7-1. Gemini CLIで「Rules+テストの叩き台」を作る🚀

Firebase公式の流れだと👇こういう感じで、Rulesとテスト雛形まで出してくれるよ✨ (Firebase)
gemini extensions install https://github.com/gemini-cli-extensions/firebase
gemini
/firestore:generate_security_rules
firestore.rulesと、テスト用のsecurity_rules_test_firestoreを生成してくれる(Node.jsプロジェクト) (Firebase)- しかも “攻撃シミュレーション”で脆弱っぽい所を探そうとしてくれるのが面白い😆🛡️ (Firebase)
- ただし 自動追従で更新はされない(作ったら終わり、毎回見直しが必要)⚠️ (Firebase)
- そして重要:Firebaseコンソール内の Gemini in Firebase はRules生成に未対応(現時点)⚠️ (Firebase)
7-2. Antigravity × Firebase MCP で“会話しながら整える”🧠✨
Firebase MCP server は Antigravity に追加できるってFirebase公式Blogで紹介されてるよ📌 メニューからMCP servers→Firebase→install、みたいな流れ(記事に手順あり) (The Firebase Blog)
ここでおすすめの頼み方(例)👇
- 「
aiNotesの必須フィールドと型のRules関数を作って」 - 「
hasOnlyで余計なフィールド混入を止めたい。安全な書き方にして」 - 「“弾くべきテストケース”を3つ作って」
8) 最後に:Rulesだけに頼り切らないのもコツ😉
Rulesは“最後の砦🛡️”だけど、アプリ側でも入力チェックしておくと UXも良くなるし、無駄なリクエストも減って気持ちいいよ😊✨ (Firestoreのガイドでも、入力チェックをRules条件として書く流れが紹介されてるよ) (Firebase)
次の第11章は「文字数・パターン(地雷💣)」へ進むけど、 この第10章の 必須+型+許可リストができた時点で、もう“守りの骨格”は完成だよ🦴🔥