joi

path: courses/express-node/joi.md

- **fileName**: joi
- **Created on**: 2024-08-19 19:07:00

looking for joi validator for express js installation npm i joi

Code Example:

import express from "express";
import Joi from "joi";

const app = express();
app.use(express.json())


// starting creating schema using joi
const schemaSaveRoute = Joi.object({ // this is the schema for the user
    username: Joi.string().required().min(3).max(30).alphanum(),
    age: Joi.number().required()
})


app.get("/", (req, res) => {
    res.status(200).json({ massage: "welcome from yossef "});
});

app.post("/save", (req, res) => {
    const result = schemaSaveRoute.validate(req.body); // check for error if found return them 
    console.log(result);
    if(result.error) { // check if there any error return the error
        return res.status(400).json({ errors : Array(result.error.details)})
    }
    return res.status(200).json({massage: "has access to the end point"});
})


app.listen(3000, () => {
    console.log("runinng in port:", 3000)
})


- const result = schemaSaveRoute.validate(req.body); // check for error if found return them
- so what this line do every schema from Joi have and function called validate and gave req.body as param for the funciton now the function get the req body and checck for the schema if match return the value only like this

{ value: { username: 'yossef', age: 2342 } } // this is the output from the console

- else if found an error show this console

{
  value: { username: 'yossef' },
  error: [Error [ValidationError]: "age" is required] {
    _original: { username: 'yossef' },
    details: [ [Object] ]
  }
}

using for advanced way

import joi from 'joi';
import { generalFields } from '../../Utlis/GeneralFields.js';



export const updateUserScehma = joi.object({
    name:joi.string().min(2).max(50),
    phone: generalFields.phone,
    headline:joi.string().min(3).max(100),
    gender:joi.string()
}).required()



export const recoverUserScehma = joi.object({
    token:generalFields.token
}).required()

1
export const acceptconnectionScehma = joi.object({
    userId:generalFields.id,
    connection:joi.string().valid('accept','reject')
}).required()


// general fields
import joi from "joi";
import { Types } from "mongoose";

// check if the value is a valid ObjectId
const checkObjectId = (value, helper) => {
  return Types.ObjectId.isValid(value)
    ? true
    : helper.message("Invalid ObjectId");
};

// General Fields for the application
export const generalFields = {
  name: joi.string().required(),
  description: joi.string().required(),
  id: joi.string().custom(checkObjectId).required(),
  gender:joi.string().valid('male','female'),
  email: joi
    .string()
    .email({ minDomainSegments: 2, tlds: { allow: ["com", "net"] } })
    .required(),
  password: joi
    .string()
    .pattern(/^\w{8,}$/)
    .messages({ "string.pattern.base": "Password length should be atleast 8" })
    .required(),
  confirmPassword: joi
    .string()
    .required()
    .messages({ "any.only": "confirm password not matching new password" }),
  age: joi.number().integer().required(),
  phone: joi
    .string()
    .pattern(/^(\+2)?01[0125][0-9]{8}$/)
    .messages({ "string.pattern.base": "please Enter a valid phone Number" })
};


adding validation(schema) give it the schema and check for param and query and body and file for all checks for the validation

/** 
 * @param {object} schema - Joi schema object
 * @return {function} Middleware for the next function
 * description: Middleware to validate the inputs
 * */
const validation = (schema) => {
    return (req,res,next)=>{
        // indestruct the inputs
        const inputs = {...req.body,...req.params,...req.query}
        if(req.file || req.files)
        {
            inputs.file = req.file || req.files
        }
        // abortearly false to return all the errors
        const validationResult = schema.validate(inputs,{abortEarly:false})

        // check if there is errors
        if(validationResult.error)
        {
            return res.status(409).json({status:'failed',errors:validationResult.error.details.map(err=>err.message)})
        }
        return next()
    }
}
export default validation;

using with end point

import validation from "./validation.mjs" // adding the validation function for all checks for validate
import userSchema from "./UserSchema.mjs"

app.post("/save", validation(userSchema),(req, res) => {
    return res.status(200).json({massage: "has access to the end point"});
})

