feat(validation): replace fieldValidation with express-validator on products and tags

Add products.validators.js and tags.validators.js following the same
pattern as articles/users. Wire createProductRules, updateProductRules,
and createTagRules into their respective routes via the validate middleware.
Remove the local fieldValidation helper from both controllers and fix
missing return statements on next() calls in products.controller.js.
This commit is contained in:
2026-04-27 00:04:50 +02:00
parent 80cd96e006
commit 6641da9a3d
6 changed files with 47 additions and 22 deletions
+3 -12
View File
@@ -134,14 +134,10 @@ module.exports.getProduct = asyncHandler(async (req, res, next) => {
module.exports.createProduct = asyncHandler(async (req, res, next) => { module.exports.createProduct = asyncHandler(async (req, res, next) => {
const { loggedUser } = req; const { loggedUser } = req;
fieldValidation(req.body.product.title, next);
fieldValidation(req.body.product.description, next);
fieldValidation(req.body.product.body, next);
const { title, description, body, tagList } = req.body.product; const { title, description, body, tagList } = req.body.product;
const slugInDB = await Product.findOne({ where: { slug: slug(`${title}`) } }); const slugInDB = await Product.findOne({ where: { slug: slug(`${title}`) } });
if (slugInDB) { if (slugInDB) {
next(new ErrorResponse("Title already exists", 400)); return next(new ErrorResponse("Title already exists", 400));
} }
const product = await Product.create({ const product = await Product.create({
@@ -181,7 +177,7 @@ module.exports.deleteProduct = asyncHandler(async (req, res, next) => {
}); });
if (!product) { if (!product) {
next(new ErrorResponse("Product not found", 404)); return next(new ErrorResponse("Product not found", 404));
} }
if (product.authorId !== loggedUser.id) { if (product.authorId !== loggedUser.id) {
@@ -203,7 +199,7 @@ module.exports.updateProduct = asyncHandler(async (req, res, next) => {
}); });
if (!product) { if (!product) {
next(new ErrorResponse("Product not found", 404)); return next(new ErrorResponse("Product not found", 404));
} }
if (product.authorId !== loggedUser.id) { if (product.authorId !== loggedUser.id) {
return next(new ErrorResponse("Unauthorized", 401, "Authentication required.")); return next(new ErrorResponse("Unauthorized", 401, "Authentication required."));
@@ -277,8 +273,3 @@ module.exports.deleteFavoriteProduct = asyncHandler(async (req, res, next) => {
res.status(200).json({ product }); res.status(200).json({ product });
}); });
const fieldValidation = (field, next) => {
if (!field) {
return next(new ErrorResponse(`Missing fields`, 400));
}
};
-7
View File
@@ -4,8 +4,6 @@ const ErrorResponse = require("../utils/errorResponse");
module.exports.createTag = asyncHandler(async (req, res, next) => { module.exports.createTag = asyncHandler(async (req, res, next) => {
try { try {
fieldValidation(req.body.tag.name, next);
const { name } = req.body.tag; const { name } = req.body.tag;
const tagInDB = await TagService.tagIsInDB(name); const tagInDB = await TagService.tagIsInDB(name);
if (tagInDB) { if (tagInDB) {
@@ -60,8 +58,3 @@ module.exports.getAllTags = asyncHandler(async (req, res, next) => {
} }
}); });
const fieldValidation = (field, next) => {
if (!field) {
return next(new ErrorResponse(`Missing fields`, 400));
}
};
@@ -0,0 +1,27 @@
const { body } = require('express-validator');
const createProductRules = [
body('product.title')
.notEmpty().withMessage("can't be blank")
.isLength({ max: 255 }).withMessage('must be at most 255 characters')
.trim(),
body('product.description')
.notEmpty().withMessage("can't be blank")
.isLength({ max: 1000 }).withMessage('must be at most 1000 characters')
.trim(),
body('product.body')
.notEmpty().withMessage("can't be blank"),
];
const updateProductRules = [
body('product.title')
.optional()
.isLength({ max: 255 }).withMessage('must be at most 255 characters')
.trim(),
body('product.description')
.optional()
.isLength({ max: 1000 }).withMessage('must be at most 1000 characters')
.trim(),
];
module.exports = { createProductRules, updateProductRules };
@@ -0,0 +1,10 @@
const { body } = require('express-validator');
const createTagRules = [
body('tag.name')
.notEmpty().withMessage("can't be blank")
.isLength({ max: 50 }).withMessage('must be at most 50 characters')
.trim(),
];
module.exports = { createTagRules };
+3 -1
View File
@@ -1,10 +1,12 @@
const express = require('express'); const express = require('express');
const { createTag, deleteTag, getAllTags } = require('../../../controllers/tags.controller'); const { createTag, deleteTag, getAllTags } = require('../../../controllers/tags.controller');
const auth = require('../../../middlewares/auth'); const auth = require('../../../middlewares/auth');
const validate = require('../../../middlewares/validate');
const { createTagRules } = require('../../../middlewares/validators/tags.validators');
const tagRouter = express.Router(); const tagRouter = express.Router();
tagRouter.post('/', auth.required, createTag); tagRouter.post('/', auth.required, createTagRules, validate, createTag);
tagRouter.get('/', auth.optional, getAllTags); tagRouter.get('/', auth.optional, getAllTags);
tagRouter.delete('/:name', auth.required, deleteTag); tagRouter.delete('/:name', auth.required, deleteTag);
+4 -2
View File
@@ -9,13 +9,15 @@ const {
updateProduct, updateProduct,
} = require('../../../controllers/products.controller'); } = require('../../../controllers/products.controller');
const auth = require('../../../middlewares/auth'); const auth = require('../../../middlewares/auth');
const validate = require('../../../middlewares/validate');
const { createProductRules, updateProductRules } = require('../../../middlewares/validators/products.validators');
const productRouter = express.Router(); const productRouter = express.Router();
productRouter.get('/', auth.optional, getProducts); productRouter.get('/', auth.optional, getProducts);
productRouter.post('/', auth.required, createProduct); productRouter.post('/', auth.required, createProductRules, validate, createProduct);
productRouter.get('/:slug', auth.optional, getProduct); productRouter.get('/:slug', auth.optional, getProduct);
productRouter.put('/:slug', auth.required, updateProduct); productRouter.put('/:slug', auth.required, updateProductRules, validate, updateProduct);
productRouter.delete('/:slug', auth.required, deleteProduct); productRouter.delete('/:slug', auth.required, deleteProduct);
productRouter.post('/:slug/favorite', auth.required, addFavoriteProduct); productRouter.post('/:slug/favorite', auth.required, addFavoriteProduct);
productRouter.delete('/:slug/favorite', auth.required, deleteFavoriteProduct); productRouter.delete('/:slug/favorite', auth.required, deleteFavoriteProduct);