bugfix> node.js > 投稿

Express APIを構築し、検証に@ hapi/joiを使用しています。ただし、次の状況に陥っています。新しいユーザーを検証する場合は、スキーマ内のすべてのプロパティが必要ですが、クライアントがユーザーを変更する場合は、クライアントだけが何を知っているので、これらのプロパティはオプションである必要があります。変更するプロパティ。したがって、新しいユーザー用にこのスキーマがある場合:

function validateUser(user) {
  const schema = Joi.object().keys({
    name: Joi.string().required(),
    lastName: Joi.string().required(),
    email: Joi.string().email().required(),
    password: Joi.string().required(),
    address: Joi.string().required(),
    city: Joi.string().required(),
    district: Joi.string().required()
});
  return schema.validate(user);
}

すべてのプロパティが必須であるため、同じプロパティですべてがオプションのスキーマを使用する場合は、すべてのプロパティがオプションである別のスキーマをハードコーディングする必要があります。冗長なコードを回避する方法またはJoiのオプションはありますか?スキーマに適用するためにvalidateUser関数に渡されるisNewパラメーターのように?

回答 2 件
  • あなたは間違った方法で問題に取り組んでいると思います。スキーマは通常、DB内でのタイプの状態を表す必要があります。たとえば、名が必要な場合、それが作成または更新されているかどうかに関係なく、常に必要になります。したがって、更新の場合は、dbからアイテムをフェッチし、その上に変更を適用してから、検証のために送信します。

    本当にこの方法で実行したい場合は、joiスキーマからアクセスできるvalidate関数にコンテキストを渡すことができます。 $ 符号。ここでは2つの選択肢があります。各プロパティにifelse条件を適用してスキーマを醜く見せるか、2つのバージョンのスキーマをまとめて、渡されたコンテキストの値に応じて選択します。このようなもの

    const Joi = require("@hapi/joi");
    const schemaA = Joi.object().keys({
      "name": Joi.string().required(),
      "lastName": Joi.string().required(),
      "email": Joi.string().email().required(),
      "password": Joi.string().required(),
      "address": Joi.string().required(),
      "city": Joi.string().required(),
      "district": Joi.string().required()
    });
    const schemaB = Joi.object().keys({
      "name": Joi.string(),
      "lastName": Joi.string(),
      "email": Joi.string().email(),
      "password": Joi.string(),
      "address": Joi.string(),
      "city": Joi.string(),
      "district": Joi.string()
    });
    function ChooseSchema() {
      return Joi.when(Joi.ref("$isNew"), {
        "is": true,
        "then": schemaA,
        "otherwise": schemaB
      });
    }
    console.log(ChooseSchema().validate({"name": "ashish"}, {"context": {"isNew": true}}));
    console.log(ChooseSchema().validate({"name": "ashish"}, {"context": {"isNew": false}}));
    
    
    

  • より良い方法は、any.fork(paths、adjuster)を使用することです。

    リストされている各パスキーが変更された新しいスキーマを返します。ここで、

    パス-キー文字列の配列、単一のキー文字列、または事前に分割されたキー文字列の配列の配列。キー文字列パスはドットを使用します。キー階層を示します。

    アジャスター-変更されたスキーマを返す必要がある署名関数(スキーマ)を使用する関数。たとえば、(schema)=>schema.required()です。

    このメソッドは元のスキーマを変更しません。

    例:

    
    // define the object
    const schemaObj = {
        name: Joi.string(),
        lastName: Joi.string(),
        email: Joi.string().email(),
        password: Joi.string(),
        address: Joi.string(),
        city: Joi.string(),
        district: Joi.string()
    };
    // no need to use fork here every obj is already not required
    const allUnreqJoiObj = Joi.object(schemaObj);
    // use of fork to modify it
    // fork for all keys
    const allReqJoiObj = Joi.object(schemaObj).fork(Object.keys(schemaObj), (schema) => schema.required());
    console.log(allReqJoiObj.validate({'city': 'some city'}));
    
    // fork for selected keys 
    const fewReqJoiObj = Joi.object(schemaObj).fork(['email', 'password'], (schema) => schema.required());
    console.log(fewReqJoiObj.validate({'city': 'some city'}));
    
    

    一部またはすべてのキーが必要なスキーマがすでにある場合は、forkを使用してそれらをオプションにします

    例:

    const schemaObj = {
      name: Joi.string().required(),
      lastName: Joi.string().required(),
    };
    const allOptional = Joi.object(schemaObj).fork(Object.keys(schemaObj), (schema) => schema.optional());
    
    const nameOptional = Joi.object(schemaObj).fork(['name'], (schema) => schema.optional());
    
    
    

あなたの答え