34
loading...
This website collects cookies to deliver better user experience
If else
conditions/statements to ensure you throw error when the user inputs wrong data? Yeah, it's stressful and trust me, you still won't cater for all scenarios. joi
. joi
helps define data easily without the need to worry about not throwing error; joi does the job for you by throwing error.express.js
]npm install joi express
const Joi = require("joi");
app.post("/register", async (req, res) => {
try {
// Define Schema
const schema = Joi.object({
username: Joi.string().min(6).alphanum().uppercase().required(),
password:Joi.string().regex(/^[a-zA-Z0-9]{3,30}$/).required(),
confirm_password:Joi.string().equal(Joi.ref('password')).messages({'any.only': 'password does not match' }).required(),
firstname: Joi.string().required(),
lastname: Joi.string(),
email: Joi.string().email({minDomainSegments: 2}).required(),
phonenumber: Joi.string().min(6).regex(/^([+])?(\d+)$/).required(),
dob: Joi.date().max('01-01-2003').iso().messages({'date.format': `Date format is YYYY-MM-DD`,'date.max':`Age must be 18+`}).required(),
sex: Joi.string().valid('male', 'female','transger', 'others')
});
// Validate req.body against the defined schema
const validation = schema.validate(req.body);
const { value, error } = validation;
if (error) {
const message = error.details.map(x => x.message);
res.status(400).json({
status: "error",
message: "Invalid request data",
data: message
});
} else {
res.json({
status: "success",
message: "Registration successful",
data: value
});
}
} catch (error) {
res.json({status:"failed",message:error.message})
}
});
Joi.object()
instantiate a Joi schema object to work with. The schema require Joi.object()
to process validation and other Joi features..string()
I won't be repeating it again in order to keep the article short and simple.username
include:.string()
a string."s"
is in lowercase, not uppercase i.e if you use .String()
joi will throw this error Joi.String is not a function
min(6)
- at least 6 characters long.max(30)
- not more than 30 characters.alphanum()
- contain alphanumeric characters e.g (olufemi78).uppercase()
- This means when the user input username, joi should convert to uppercase (interesting yeah? 😉)required()
- This means username is required, if user does not pass it, joi will throw error "\"username\" is required"
password
include:.regex('^[a-zA-Z0-9]{3,30}$')
- This means, it must satisfy the custom regex pattern.^ : Asserts the start of a string
[a-zA-Z0-9]{3,30} : Matches any character from a-z or 0-9 but the length range must between 3 to 30
$ : End
confirm_password
include:.equal(Joi.ref('password'))
- This means it reference password
and it must be equal to password.messages({ 'any.only': 'password does not match' })
- If password
and confirm_password
does not match, joi will throw this custom error password does not match
. any.only
is error type so whenever the error type is any.only
I prefer to send custom message and not the typical joi error message. Just make's the error message more descriptive to the user.firstname
and lastname
:username
name is required while lastname
is not requiredemail
include:.email({minDomainSegments: 2})
- It must be a valid email string and must have two domain parts e.g. user.com
. One fascinating thing about email validation with joi is that you can decide the top-level domains (TLDs) you want. e.g; you want only .com
and .net
.email({ minDomainSegments: 2, tlds: { allow: ['com', 'net'] } })
This will only allow .com
and .net
phonenumber
include:+248888888888
dob
include:Joi.date().max('01-01-2003').iso()
- it must be a valid date in ISO 8601 format and it cannot be after Jan 1, 2003. This is super useful if you want to ensure a certain age range can not register on your platform e.g a betting website allow only 18+.messages({'date.format':
Date format is YYYY-MM-DD
'date.max':Age must be 18+})
- This means if user enter invalid date format and joi throws error, rather sending back the not too fancy joi error message, send a custom message.
Custom messages breakdown:'date.format'
: means the error type i.e if joi is throwing error type that is 'date.format'
, then send this custom message Date format is YYYY-MM-DD
to the user. if error type is 'date.max':
then send this custom message Age must be 18+
. If there's no custom message for this particular error type (date.max
), joi will throw this '"dob" must be less than or equal to "2003-01-01T00:00:00.000Z"'
. To aid user experience, I decided to make it easy by sending "Age must be 18+"
rather than joi error message. You can literally send any message you pleased. Since it's a custom message, you're fully in control of the message. That's really cool 👌sex
include:.valid('male', 'female','transger')
- This means only 4 options are accepted i.e male
, female
, transgender
and others
. If user enter any other option aside from the 4, joi will throw this error "\"sex\" must be one of [male, female, transger, others]"
. This come in handy for analytics. You can easily know the genders that register on your platform.
const validation = schema.validate(req.body);data
from the body request and validates it against the schema
already defined.const { value, error } = validation;
if (error) {
const message = error.details.map(x => x.message);
res.status(422).json({
status: "error",
message: "Invalid request data",
data: message
});
map()
to pick out just the error message and not the whole error object.meta:Joi.array()
meta:Joi.object()
Joi.alternatives()
can be used to pass many alternatives like array, object, string etc. For example, in a scenario where you're either expecting an array or object, especially when you depend on an external API and you can't be so sure if the response would be an array or an object.meta:Joi.alternatives().try(Joi.object(), Joi.array())
Joi.array().items(Joi.string())
Joi.array().items(Joi.object())