JOI validation when condition not working as expected - joi

I have the following JOI schema defined;
schema = Joi.object({
flag: Joi.boolean()
.required(),
toolDetail: Joi.array().items(
Joi.object({
amount: Joi.number()
.min(0)
.max(499.99)
.precision(2)
.options({ convert: false })
.when('flag', {
is: true,
then: Joi.number().required(),
otherwise: Joi.number()
.strip()
.optional()
.allow(''),
}),
tool: Joi.string()
.min(0)
.max(500)
.when('flag', {
is: true,
then: Joi.string().required(),
otherwise: Joi.string()
.strip()
.optional()
.allow(''),
}),
}),
),
});
I have confirmed that the flag is being set correctly, but it seems that 'amount' and 'tool' is always hitting the otherwise condition, regardless of the value set in the 'flag'.
Is there something incorrect in my definition?

Works as expected once I added 4 dots prefix to the flag
.when('....flag', {
https://joi.dev/api/?v=17.2.1#relative-references

Related

How to don't validate fields that don't exists in Schema object

I have a schema with two fields, but in some cases is necessary send other field that not is necessary validate. How to allow this fields?
const schemaInsercao = Joi.object({
nome: Joi.string()
.min(3)
.max(255)
.required()
,
ativo: Joi.string()
.max(1)
.required()
.valid('S', 'N')
,
descricao: Joi.string()
.max(255)
.required()
});
....
sending
{
"nome":"Invictos Tecnologia",
"ativo":"S",
"teste":""
}
the error
{
"msg": "\"teste\" is not allowed"
}
https://joi.dev/api/?v=17.6.0#anyvalidatevalue-options
schema.validate(data, {
allowUnknown: true
})

Joi when sibling then add extra rules at root

I have a complex validation which changes depending on the a value in the JSON.
{ type: 'a', thing: 1, foo: 'abc' }
{ type: 'b', thing: 2, bar: 123 }
I want to validate that if the type is a, then use one set of siblings, if b then use another set of siblings
I would like to use the when switch, but cant work out how to do this at the root.
Joi.object({
type: Joi.string().valid('a','b').required(),
thing: Joi.number().required()
}).when('type', {
switch: [
{ is: 'a', then: Joi.object({ foo: Joi.string() }) },
{ is: 'b', then: Joi.object({ bar: Joi.number() }) },
],
otherwise: Joi.forbidden(),
});
However this gives the following error:
Error: Invalid reference exceeds the schema root: ref:type
This kinda makes sense as an error but I don't know how to restructure this to get it to apply the selector at the root.
Im using latest JOI (16.0.1)
This can be resolved by prefixing the key name passed to .when() with a ., to denote the key as being relative to the object being validated:
Joi.object({
type: Joi.string().valid('a','b').required(),
thing: Joi.number().required()
})
.when('.type', { /* <-- prefix with . */
switch : [
{ is: 'a', then: Joi.object({ foo: Joi.string() }) },
{ is: 'b', then: Joi.object({ bar: Joi.number() }) },]
})
Here's a working example - hope that helps :-)

How to write message to Mattermost using Fastlane?

How do I write a message to Mattermost using Fastlane ?
Below is my trial. I got most from this link.
What is still wrong ?
(of course, I replaced the MATTERMOST_WEBHOOK_URL by the actual value that I established in Mattermost).
In the link above, I saw an actions folder with a mattermost.rb file
How do I get this action to work ? What do I need to do inside my Fastfile or anywhere in order to get this to work ?
In fact, running the fastlane send_message lane, I get a success. But unfortunately, nothing is visible in my Mattermost channel.
Inside my Fastfile, I do:
def send_message_to_mattermost(options)
unless ENV['MATTERMOST_WEBHOOK_URL'].nil? || ENV['MATTERMOST_WEBHOOK_URL'].empty?
mattermost(
pretext: options[:pretext],
message: options[:msg],
default_payloads: options[:default_payloads],
username: 'Fastlane',
icon_url: 'https://s3-eu-west-1.amazonaws.com/fastlane.tools/fastlane.png',
payload: {},
attachment_properties: {
title: options[:title],
thumb_url: options[:thumb_url],
fields: [{
title: 'Version',
value: options[:version_number],
short: true
},
{
title: 'Build Number',
value: options[:build_number],
short: true
},
{
title: 'Built by',
value: 'Jenkins',
short: true
}]
},
success: options[:success]
)
end
end
And my Fastlane lane looks like this:
lane :send_message do
send_message_to_mattermost({
:version_number => ENV['VERSION_NUMBER'],
:build_number => ENV["BUILD_NUMBER"],
:pretext => ENV['MAIN_APP_IDENTIFIER'],
:title => 'Unsuccessful Build',
:thumb_url => 'https://support.apple.com/library/content/dam/edam/applecare/images/en_US/iOS/move-to-ios-icon.png',
:msg => "My message...",
:default_payloads => [:lane],
:success => true
})
end
Is mattermost(...) a standard command in Fastlane ? If not what do I need to do in order to send information to a Mattermost channel from Fastlane ?
I finally found a solution.
What was missing is to set the ENV["MATTERMOST_WEBHOOK_URL"] upfront
before_all do
ENV["MATTERMOST_WEBHOOK_URL"] = 'https://my_new_webooh_from_mattermost'
end
...and leave the following code intact (i.e. do not replace 'MATTERMOST_WEBHOOK_URL' by anything else - the before_all does the trick...)
def send_message_to_mattermost(options)
unless ENV['MATTERMOST_WEBHOOK_URL'].nil? || ENV['MATTERMOST_WEBHOOK_URL'].empty?
mattermost(
pretext: options[:pretext],
message: options[:msg],
default_payloads: options[:default_payloads],
username: 'Fastlane',
icon_url: 'https://s3-eu-west-1.amazonaws.com/fastlane.tools/fastlane.png',
payload: {},
attachment_properties: {
title: options[:title],
thumb_url: options[:thumb_url],
fields: [{
title: 'Version',
value: options[:version_number],
short: true
},
{
title: 'Build Number',
value: options[:build_number],
short: true
},
{
title: 'Built by',
value: 'Jenkins',
short: true
}]
},
success: options[:success]
)
end
end

How to validate for ObjectID

Using Joi schema validation, is it possible to validate against MongoDB ObjectID's?
Something like this could be great:
_id: Joi.ObjectId().required().error(errorParser),
const Joi = require('#hapi/joi')
Joi.objectId = require('joi-objectid')(Joi)
const schema = Joi.object({
id: Joi.objectId(),
name: Joi.string().max(100),
date: Joi.date()
})
checkout https://www.npmjs.com/package/joi-objectid
I find that if I do
Joi.object({
id: Joi.string().hex().length(24)
})
it works without installing any external library or using RegEx
The hex makes sure the string contains only hexadecimal characters and the length makes sure that it is a string of exactly 24 characters
This package works if you are using the new version of Joi.
const Joi = require('joi-oid')
const schema = Joi.object({
id: Joi.objectId(),
name: Joi.string(),
age: Joi.number().min(18),
})
package: https://www.npmjs.com/package/joi-oid
If you want a TypeScript version of the above library integrated with Express without installing anything:
import Joi from '#hapi/joi';
import { createValidator } from 'express-joi-validation';
export const JoiObjectId = (message = 'valid id') => Joi.string().regex(/^[0-9a-fA-F]{24}$/, message)
const validator = createValidator({
passError: true,
});
const params = Joi.object({
id: JoiObjectId().required(),
});
router.get<{ id: string }>(
'/:id',
validator.params(params),
(req, res, next) => {
const { id } = req.params; // id has string type
....
}
);
I share mine
let id =
Joi.string()
.regex(/^[0-9a-fA-F]{24}$/)
.message('must be an oid')
With joi naked package you can use this:
const ObjectId = joi.object({
id: joi.binary().length(12),
})
This is a core function without any external package. I have used Joi and mongoose packages to achieve it.
const Joi = require("joi");
const ObjectID = require("mongodb").ObjectID;
const schema = Joi.object({
id: Joi.string().custom((value, helpers) => {
const filtered = ObjectID.isValid(value)
return !filtered ? helpers.error("any.invalid") : value;
},
"invalid objectId", ).required(),
name: Joi.string(),
age: Joi.number().min(18),
})
I see many correct answers here, but I also want to express my opinion.
I am not against installing npm packages, but installing one package just to validate an object id is overkill. I know programmers are lazy but C'mooon :)
Here is my full code function that validates two object id properties, very simple:
function validateRental(rental) {
const schema = Joi.object({
movieId: Joi.string()
.required()
.regex(/^[0-9a-fA-F]{24}$/, 'object Id'),
customerId: Joi.string()
.required()
.regex(/^[0-9a-fA-F]{24}$/, 'object Id'),
})
const { error } = schema.validate(rental)
return {
valid: error == null,
message: error ? error.details[0].message : null,
}
}
This way, if any of the properties contain invalid id like this:
{
"movieId": "123456",
"customerId": "63edf556f383d108d54a68a0"
}
This will be the error message:
`"movieId" with value "123456" fails to match the object Id pattern`

Joi validate presence of a key or another one

I'm using Joi for http body validation. I want to allow keyA to be present OR a keyB to be present and required but not both. I don't find in documentation what I'm looking for and it seems that a cycling loop appear in my schema.
const messageSchema = Joi.object().keys({
keyA: Joi.when('keyB', { is: Joi.exist(), then: Joi.forbidden(), otherwise: Joi.string().required() }),
keyB: Joi.when('keyA', { is: Joi.exist(), then: Joi.forbidden(), otherwise: Joi.string().uri().required() }),
});
Any idea ?
Finally found what I was looking for :
const messageSchema = Joi.object().keys({
keyA: Joi.string(),
keyB: Joi.string().uri(),
}).or('keyA', 'keyB');