P. Vitvera
P. Vitvera

Reputation: 95

Extended Joi not implementing custom operators

I have issues extending joi class with custom operators. I want to validate mongodb Ids, but the extended object throws following error:

error: uncaughtException: JoiObj.string(...).objectId is not a function
TypeError: JoiObj.string(...).objectId is not a function

Code is following:

import Joi from 'joi';
import * as mongodb from 'mongodb';

interface ExtendedStringSchema extends Joi.StringSchema {
    objectId(): this;
}

interface ExtendedJoi extends Joi.Root {
    string(): ExtendedStringSchema;
}

const JoiObj: ExtendedJoi = Joi.extend({
    base: Joi.string(),
    type: 'objectId',
    messages: {
        'objectId.invalid': '"{{#label}}" must be a valid mongo id'
    },
    validate(value, helpers) {
        if (!mongodb.ObjectId.isValid(value)) {
            return helpers.error('objectId.invalid');
        }

        return value;
    }
});

const objIdSchema = JoiObj.object({
    id: JoiObj.string().objectId()
});

I found 2 examples:

https://github.com/sideway/joi/issues/2357

How to extend a module from npm using TypeScript?

however they use different properties than what is described in TS definition file and thus does not work.

Upvotes: 2

Views: 2043

Answers (2)

Muzaffer Yıldırım
Muzaffer Yıldırım

Reputation: 124

I also had this problem. I solved it with this package.

https://www.npmjs.com/package/joi-oid

const Joi = require('joi-oid')

const schema = Joi.object({
  id: Joi.objectId(),
  name: Joi.string(),
  age: Joi.number().min(18),
})

Good luck :)

Upvotes: 0

a1300
a1300

Reputation: 2813

You want to extend the Joi.string() base. Keep in mind, that you can't validate new mongodb.ObjectID() because it is of type object. You extended Joi.string() and this checks first if your value is of type string. And it will stop validating if it isn't. You can only validate new mongodb.ObjectID().toHexString() which looks like: "5f91a1449b13e3010c5548a2".

This answers is using joi 17.2.1 and mongodb 3.6.2

import Joi from 'joi';
import * as mongodb from 'mongodb';

interface ExtendedStringSchema extends Joi.StringSchema {
    objectId(): this;
}

interface ExtendedJoi extends Joi.Root {
    string(): ExtendedStringSchema;
}

const stringObjectExtension: Joi.Extension = {
    type: 'string',
    base: Joi.string(),
    messages: {
        'string.objectId': '{{#label}} must be a valid mongo id'
    },
    rules: {
      objectId: {
        validate: (value: any, helpers) => {
          if (!mongodb.ObjectId.isValid(value)) {
              return helpers.error('string.objectId')
          }

          return value;
        }
      }
    }
};

// create extended Joi
const JoiObj: ExtendedJoi = Joi.extend(stringObjectExtension);

// create new mongodb id
const id = new mongodb.ObjectID();

const objIdSchema = JoiObj.object({
    id: JoiObj.string().objectId()
});

// will fail because it won't pass the Joi.string() validation
const data1 = {
  id: id
};
console.log(objIdSchema.validate(data1).error);

// will succeed
const data2 = {
  id: id.toHexString()
};
console.log(objIdSchema.validate(data2).error);

Upvotes: 2

Related Questions