now how this works first there is afunction for validation its work for all query, body, param check for all second call the function for validate the build in any schema joi and give the inputs{ req.body, req.query, req.param} any one from this and after this gone check for the inputs and the validateScame if match then very thing is good else gone return a error object insdie the validationResult after this return error massage and return the error in validateResult.error and done else don't return any error object that mean that the schema i equl to the inputs and passing and going for the next middleware if found

option in joi:

Method Description Example Usage
string() Validates that the value is a string. Joi.string()
number() Validates that the value is a number (integer or float). Joi.number()
boolean() Validates that the value is a boolean. Joi.boolean()
array() Validates that the value is an array. Joi.array()
object() Validates that the value is an object. Joi.object()
date() Validates that the value is a date. Joi.date()
any() The most general type; can be used to validate any data type. Joi.any()
min(length) Sets a minimum length for strings, arrays, or numbers (for numbers, it sets a minimum value). Joi.string().min(5)
max(length) Sets a maximum length for strings, arrays, or numbers (for numbers, it sets a maximum value). Joi.string().max(10)
required() Specifies that the field must be present and cannot be undefined or null. Joi.string().required()
optional() Specifies that the field is optional. Joi.string().optional()
default(value) Assigns a default value if the field is not present or is undefined. Joi.string().default('default value')
pattern(regex) Validates that the string matches the given regular expression pattern. Joi.string().pattern(/^[a-zA-Z0-9]{3,30}$/)
email() Validates that the string is a valid email address. Joi.string().email()
uri() Validates that the string is a valid URI. Joi.string().uri()
alphanum() Validates that the string contains only alphanumeric characters. Joi.string().alphanum()
trim() Removes leading and trailing whitespace from the string. Joi.string().trim()
lowercase() Converts the string to lowercase before validation. Joi.string().lowercase()
uppercase() Converts the string to uppercase before validation. Joi.string().uppercase()
valid(...values) Validates that the value matches one of the specified values (enumeration). Joi.string().valid('a', 'b', 'c')
invalid(...values) Ensures that the value does not match any of the specified values. Joi.string().invalid('a', 'b', 'c')
length(value) Specifies the exact length of a string or array, or the exact value of a number. Joi.string().length(8)
greater(limit) Validates that the number is greater than the specified limit. Joi.number().greater(10)
less(limit) Validates that the number is less than the specified limit. Joi.number().less(100)
integer() Validates that the number is an integer. Joi.number().integer()
positive() Validates that the number is positive. Joi.number().positive()
negative() Validates that the number is negative. Joi.number().negative()
exist() Validates that the field exists (alias for required()). Joi.exist()
allow(...values) Allows specified values to pass validation without applying any further rules. Joi.string().allow(null, '')
forbidden() Ensures that the field is not present. Joi.string().forbidden()
when(condition, options) Conditional validation based on another field's value. Joi.string().when('otherField', { is: 'someValue', then: Joi.required() })
not(...values) Validates that the value does not match any of the specified values. Joi.string().not('a', 'b', 'c')
empty(schema) Considers the value to be empty if it matches the provided schema (e.g., an empty string or null). Joi.string().empty('')
insensitive() Validates that the string comparison is case-insensitive. Joi.string().valid('abc').insensitive()
error(message) Customizes the error message for validation failures. Joi.string().min(5).error(new Error('Custom error message'))
regex() Validates that the string matches a regular expression pattern (similar to pattern()). Joi.string().regex(/^[a-zA-Z0-9]{3,30}$/)
uuid() Validates that the string is a valid UUID (Universally Unique Identifier). Joi.string().uuid()
hex() Validates that the string is a valid hexadecimal number. Joi.string().hex()
ip() Validates that the string is a valid IP address. Joi.string().ip()
port() Validates that the number is a valid TCP/UDP port. Joi.number().port()
hostname() Validates that the string is a valid hostname. Joi.string().hostname()
isoDate() Validates that the string is a valid ISO 8601 date. Joi.date().iso()
insensitive() Validates case-insensitive string comparisons for valid() values. Joi.string().valid('abc').insensitive()

continue:[[]]
before:jwt.md