Search code examples
javascriptnode.jsjsonschemajson-schema-validatorajv

why my json schema let a wrong value pass?


I'm trying to validate a json object before requesting an api but I have an issue my user should look like

{
    "type": "student",
    "firstname": "jhon",
    "lastname": "DOE",
    "login": "jDOE",
    "pwd": "jdoepassword",
    "classes": []
}

or as a teacher

{
    "type": "teacher",
    "firstname": "teacher",
    "lastname": "TEACHER",
    "login": "tTEACHER",
    "pwd": "tTeacherpassword"
}

I'm trying to use ajv module and here's my code :

var Ajv = require('ajv');
const ajv = new Ajv({allErrors: true});
const schema = {
  $jsonSchema: {
    anyOf: [
      {
        properties: {
          _id: {
            bsonType: 'objectId'
          },
          type: {
            'enum': [
              'student'
            ],
            bsonType: 'string',
            description: 'as to be a student'
          },
          firstname: {
            bsonType: 'string',
            description: 'must be a string'
          },
          lastname: {
            bsonType: 'string',
            description: 'must be a string'
          },
          login: {
            bsonType: 'string',
            description: 'must be a string',
            pattern: '^(?!$).*'
          },
          pwd: {
            bsonType: 'string',
            description: 'must be a string'
          },
          classes: {
            bsonType: 'array',
            items: {
              bsonType: [
                'string'
              ],
              additionalProperties: false
            }
          }
        },
        required: [
          'type',
          'firstname',
          'lastname',
          'login',
          'pwd',
          'classes'
        ],
        additionalProperties: false
      },
      {
        properties: {
          _id: {
            bsonType: 'objectId'
          },
          type: {
            'enum': [
              'teacher'
            ],
            bsonType: 'string',
            description: 'as to be a teacher'
          },
          firstname: {
            bsonType: 'string',
            description: 'must be a string'
          },
          lastname: {
            bsonType: 'string',
            description: 'must be a string'
          },
          login: {
            bsonType: 'string',
            description: 'must be a string',
            pattern: '^(?!$).*'
          },
          pwd: {
            bsonType: 'string',
            description: 'must be a string'
          }
        },
        required: [
          'type',
          'firstname',
          'lastname',
          'login',
          'pwd'
        ],
        additionalProperties: false
      }
    ]
  }
};
const test = ajv.compile(schema);
/* I initiate my command line app here so argv contains all needed fields */ 
let user = {};
user.type = argv.type || 'student';
user.firstname = argv.firstname;
user.lastname = argv.name;
user.login = argv.login || argv.firstname.slice(0, 1) + argv.name.slice(0, 7);
user.pwd = argv.password;
if (user.type == "student") user.classes = [];
const isValid = test(user);
if (isValid) {
    /* request API */
}

but when I create a user such as

{
  type: 'fujkdswghldfkj',   /*<= here's the important part*/
  firstname: 'arandomfirstname',
  lastname: 'arandomlasname',
  login: 'arandomlogin',
  pwd: 'password',
  classes: []
}

the api is requested as if it was normal to have a type "fujkdswghldfkj" instead of the enum 'student' or 'teacher', somebody know why ?


Solution

  • I think your schema definition is wrong. When I change it to:

    const schema = {
      type: 'object',
      properties: {
        type: {
          enum: ['teacher', 'student']
        },
        firstname: {
          type: 'string',
        },
        lastname: {
          type: 'string',
        },
        login: {
          type: 'string',
        },
        pwd: {
          type: 'string'
        },
      },
      required: [
        'type',
        'firstname',
        'lastname',
        'login',
        'pwd',
      ],
    };
    

    and then do the following:

    const test = ajv.compile(schema);
    const isValid = test({
      type: 'fujkdswghldfkj',   
      firstname: 'arandomfirstname',
      lastname: 'arandomlasname',
      login: 'arandomlogin',
      pwd: 'password',
      classes: [],
    });
    

    I get the following validation-error:

    [
      {
        keyword: 'enum',
        dataPath: '.type',
        schemaPath: '#/properties/type/enum',
        params: { allowedValues: ["teacher", "student"] },
        message: 'should be equal to one of the allowed values'
      }
    ]