Use validation error values on custom Joi/celebrate messages - node.js

I'm creating something using a nodejs/typescript stack for the server, and I'm trying to define custom generic error messages instead of per-field messages. Something like this:
routes.post(
'/points',
upload.single('image'),
celebrate({
body: Joi.object().keys({
name: Joi.string().required(),
email: Joi.string().required().email(),
whatsapp: Joi.number().required(),
latitude: Joi.number().not(0).required(),
longitude: Joi.number().not(0).required(),
city: Joi.string().required(),
uf: Joi.string().required().max(2),
items: Joi.string().required()
}),
}, {
abortEarly: false,
messages: {
'string.empty':'{context.label} cant be empty!'
}
}),
pointsController.create
);
As you can see, I'm trying to use a variable/value inside the custom message. I got that 'key' based on the error entry that comes out of celebrate/joi error, which is like this:
{
message: ' cant be empty!',
path: [ 'items' ],
type: 'string.empty',
context: { label: 'items', value: '', key: 'items' }
}
If there a way to do something like that?
The message is not 'parsing' the {context.label} as I though it would. I mean, this is a shot in the dark since I couldn't find anywhere if something like this is suported at all.

You can use {#label} to achieve what you want to.
Try:
.messages({
'string.empty': '{#label} cant be empty!',
'any.required': '{#label} is a required field for this operation'
})
and so on for all other types.
Other values are also accessible similarly. For ex, if you want to generalise the error message for string min/max:
.messages({
'string.min': '{#label} should have a minimum length of {#limit}'
})
Here, limit (min) was set when you created the schema for the string.

Related

Sequelize setter error 'invalid input syntax for integer: "[object Object]"'

I am trying to associate a list of contacts to a customer using the associations setter method, however, it always throws the error 'invalid input syntax for integer: "[object Object]"'.
The relevant query mentioned in the error is: UPDATE "contactperson" SET "refCustomerId"=$1,"updatedAt"=$2 WHERE "id" IN ('[object Object]')
This is how I use the setter:
db.customer.findByPk(customerID, {
include: [{
model: db.address,
as: 'address',
},{
model: db.contactoption,
as: 'contactOptions',
}, {
model: db.contactperson,
as: 'contactPersons',
}]
}).then(customer => {
customer.setContactPersons([ { firstName: 'tester', lastName: 'tester', description: 'lorem ipsum' } ]);
});
This is the association:
Customer.hasMany(models.contactperson, {
foreignKey: 'refCustomerId',
as: 'contactPersons'
});
Any idea what I'm doing wrong?
I managed to resolve this issue using the following code:
db.contactperson.bulkCreate([ { firstName: 'tester', lastName: 'tester', description: 'lorem ipsum' } ]).then(newContactPersons => {
customer.setContactPersons(newContactPersons);
});
It's a more complicated approach than intended, but it get's the job done.
You used set<ModelName>s that just updates a link field of given records. If you need to create contactperson record you need to use createContactPerson instead of setContactPersons (NOTE: you cannot create several records at once).
customer.createContactPerson({
firstName: 'tester',
lastName: 'tester',
description: 'lorem ipsum'
});
compare to:
const contactPerson = db.contactperson.findById(1);
if (contactPerson) {
customer.addContactPersons([contactPerson.id]);
}
set<ModelName>s - replaces old linked records with the new existing ones
add<ModelName>s - adds exisiting records in addition to old ones
create<ModelName> - create a new non-existing record in addition to old ones
See hasMany special methods
Exactly what Anatoly posted.
I had method declared on TypeScript like:
declare addPost: HasManyCreateAssociationMixin<PostClass, 'userId'>;
When i changed to:
declare createPost: HasManyCreateAssociationMixin<PostClass, 'userId'>;
Everything works so remember - how you describe name of method its very necesary.

Joi - Required based on value on other key

I want to validate an input which only has two fields(namely text and image). Both text and image are string and one of them must always be present. When one of the fields is absent then the other one can not be an empty string.
this is the Validation I have defined.
text: Joi.string()
.when('image',
{
is: Joi.string(),
then: Joi.string().allow(''),
otherwise: Joi.string().required(),
}
),
image: Joi.string().allow(null),
when I use the below input, the validation allows the data to pass. I dont how to change the validation to prohibit the below input.
post: {
text: ''
}
Use exist() instead of string() when validating:
when('image', {
is: Joi.exist(),
then: Joi.string().allow(''),
otherwise: Joi.string().required(),
})
body:Joi.object({
notifiyto:Joi.string().valid('selectedCustomer','selectedDrivers','allCustomers','allDrivers').required(),
notifiyIds:Joi.when('notifiyto',{
is: Joi.exist().valid('selectedCustomer', 'selectedDrivers'),
then: Joi.required(),
}),
message:Joi.string()
})

How to add extra properties to error returned from express-validator

When I use the express-validator and validate fields, I always get the error response with value, msg, param and location properties. What if I want to add extra properties in there like say code to communicate it to the client.
For ex:
When I do
check('name').not().isEmpty().withMessage('Name must have more than 5 characters')
I get
{ value: undefined, msg: 'Name must have more than 5 characters', param 'name', location: 'body'}
// What I am looking to achieve is this
{ value: undefined, msg: 'Name must have more than 5 characters', code: 'NAME_MANDATORY' param 'name', location: 'body'}
How do I achive this with express-validator?
you can try to give the withMessage a function like this
withMessage((value, { req, location, path }) => {
return { value, location, path, otherkey:'some message' };
})

GraphQL mutation that accepts an array of dynamic size in one request as input with NodeJs

I want to pass an object array of [{questionId1,value1},{questionId2,value2},{questionId3,value3}] of dynamic size in GraphQL Mutation with NodeJS
.........
args: {
input: {
type: new GraphQLNonNull(new GraphQLInputObjectType({
name: 'AssessmentStep3Input',
fields: {
questionId:{
name:'Question ID',
type: new GraphQLNonNull(GraphQLID)
},
value:{
name:'Question Value',
type: new GraphQLNonNull(GraphQLBoolean)
}
}
}))
}
},
.........
How can I do that with the given sample of code?
Thanks
If you want to pass an object array with GraphQL Mutation you need to use "GraphQLList" which allows you to pass an array with dynamic size of given input.
Here is the example
........
........
args: {
input: {
type: new GraphQLNonNull(GraphQLList(new GraphQLInputObjectType({
name: 'AssessmentStep3Input',
fields: {
questionId:{
name:'Question ID',
type: new GraphQLNonNull(GraphQLID)
},
value:{
name:'Question Value',
type: new GraphQLNonNull(GraphQLBoolean)
}
}
}))
)
}
},
........
........
Hope it helps.
Thanks
i just published the article on that, so that you can take a look if you would like to know more detail. This is the repository with the examples, where the createUsers mutation is implemented https://github.com/atherosai/express-graphql-demo/blob/feature/5-modifiers/server/graphql/users/userMutations.js. You can take a look how it is implemented, but in general the above answer is correct. You can input as many objects as you would like to in the array (if you have not implemented some number of items limiting, but it is not there by default).

Database query API error construction

I'm working on a simple API that performs an INSERT query into a SQL database, using information supplied from a form clients would fill out on the front end. I'm curious if there is a preferred way when it comes to constructing the error message regarding query errors.
Using a concrete example, I have a form to be filled out by users with attributes A, B, and C. In the SQL database, they're all enforced with a "NOT NULL" constraint. Therefore, if an empty form was submitted, the following error object would be returned:
{
...
errors:
[ ValidateErrorItem {
message: "model.a cannot be null"
type: "..."
path: "..."
value: "..."
.. },
ValidateErrorItem {
message: "model.b cannot be null"
type: "..."
path: "..."
value: "..."
.. },
ValidateErrorItem {
message: "model.c cannot be null"
type: "..."
path: "..."
value: "..."
.. },
]
}
How would one typically construct an error message to be display to the user (other than simply showing "An error occurred with the query")?
Note: I know that this scenario can be prevented using front end validation, but other things can go wrong (besides non-null validation), so this is just a simple example when an error occurs, not necessarily what I'd do in practice.
These kind of validations should be performed for each api request. I prefer to use Joi.
Joi will throw error anytime the schema does not match with what you are expecting. For example
const schema = Joi.object().keys({
modelA: Joi.string().required(),
modelB: Joi.string().required(),
modelC: Joi.string().required(),
});
const myObj = { modelA: 'modelA' };
console.log(Joi.validate(myObj, schema));
The above code will throw an error { ValidationError: child "modelB" fails because ["modelB" is required]
You can also add customer error message like this
const schema = Joi.object().keys({
modelA: Joi.string().required(),
modelB: Joi.string().required().error(new Error('Was expecting a string')),
modelC: Joi.string().required(),
});
const myObj = { modelA: 'modelA' };
console.log(Joi.validate(myObj, schema));
This will throw an error
Error: Was expecting a string
These messages can be parsed by front-end and shown as such.

Resources