Node.js中如何验证API请求?POST数据验证遇Joi使用难题
Got it, let's get that Joi validation working for your POST endpoint. I'll walk you through the exact steps to integrate it properly into your existing code.
Step 1: Install Joi (if you haven't already)
First, make sure you have Joi installed in your project. Run this command in your terminal:
npm install joi # Or if you use yarn: yarn add joi
Step 2: Define Your Validation Schema
You need to create a Joi schema that describes the valid structure of your POST body. For your ProductName field, let's match your SQL VarChar(50) requirement with a required string that can't exceed 50 characters. Here's how to define it:
const Joi = require('joi'); // Define the validation schema with custom error messages const productSchema = Joi.object({ ProductName: Joi.string() .max(50) .required() .messages({ 'string.empty': 'ProductName cannot be left empty', 'string.max': 'ProductName must be less than 50 characters long', 'any.required': 'ProductName is a mandatory field' }) });
The messages block is optional but super helpful for returning user-friendly feedback instead of generic Joi errors.
Step 3: Integrate Validation into Your POST Endpoint
Now update your existing POST route to validate the request body before you touch any database operations. Here's the modified version of your code:
appRouter.route('/') .post(async function (req, res) { try { // Validate the incoming request body against our schema const { error, value } = productSchema.validate(req.body); if (error) { // Return 400 Bad Request with the specific validation error return res.status(400).json({ success: false, message: error.details[0].message }); } // If validation passes, proceed with database logic await conn.connect(); const transaction = new sql.Transaction(conn); await transaction.begin(); const request = new sql.Request(transaction); // Use the validated value instead of raw req.body for safety request.input("ProductName", sql.VarChar(50), value.ProductName); // Replace with your actual INSERT query await request.query('INSERT INTO Products (ProductName) VALUES (@ProductName)'); await transaction.commit(); res.status(201).json({ success: true, message: 'Product created successfully' }); } catch (err) { // Handle database errors or unexpected issues if (transaction) await transaction.rollback(); res.status(500).json({ success: false, message: 'Failed to create product', error: err.message }); } finally { // Clean up the database connection if (conn) conn.close(); } });
Key Things to Note:
- We use
productSchema.validate(req.body)to check incoming data. Theerrorobject exists if validation fails, andvalueis the sanitized/validated data (always use this instead of rawreq.bodyto avoid unexpected inputs). - Return a 400 status code for validation errors—this tells the client they sent invalid data, not a server issue.
- Wrapping everything in
try/catchensures we handle both validation errors and database exceptions, including rolling back transactions if something goes wrong mid-process.
Extending the Schema (If You Add More Fields)
If your POST body includes additional fields like Price or StockQuantity, just expand the schema:
const productSchema = Joi.object({ ProductName: Joi.string().max(50).required(), Price: Joi.number().positive().required(), StockQuantity: Joi.number().integer().min(0).required() });
That's it! This setup will block invalid data from reaching your database and give clear feedback to clients.
内容的提问来源于stack exchange,提问作者Saineshwar Bageri - MVP

