Dashiell Rose Bark-Huss
Dashiell Rose Bark-Huss

Reputation: 2965

Express Validator: How to make conditional validations based on other fields?

How can I write custom validations for express-validator that rely on information from other fields?

Example Problem:


I have a wishlist app where users can buy items for the wishlist owner. They can leave a note with that item. The note must have less characters than the price of the item.
Post Request: "/purchase"
Body: {
"itemId": "1",
"note": "I'm buying this to say thank you for your help with my Chinese practice. You helped me understand tones better."
}

In the database, the item with ID 1 is $100. This note is 111 characters. 111 is greater than 100 so it should not validate.


I can't figure out how to access the other fields in a custom validator using express-validator so I can't figure out how to write this validation.

I can successfully limit the note length to a constant length, example 100 characters. But how do I make that character length value equal to the price of the item: data.items.find((i) => i.itemId === +req.body.itemId).price;? Is there a way to access req.body within the body() middleware?

  body('note', `Note must be 100 or less characters`).custom((note) => note.length <= 100),

Full code:

const { body, validationResult } = require('express-validator');
const express = require('express');
const bodyParser = require('body-parser');

const app = express();
const data = {
  items: [
    { itemId: 1, price: 100 },
    { itemId: 2, price: 50 },
  ],
};

app.use(bodyParser.json());
app.post(
  '/purchase',
  body('note', `Note must be 100 or less characters`).custom((note) => note.length <= 100),
  (req, res, next) => {
    const errors = validationResult(req).array();
    if (errors.length) {
      return res.status(400).send(errors);
    }
    return next();
  },
  (req, res, next) => {
    const itemPrice = data.items.find((i) => i.itemId === +req.body.itemId).price;
    res.status(200).send({
      message: `Item ${req.body.itemId} purchased for $${itemPrice}`,
    });
  }
);

app.listen(3500);

Upvotes: 2

Views: 3282

Answers (1)

Dashiell Rose Bark-Huss
Dashiell Rose Bark-Huss

Reputation: 2965

I found out you can pass the request object to the custom validator.

const { body, validationResult } = require('express-validator');
const express = require('express');
const bodyParser = require('body-parser');

const app = express();
const data = {
  items: [
    { itemId: 1, price: 100 },
    { itemId: 2, price: 50 },
  ],
};

app.use(bodyParser.json());
app.post(
  '/purchase',
  body('note', `Note too long.`).custom(
    (note, { req, location, path }) =>
      note.length <= data.items.find((i) => i.itemId === +req.body.itemId).price
  ),
  (req, res, next) => {
    const errors = validationResult(req).array();
    if (errors.length) {
      const noteError = errors.find((err) => err.msg === 'Note too long.');
      if (noteError)
        noteError.msg = `Note must be less than ${
          data.items.find((i) => i.itemId === +req.body.itemId).price
        } characters`;
      return res.status(400).send(errors);
    }
    return next();
  },
  (req, res, next) => {
    const itemPrice = data.items.find((i) => i.itemId === +req.body.itemId).price;
    res.status(200).send({
      message: `Item ${req.body.itemId} purchased for $${itemPrice}`,
    });
  }
);

app.listen(3500);

The reference link to this with examples is at: the official express-validator docs

Upvotes: 3

Related Questions