Joi Schema should contain one field or another - javascript

I'm looking into using Joi for api validation.
I can't seem to confirm whether my schema is correct in that I want either the email or mobile to be required (but they both can't be empty/non existent) - is the below correct?
var schemaForRegistration = Joi.object().keys({
email: Joi.string().email(),
mobile:Joi.number().integer()
}).without('email', 'mobile');
Thanks

It might be that or() is what you're after.
Try this:
const Joi = require('joi')
const schema = Joi.object().keys({
email: Joi.string().email(),
mobile: Joi.number().integer()
}).or('email', 'mobile')
Joi.validate({ email: 'xxx#yyy.com', mobile: '999000999000' }, schema, console.log)
Joi.validate({ mobile: '999000999000' }, schema, console.log)
Joi.validate({ email: 'xxx#yyy.com' }, schema, console.log)
Joi.validate({}, schema, console.log)
The final validation will fail because neither email nor mobile is present.

Related

Joi validate one of two schemas

I have a simple object with few fields that I would like to validate. I wish to allow or a specific validation schema or that all of the properties have empty values
I created the following two schemas:
const nonEmptyUserInfoValidationSchema = Joi.object({
url: Joi.string().uri().required(),
username: Joi.string().required().min(usernameMinLength),
password: Joi.string().required().min(passwordMinLength),
});
const emptyUserInfoValidationSchema = Joi.object({
url: Joi.string().empty().required(),
username: Joi.string().empty().required(),
password: Joi.string().empty().required(),
});
I wish to create schema that validates if emptyUserInfoValidationSchema or nonEmptyUserInfoValidationSchema is applied but I can't figure out how to do it, any suggestions?
allowed:
{url:"http://some.url", username:"some username", password:"some password"}
{url:"", username:"", password:""}
not allowed:
{url:"http://some.url", username:"", password:""}
Well I finally found what I was looking for joi.alternatives:
export const ansibleInfoValidationSchema = Joi.alternatives(emptyUserInfoValidationSchema , nonEmptyUserInfoValidationSchema );
seems to do the trick
You use the .keys().and() to specify peers. This means that none of the fields specified in the .and() will exist without each other. Hence should be used as so:
const schema = Joi.object({
url: Joi.string().uri(),
username: Joi.string().min(usernameMinLength),
password: Joi.string().min(passwordMinLength)
}).keys().and('url', 'username', 'password');
I hope this helps you can use the when condition in Joi
var schema = Joi.object({
url : Joi.any().when('username',{
is: Joi.empty(),
then: Joi.empty().required(),
otherwise: Joi.string().required()
}),
username: Joi.when('password',{
is: Joi.empty(),
then: Joi.empty(),
otherwise: Joi.string().required().min(usernameMinLength)
})
});
here's a link to when docs Joi When Condtion

Adding a validator to an existing schema with mongoose

I have a mongoose schema that looks like this:
const userSchema = new Schema({
username: {
type: String,
required: true,
unique: true,
minlength: 4,
maxlength: 20,
validate: {
validator: username => !username.startsWith('banned_prefix')
msg: 'This username is invalid',
type: 'username-validation-1'
}
}
});
I want the schema to look like this:
const userSchema = new Schema({
username: {
type: String,
required: true,
unique: true,
minlength: 4,
maxlength: 20,
validate: [
{
validator: username => !username.startsWith('banned_prefix')
msg: 'This username is invalid',
type: 'username-validation-1'
},
{
validator: username => !username.startsWith('new_banned_prefix')
msg: 'This username is invalid',
type: 'username-validation-2'
}
]
}
});
How do I do this given that the database and schema already exist and I don't want to completely delete and reset the db?
I tried writing a migration using the native mongodb node driver based on https://docs.mongodb.com/manual/core/schema-validation/#existing-documents. However, it seems like mongoose doesn't actually add native mongodb validators for the validators specified in the schema. That is, when I printed out the validator data for the collection, I get an empty object:
// prints {}
console.log((await db.listCollections({ name: 'users' }).toArray())[0].options.validator);
I don't want to add this new validator in a way that makes it different from the existing validators I have on the schema.
Actually, it looks like this isn't an issue at all because, I presume, mongoose isn't using mongodb native validators so there doesn't need to be any change to the actual db. Mongoose will pick up a validator change like this automatically, no migration necessary.
This wasn't clear to me at first because I was trying to manually recreate the model with the mongoose.model function and was getting errors about overwriting an existing model.

