joi
joi copied to clipboard
how do I convert a string into a number? and use number checks
Context
[email protected]
v16.14.2
Darwin 5c52309d33e3 20.6.0 Darwin Kernel Version 20.6.0: Tue Apr 19 21:04:45 PDT 2022; root:xnu-7195.141.29~1/RELEASE_X86_64 x86_64 i386 Darwin
How can we help?
I'm trying to check whether one converted object is greater than another, problem is it's not converting
1) env
custom conversion:
ValidationError: "RETRY_TIMEOUT_DURATION" must be a number
at Object.exports.process (/Users/nqy642/IdeaProjects/exceptionsone/node_modules/joi/lib/errors.js:193:16)
at Object.internals.entry (/Users/nqy642/IdeaProjects/exceptionsone/node_modules/joi/lib/validator.js:153:26)
at Object.exports.entry (/Users/nqy642/IdeaProjects/exceptionsone/node_modules/joi/lib/validator.js:27:30)
at internals.Base.validate (/Users/nqy642/IdeaProjects/exceptionsone/node_modules/joi/lib/base.js:548:26)
at Object.internals.assert (/Users/nqy642/IdeaProjects/exceptionsone/node_modules/joi/lib/index.js:225:27)
at Object.attempt (/Users/nqy642/IdeaProjects/exceptionsone/node_modules/joi/lib/index.js:107:26)
at Object.validateRequired (/Users/nqy642/IdeaProjects/exceptionsone/packages/util/src/validate.ts:20:37)
at Context.<anonymous> (src/framework/util/env.spec.ts:32:19)
at processImmediate (node:internal/timers:466:21)
at process.topLevelDomainCallback (node:domain:152:15)
at process.callbackTrampoline (node:internal/async_hooks:128:24)
import Joi from 'joi'
import parse from 'parse-duration'
import { Primitive, SafeDictionary } from 'ts-essentials'
export type EnvKey =
| 'RETRY_TIMEOUT_DURATION'
| 'AXIOS_TIMEOUT_DURATION'
export type Env = SafeDictionary<Exclude<Primitive, symbol>, EnvKey> & {
RETRY_TIMEOUT_DURATION: number
AXIOS_TIMEOUT_DURATION: number
}
const convertDuration = (envVar: string): number => parse(envVar)
export const envValidator = Joi.object<Env>({
AXIOS_TIMEOUT_DURATION: Joi.number().empty().default(30000).custom(convertDuration),
RETRY_TIMEOUT_DURATION: Joi.number()
.greater(Joi.ref('AXIOS_TIMEOUT_DURATION'))
.empty()
.default(40000)
.custom(convertDuration),
})
it('custom conversion', () => {
const environment = {
RETRY_TIMEOUT_DURATION: '40s',
}
const valid = Joi.attempt(environment, envValidator)
expect(valid.RETRY_TIMEOUT_DURATION).to.be.eq(40000)
})
if I use Joi.string()
it seems to work except that I can't use .greater()
because it's not on string.
In the past, I have used Joi extensions to do this:
Extension:
'use strict';
const parse = require('parse-duration');
function JoiDurationExtension(Joi) {
return ({
type: 'number',
base: Joi.number(),
coerce(value, helpers) {
if (helpers.schema.$_getRule('duration')) {
return {
value: parse(value),
};
}
return { value };
},
rules: {
duration: {
convert: true,
method() {
return this.$_addRule('duration');
},
validate(value, helpers) {
return true;
},
},
},
});
};
module.exports = JoiDurationExtension;
Usage:
'use strict';
const assert = require('assert');
const BaseJoi = require('joi');
const JoiDuration = require('./joi-duration');
const Joi = BaseJoi.extend(JoiDuration);
const Schema = Joi.number().duration().max(40001).prefs({ convert: true });
const value = Joi.attempt('40s', Schema);
assert.equal(typeof value, 'number', 'duration was cohersed');
assert.equal(value, 40000, 'duration was parsed');
Joi.assert('41s', Schema); // fails