Search code examples
expressexpress-validator

Why is express-validator not rejecting this request?


why is express-validator not rejecting this request?

import { Router, Request, Response } from 'express'
import { header } from 'express-validator'

if (!process.env.CRONJOB_SECRET) {
  console.error('Please set CRONJOB_SECRET')
  process.exit(1)
}

const router = Router()

/**
 * start/stop jobs every minute
 */
router.get(
  '/start-stop-jobs',
  header('x-cronjob-secret').equals(process.env.CRONJOB_SECRET),
  async (req: Request, res: Response) => {
    const log = {
      secret: process.env.CRONJOB_SECRET,
      equals: req.headers['x-cronjob-secret'],
      started: [],
      stopped: [],
      error: {},
    }
    // stop any events
    console.log('Completed /start-stop-jobs', log)
    return res.json({ status: 'ok', log })
  },
)

When I GET /start-stop-jobs, without a header, I get this response:

{"status":"ok","log":{"secret":"CRONJOB_SECRET","started":[],"stopped":[],"error":{}}}

This seems like a trivial use case. What am I missing?


Solution

  • That should be because "express-validator" needs another validationResult function to be called. Per the doc:

    // ...rest of the initial code omitted for simplicity.
    const { body, validationResult } = require('express-validator');
    
    app.post(
      '/user',
      // username must be an email
      body('username').isEmail(),
      // password must be at least 5 chars long
      body('password').isLength({ min: 5 }),
      (req, res) => {
        // Finds the validation errors in this request and wraps them in an object with handy functions
        const errors = validationResult(req);
        if (!errors.isEmpty()) {
          return res.status(400).json({ errors: errors.array() });
        }
    
        User.create({
          username: req.body.username,
          password: req.body.password,
        }).then(user => res.json(user));
      },
    );
    

    Note the call to const errors = validationResult(req); after the validation specification codes, leading to immediate returning res.status(400) if there are errors. That is the missing part in your code.

    You could extract this functionality into another middleware if you don't want repeating code

    // middlewares/handleValidationError.js
    const { validationResult } = require("express-validator");
    
    exports.handleValidationError = function (req, res, next) {
      // Finds the validation errors in this request and wraps them in an object with handy functions
      const errors = validationResult(req);
      if (!errors.isEmpty()) {
        return res.status(400).json({ errors: errors.array() });
      }
      next();
    };
    
    // Using the middleware
    // App.js
    
    const { handleValidationError } = require("/middlewares/handleValidationError");
    
    router.get(
      "/start-stop-jobs",
      header("x-cronjob-secret").equals(process.env.CRONJOB_SECRET),
      handleValidationError,
      async (req: Request, res: Response) => {
        const log = {
          secret: process.env.CRONJOB_SECRET,
          equals: req.headers["x-cronjob-secret"],
          started: [],
          stopped: [],
          error: {},
        };
        // stop any events
        console.log("Completed /start-stop-jobs", log);
        return res.json({ status: "ok", log });
      }
    );