React Yup schema

I'm using Yup to validate an email field:
const Schema = Yup.object().shape({
email: Yup.string()
.email("non valid email format")
.required("Email required"),
...
During form submit, I check if the email domain is included in a list of forbidden domains, if yes, I display an error message in a popup:
const forbidDomains = domains;
const domain = data.email.split("#");
if(forbidDomains.Domains.includes(domain[1])) {
this.setState({openPopup:true,statusMessage:"domain not allowed : " + domain[1]})
this.setState({isSubmitting:false})
return;
}
I would like to check the domain in the Yup schema, but I'm not sure if it's possible.
I think that what you are looking for is the .test() from Yup. Maybe something like this may work:
const schema = {
email: Yup.string()
.string()
.email()
.test('test-name', 'Validation failure message',
function(value) {
// your logic to check the domain
})
}

Validate only one single field of a bigger Joi schema

I want to use Joi for form field validation and want to stick with one big schema object for validation of the whole form, yet I want to run single entry validation after one form field has been changed - i.e. after the first form field has recieved a value, I do not want to validate the complete form, but only the one field updated. I am envisioning something like
const schema = Joi.object({
username: Joi.string()
.alphanum()
.min(3)
.max(30)
.required(),
password: Joi.string()
.pattern(new RegExp('^[a-zA-Z0-9]{3,30}$'))
.required(),
});
const validationResult = schema.username.validate('Tommy');
Is that possible?
Yes, by extracting the username schema to a separate schema like so:
const username_schema = Joi.string()
.alphanum()
.min(3)
.max(30)
.required();
const schema = Joi.object({
username: username_schema,
password: Joi.string()
.pattern(new RegExp('^[a-zA-Z0-9]{3,30}$'))
.required(),
});
const validationResult = username_schema.validate('Tommy');

JS library to check if extra data field returned in http response payload?

I’m currently working on building end-to-end testing for an API another team is working on, and I was wondering if anyone perhaps knows about a JS library that I could use to test whether an extra field is returned in HTTP response body? The purpose of this functionality would be to keep the QA team informed when the dev team makes changes to the api via the tests, instead of the developers manually having to let us know they’ve created updates. I know this can be implemented manually but if the wheel already exists, I’d prefer to avoid recreating it lol.
Example scenario:
API call: GET user
- returns : user name, user ID and user birthday.
With proposed functionality, if the dev team made updates to the Get user call, and it returns the following
- return : user name, user ID, user birthday AND user address.
A test would fail to let me know that an extra field that wasn't expected (user address) was returned.
Schema validation seems to be what you are looking for. Besides the library mentioned in another answer, you may also want check a similar one: joi
const Joi = require('joi');
const schema = Joi.object().keys({
userName: Joi.string().alphanum().required(),
userId: Joi.number().required(),
userBirthDay: Joi.number().required(),
})
const result = Joi.validate({
userName: 'johndoe',
userId: 1234567,
userBirthDay: 1970,
userAddress: 'John Doe St.'
}, schema);
if (result.error) {
console.log(result.error.details);
}
In the spec you can make assertion on existence of error key in result object using the assertion library of your choice.
The example above assumes that you are using nodejs as an environment to run tests, but browser version of joi also exists: joi-browser
You need schema validation, there are libraries out there like ajv.
var ajv = new Ajv({ allErrors: true }); // options can be passed, e.g. {allErrors: true}
// API call: GET user - returns : user name, user ID and user birthday.
// With proposed functionality, if the dev team made updates to the Get user call, and it returns the following - return : user name, user ID, user birthday AND user address.
var schema = {
type: "object",
properties: {
userName: {
type: "string",
},
userId: {
type: "string",
},
userBirthdate: {
type: "string",
},
},
required: ["userName", "userId", "userBirthdate"],
additionalProperties: false,
};
var validate = ajv.compile(schema);
var validUser = {
userName: "John",
userId: "john",
userBirthdate: "01012000",
};
var invalidUser = {
userName: "John",
userId: "john",
userBirthdate: "01012000",
userAddress: "World",
};
var valid = validate(validUser);
console.log(`Valid user is valid: ${valid}`);
valid = validate(invalidUser);
console.log(`Invalid user is valid: ${valid}`);
console.log('Validate errors:', validate.errors);
<script src="https://cdnjs.cloudflare.com/ajax/libs/ajv/6.6.2/ajv.min.js"></script>

Categories