Search code examples
javascriptnode.jsjoi

How to pass external params to JOI extension?


Maybe JOI isn't the tool for this but I'd like to use it if possible. Basically I have a user that is sending a request to an API to store a specific type of metric data. Certain metrics however are user role restricted, so I want to be able to use JOI to 1) validate the user is trying to store a valid metric and 2) validate that the user has the proper role to store that metric.

I've tried using context and passing that into the extended validator but I've had no luck in getting that to work, this is ideally what I'd like to be able to do:

From main function:

let userMetric = {id: "metric1", label: "Metric 1"};
let userRoles = ["metric2access"];
const { error, val } = schema.validate({ metric: userMetric }, {context: {userRoles: userRoles }});

Schema:

const Joi = require('./customjoi')

let validMetricIds = ["metric1", "metric2"]

const schema = Joi.object().keys({
    metric: Joi.object({
        id: Joi.string().roleCheck({userRoles: '$userRoles'}).valid(...validMetricIds)
    })
})

customjoi.js

module.exports = Joi.extend((joi) => ({
    type: "string",
    base: joi.string(),
    messages: {
       "string.roleCheck": "User does not have access to {{#label}}"
    },
    rules: {
        roleCheck: {
            params: {
                options: Joi.object({
                    userRoles: Joi.any()
                })
            },
            validate(params, value, helpers) {
                let metricsRequiredRoles = {"metric1": ["metric1access"], "metric2": ["metric2access"]};
                if (Object.keys(metricsRequiredRoles).includes(value)) {
                    requiredRole = metricsRequiredRoles[value];
                    if (params.options.userRoles.includes(requiredRole)) {
                        return value;
                    } else {
                        return helpers.error("string.roleCheck")
                    }
                }

                return value;
            }
        } 
    } 
}))

Is this type of thing possible with JOI? Is there another way to do it that's not like the way I wrote here?


Solution

  • if anyone ever reads this just use a global variable i guess