javascriptnode.jsmongodbexpressjoi

How to validate an array of objects in a request body using JOI


I am trying to validate the request body of an order placed. I recieve an array of json objects on the request body that I am trying to validate. Everytime I get the error " "productId" is required"

Here is my request body:

req.body={
    "productId": [
        { "id": "5dd635c5618d29001747c01e", "quantity": 1 },
        { "id": "5dd63922618d29001747c028", "quantity": 2 },
        { "id": "5dd635c5618d29001747c01e", "quantity": 3 }
    ]
}

Here is the valdateOrder function to validate the request body:

function validateOrder(req.body) {
    const schema = {

        productId: joi.array().items(
            joi.object().keys({
                id: joi.string().required(),
                quantity: joi.string().required()
            })).required(),
    }

    return joi.validate(req.body, schema)

}

I would be really thankful if anyone can point out whats wrong with my validateOrder function.


Solution

  • This seems an odd way to go about it. As per https://hapi.dev/module/joi/, define your schema as its own thing, then validate your data using that schema:

    const Joi = require('@hapi/joi');
    
    const schema = Joi.object({
      productId: Joi.array().items(
        Joi.object(
          id: Joi.string().required(),
          quantity: Joi.number().required()
        )
      )
    };
    
    module.exports = schema;
    

    And then you validate with that in your route middleware:

    const Joi = require('@hapi/joi');
    const schema = require(`./your/schema.js`);
    
    function validateBody(req, res, next) {
      // If validation passes, this is effectively `next()` and will call
      // the next middleware function in your middleware chain.
    
      // If it does not, this is efectively `next(some error object)`, and
      // ends up calling your error handling middleware instead. If you have any.
    
      next(schema.validate(req.body));
    }
    
    module.exports = validateBody;
    

    Which you use like any other middleware in express:

    const validateBody = require(`./your/validate-body.js`);
    
    // general error handler (typically in a different file)
    function errorHandler(err, req, res, next) {
      if (err === an error you know comes form Joi) {
        // figure out what the best way to signal "your POST was bad"
        // is for your users
        res.status(400).send(...);
      }
      else if (...) {
        // ...
      }
      else {
        res.status(500).send(`error`);
      }
    });
    
    // and then tell Express about that handler
    app.use(errorHandler);
    
    // and then you inclide your body validator in your
    // post handling middleware chain:
    app.post(
      `route`,
      ...,
      validateBody,
      ...,
      (req, res) => res.json(...)
    );