APIのレスポンスは、DBから取得したレコードをそのままJSON化して返してはいけない
https://scrapbox.io/files/65884d22bcee4a00261c8942.webp
例
例えば、以下のようなコードを書いてはいけない
code:api.js
// データベースからShop(店)レコード取得
const r = db.Shop.findOne({where:{store_id:1}})
// NG
res.json(r);
なぜ?
テーブルには、公開したくないフィールドが含まれている可能性があり、"うっかり公開"を未然に防ぐ必要がある
公開したくないフィールドの例
ストアの住所、担当者名などの個人情報
管理者用メモ
今はそのようなフォールドがなくても、後から追加される可能性があり、予め フェイルセーフな設計にしておくのが望ましい
どのようにすればよい?
JSON化する際に、公開して良いフィールドだけ、ホワイトリストを指定しておく
_.omitを使ったブラックリストを指定する方法は、フェイルセーフの効果がないので使わない
code:model/shop.js
const _ = require('underscore');
Model.prototype.toJSON = async function({full=false}) {
let keys = [
"store_id", "store_name", ... // 公開して良い情報のみ
//"charge_name", "address", ... // 公開しては良くない情報
];
// 明示的に full=true が指定された場合のみ
if (full) {
}
// keys で指定されたフィールドのみJSON化
// "_.omit" は使わないこと
return _.pick(this.dataValues, keys);
}
code:api.js
// db からストア取得
const r = db.Shop.findOne({where:{user_id:1}})
// レスポンス(公開用)
res.json(r.toJSON({})); // charge_name, address は含まれない
// レスポンス(管理用)
res.json(r.toJSON({full:true})); // charge_name, address が含まれる
次の議論
_.omitを使わせないようにするにはどうすればよいか?
フィールドを追加する度に、toJSON を修正するのは面倒。フィールド定義の近くで指定できないか?
code:例
popurarity {
type: DataTypes.INTEGER,
apiOpennessLevel: APIOpennessLevel.public // <-- ここ
}
テストで防げないか?あるいはどこまで防げるか?
どこでホワイトリストを適用するか
箇所
レスポンス生成直前(今回の説明)
atteibute を指定するなどSELCT時
小池宏幸.icon
個人的には、公開ギリギリまではフィルターしないほうが望ましいと考える
内部処理は様々なフィールドが使えるほうが便利なのと、公開してもそれほど問題ないであろうという判断から
メンバーの権限やスキルにもよるかもしれない
atteibute を動的に変える方法なら、それほど差はないかも
例
code:api.js
const attibutes = db.Store.FieldKeys.public // toJSON内の key に相当
const s = db.Store.findOne({attributes, where:{store_id:1}})
res.json(r);