1. Settings
Before diving into the details of the examples, you should install Express Validator.
npm install express-validator
2. Questions
2.1 Validation Checks
Q) Now, we use Express Validator to check if the queries from the request comply with the conditions: the query must be in string format, not empty, and between 3 and 10 characters in length. As a tip, you should import the validationResult package from Express Validator and use method chaining to verify if all the conditions are met. Additionally, we can set up a custom message to display if any condition fails.
A)
import {query} from 'express-validator';
router.get("/api/products",query('filter')
.isString()
.notEmpty()
.withMessage("must not be empty")
.isLength({min:3,max:10})
.withMessage("must be at least 3-10 characters")
,(req,res)=>{
const result=validationResult(req);
console.log(result);
const {query:{filter,value},}=req;
if(!filter&&!value) return res.send(products);
if(filter&&value)
res.send(products.filter((product)=>product[filter].includes(value))).status(200);
})
Q) Let’s go over a validation problem one more time. We have two body parameters: one is a string for the label, and the other is an integer representing the popularity scale. In this section, you’ll need to check that the label isn’t empty and is between 3 and 40 characters long. As for popularity, the value should be an integer between 1 and 5
A)
import {query} from 'express-validator';
router.post("/api/products",
body("label")
.isString()
.withMessage("label must be a string")
.isLength({min:3,max:40})
.withMessage("label must be 3 charactesr with a max of 40")
.notEmpty()
.withMessage("label can not be empty"),
body("popularity")
.isInt({min:1,max:5})
.withMessage("Poular must be an integer betwen 1 and 5")
.toInt()
,(req,res)=>{
const result=validationResult(req);
console.log(result);
const {body}=req;
const newData={id:products[products.length-1].id+1,...body};
products.push(newData);
res.sendStatus(201);
})
Q) "In the code above, the line const { body } = req; works properly in your REST API server. However, you might want to explore alternative methods for receiving the body input and ensuring it complies with your predefined requirements."
Hint) importing 'matchedData' from 'express-validator'
router.post("/api/products",
productVaidators
,(req,res)=>{
const result=validationResult(req);
console.log(result);
if(!result.isEmpty())
//validationResult(req).array returns validation errors as an array
return res.status(400).sned({errors:result.array()});
//here is the improvement
const data=matchedData(req);
const newData={id:products[products.length-1].id+1,...data};
products.push(newData);
res.sendStatus(201);
})
Q)"Now, let's take it a step further and improve on the previous question. This time, we'll use the module and package system to organize the relevant files in a cleaner and more structured way. You can create a separate folder and add a file named validationSchema.mjs to store the general schema that the body parameters must adhere to."
-src
|-utils
|-validationScheam.mjs
|-index.mjs
//./src/utils/validationSchema.mjs
export const createUserValidationSchema={
label:{
isString:{
errorMessage:"Label must be a string"
},
isLength:{
options:{
min:3,
max:40,
},
errorMessage:"Label must be 3 charateriscts with a max of 40",
},
notEmpty:{
errorMessage:"Label cannot be empty",
}
},
popularity:{
isInt:{
options:{
min:1,
max:5
},
errorMessage:"Popularity must be an integer between 1 and 5",
toInt:true,
}
},
};
//index.mjs
import express from 'express';
import {query,validationResult,body,matchedData,checkSchema} from "express-validator";
import { createUserValidationSchema } from './utils/validationSchema.mjs';
app.post("/api/products",
//Don't forget to import 'checkShema and your own defined function object'
checkSchema(createUserValidationSchema)
,(req,res)=>{
const result=validationResult(req);
console.log(result);
if(!result.isEmpty())
//validationResult(req).array returns validation errors as an array
return res.status(400).sned({errors:result.array()});
//here is the improvement
const data=matchedData(req);
const newData={id:products[products.length-1].id+1,...data};
products.push(newData);
res.sendStatus(201);
})
Q) " Up to this point, we’ve been keeping all our endpoints and methods in a single file, the index.mjs file, almost as if we’re leaving them unorganized. This kind of file management will eventually lead to decreased readability of the code as the number of URLs and methods grows. Therefore, we plan to organize our code by creating folders based on specific purposes and placing the corresponding endpoints and methods in each folder. This is where routers come into play. "
-src
|-routes
|-products.mjs
|-users.mjs
|-utils
|-middlewares.mjs
|-constants.msj//where the data is stored
|-validationSchema.mjs
index.mjs//main file
/utils/constants.mjs
export const products=[
{
id:1,
label:"cookie",
popularity:5
},
{
id:2,
label:"pizza-2",
popularity:3
},
{
id:3,
label:"pizza-3",
popularity:2
}
]
//middleware.mjs
import { products } from "./constants.mjs";
export const logginMiddleware=(req,res,next)=>{
const currentDateTime=new Date();
console.log(`[${currentDateTime}] ${req.method} ${req.url}`);
next();
}
export const resolveByUserIndex=(req,res,next)=>{
const{params:{id}}=req;
const parsedId=parseInt(id);
if(isNaN(parsedId)) return res.sendStatus(400);
const findIndex=products.findIndex((product)=>product.id===parsedId);
if(findIndex===-1) return res.sendStatus(404);
//add extra option to the requeset
req.findIndex=findIndex;
next();
}
//product.mjs
import { Router} from "express";
import {query,validationResult,body,matchedData,checkSchema} from "express-validator";
import { products } from "../utils/constants.mjs";
import {createUserValidationSchema} from "../utils/validationSchema.mjs";
import { logginMiddleware,resolveByUserIndex } from "../utils/middleware.mjs";
const router=Router();
router.get("/products",logginMiddleware,(req,res)=>{
res.json(products);
})
router.get('/api/products',
query('filter')
.isString()
.notEmpty()
.withMessage("must not be empty")
.isLength({min:3,max:10})
.withMessage("must be at least 3-10 characters")
,(req,res)=>{
const result=validationResult(req);
console.log(result);
const {query:{filter,value},}=req;
if(!filter&&!value) return res.send(products);
if(filter&&value)
res.send(products.filter((product)=>product[filter].includes(value))).status(200);
}
);
router.get("/api/products/:id",(req,res)=>{
const parsedId=parseInt(req.params.id);
if(isNaN(parsedId))
return res.status(400).send({msg:"Bad request!not found"});
const foundProduct=products.find((product)=>product.id===parsedId);
if(!foundProduct) return res.sendStatus(404);
return res.send(foundProduct).status(200);
})
//POST//////////////////////////////////////////////////
router.post("/api/products",
checkSchema(createUserValidationSchema)
,(req,res)=>{
const result=validationResult(req);
console.log(result);
if(!result.isEmpty())
//validationResult(req).array returns validation errors as an array
return res.status(400).sned({errors:result.array()});
//here is the improvement
const data=matchedData(req);
const newData={id:products[products.length-1].id+1,...data};
products.push(newData);
res.sendStatus(201);
})
//PUT//////////////////////////////////////////////
router.put("/api/products/:id",resolveByUserIndex,(req,res)=>{
const{
body,
params:{id},
}=req;
const parsedId=parseInt(id);
products[req.findIndex]={id:parsedId,...body};
res.send(products).status(200);
})
//Delete/////////////////////////////
router.delete("/api/products/:id",resolveByUserIndex,(req,res)=>{
console.log(req.findIndex);
products.splice(req.findIndex,1);
console.log(products);
return res.status(200).send({msg:`The record with id=${req.params.id} has been successfully deleted! `});
});
//export router
export default router;
./index.mjs
import express from 'express';
import productsRouter from './routes/products.mjs';
import { products} from './utils/constants.mjs';
const app=express();
app.use(express.json());
//register product router
app.use(productsRouter);
//register extra router here...
const port=process.env.port||3000;
app.listen(port,()=>{
console.log(`Running on ${port}`);
})
🎶The Definition of Router in Node.js🎶
"In Node.js, a router is responsible for handling requests and determining how the application should respond to them based on the request's URL and HTTP method (e.g., GET, POST, PUT, DELETE).
Routers are typically used in frameworks like Express.js, which provide a simple and intuitive way to define and organize routes in your application."
💻 Better file management
//./routes/index.mjs
import { Router } from "express";
import productsRouter from './products.mjs';
const router=Router();
router.use(productsRouter);
///add more routers here
export default router;
//./index.mjs
import express from 'express';
import productsRouter from './routes/products.mjs';
import {indexRouter} from './routes/index.mjs';
const app=express();
app.use(express.json());
//register indexRouter here
app.use(indexRouter);
const port=process.env.port||3000;
//GET//////////////////////////////////////////////////
app.get('/',(req,res)=>{
res.send("Welcome to our home page");
})
app.listen(port,()=>{
console.log(`Running on ${port}`);
})
'Back-End > Node JS' 카테고리의 다른 글
3. CRUD/ MiddleWare (0) | 2025.01.16 |
---|