Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can a JOI extension be applied to 'any()' so that it works for all types?

Tags:

joi

I'm building a JOI extension to allow me to blacklist certain people from sending certain API values, if they are missing certain roles from their JWT scope.

So far I've go this:

const Joi = require('joi')
const { string, number, ref, required, only, lazy } = Joi.extend(joi => ({
  name: 'string',
  base: Joi.string(),
  language: {
    permits: 'you are not allowed to edit {{key}}'
  },
  pre (value, state, options) {
    this.permissions = options.context.auth.credentials.scope
  },
  rules: [{
    name: 'whitelist',
    params: {
      permits: Joi.array()
    },
    validate(params, value, state, options) {
      const permitted = params.permits.find(value => this.permissions.includes(value))
      return permitted ? value : this.createError('string.permits', {}, state, options)
    }
  }]
}))

Which works perfectly.

However, Note the name and base are set to 'string'. I want this to work for numbers, arrays, objects, you name it.

I've tried this:

  name: 'any',
  base: Joi.any()

but it doesn't seem to work:

/home/ant/Projects/roles-example/routes/validation.routes.js:55
          reference: string().whitelist(['all-loans']),
                              ^

TypeError: string(...).whitelist is not a function

I would assume that any would allow me to append the function to any other type within JOI. But it seems that I can't.

Does anyone have any pointers for me, before I have to start adding this to all of the JOI base types?

like image 574
Antony Jones Avatar asked Sep 14 '25 08:09

Antony Jones


1 Answers

The way I solved this problem is by declaring the any rules separate and adding them all to each Joi type.

const Joi = require('joi')

const anyRules = j => [
  {
    name: 'whitelist',
    params: {
      permits: j.array()
    },
    validate(params, value, state, options) {
      const permitted = params.permits.find(value => this.permissions.includes(value))
      return permitted ? value : this.createError('string.permits', {}, state, options)
    }
  }
];

module.exports = Joi
.extend(j => ({
  name: 'any',
  base: j.any(),
  rules: anyRules(j),
}))
.extend(j => ({
  name: 'array',
  base: j.array(),
  rules: anyRules(j).concat([
    // ...
  ]),
}))
.extend(j => ({
  name: 'boolean',
  base: j.boolean(),
  rules: anyRules(j).concat([
    // ...
  ]),
}))
.extend(j => ({
  name: 'binary',
  base: j.binary(),
  rules: anyRules(j).concat([
    // ...
  ]),
}))
.extend(j => ({
  name: 'date',
  base: j.date(),
  rules: anyRules(j).concat([
    // ...
  ]),
}))
.extend(j => ({
  name: 'func',
  base: j.func(),
  rules: anyRules(j).concat([
    // ...
  ]),
}))
.extend(j => ({
  name: 'number',
  base: j.number(),
  rules: anyRules(j).concat([
    // ...
  ]),
}))
.extend(j => ({
  name: 'object',
  base: j.object(),
  rules: anyRules(j).concat([
    // ...
  ]),
}))
.extend(j => ({
  name: 'string',
  base: j.string(),
  rules: anyRules(j).concat([
    // ...
  ]),
}))
.extend(j => ({
  name: 'alternatives',
  base: j.alternatives(),
  rules: anyRules(j).concat([
    // ...
  ]),
}))
;
like image 122
Nate Avatar answered Sep 17 '25 18:09

Nate