Routing System¶
Relevant source files * proyecto.zip * src/router.js
Purpose and Scope¶
The Routing System is the central request routing mechanism for the registro-sesiones application. It defines all HTTP endpoints, maps URL paths to handler functions, applies middleware for authentication and validation, and coordinates between the presentation layer (views) and business logic (controllers). This document covers the router architecture, route organization, middleware integration, and handler patterns.
For details on specific route categories, see:
- Public Routes - unauthenticated endpoints
- Protected Routes - authenticated user and admin endpoints
- API Endpoints - RESTful data endpoints
For authentication middleware specifics, see Authentication & Authorization.
Sources: src/router.js L1-L607
Router Architecture¶
Express Router Setup¶
The routing system is implemented using Express.js Router and exported as a module that is mounted in the main application. The router is configured with dependencies for authentication, validation, file uploads, and database access.
flowchart TD
RouterInstance["express.Router()<br>Line 2"]
ExpressValidator["express-validator<br>body, validationResult"]
BCrypt["bcryptjs<br>Password Hashing"]
DB["database/db<br>MySQL Connection"]
JWT["jsonwebtoken<br>Token Management"]
Puppeteer["puppeteer<br>PDF Generation"]
PDFKit["pdfkit<br>PDF Creation"]
EJS["ejs<br>Template Rendering"]
VerifyToken["verifyToken<br>src/middlewares/verifyToken"]
VerifyAdmin["verifyAdmin<br>src/middlewares/verifyAdmin"]
Upload["upload<br>src/middlewares/multerConfig"]
Limiter["limiter<br>src/middlewares/authLimiter"]
CRUD["crud<br>src/controllers"]
ExternalApp["index.js<br>app.use('/', router)"]
RouterInstance --> ExternalApp
subgraph subGraph3 ["Router Module - src/router.js"]
RouterInstance
RouterInstance --> ExpressValidator
RouterInstance --> BCrypt
RouterInstance --> DB
RouterInstance --> JWT
RouterInstance --> Puppeteer
RouterInstance --> PDFKit
RouterInstance --> EJS
RouterInstance --> VerifyToken
RouterInstance --> VerifyAdmin
RouterInstance --> Upload
RouterInstance --> Limiter
RouterInstance --> CRUD
subgraph Controllers ["Controllers"]
CRUD
end
subgraph subGraph1 ["Middleware Imports"]
VerifyToken
VerifyAdmin
Upload
Limiter
end
subgraph Dependencies ["Dependencies"]
ExpressValidator
BCrypt
DB
JWT
Puppeteer
PDFKit
EJS
end
end
Sources: src/router.js L1-L22
Route Categories and Organization¶
The router defines 21 routes organized into three main categories: public routes, protected routes, and API endpoints. Routes are registered using HTTP verb methods (router.get(), router.post()) with optional middleware chains.
Route Registration Pattern¶
Routes follow a consistent registration pattern:
router.<method>("<path>", [middleware1, middleware2, ...], handlerFunction)
Complete Route Map¶
| HTTP Method | Path | Middleware | Handler Type | Purpose |
|---|---|---|---|---|
| GET | / |
None | View | Home page with optional user info |
| GET | /login |
None | View | Login form |
| GET | /registro |
None | View | Registration form |
| GET | /admin |
verifyToken |
View | Product management dashboard |
| GET | /pdfAdmin |
verifyToken |
View | PDF preview page |
| GET | /create |
None | View | Create product form |
| GET | /edit/:id |
None | View | Edit product form |
| GET | /delete/:id |
None | Redirect | Delete product and redirect |
| GET | /logout |
None | Redirect | Clear JWT cookie and redirect |
| GET | /soporte |
verifyToken |
View | Support chat interface |
| GET | /api/mensajes |
verifyAdmin |
JSON | Get messages for specific user |
| GET | /api/mensajes/mios |
verifyToken |
JSON | Get current user's messages |
| GET | /api/usuarios-conversaciones |
verifyAdmin |
JSON | Get list of users with conversations |
| GET | /pdf/descargar |
verifyToken |
Download PDF (Puppeteer) | |
| GET | /pdfkit/descargar |
verifyToken |
Download PDF (PDFKit) | |
| GET | /set-lang/:lang |
None | Redirect | Set language preference |
| POST | /register |
upload.single(), validation |
View | User registration |
| POST | /auth |
limiter |
View | User authentication |
| POST | /save |
None | Redirect | Create product (via controller) |
| POST | /update |
None | Redirect | Update product (via controller) |
Sources: src/router.js L59-L604
Route Handler Types¶
The routing system implements four distinct handler patterns based on the type of response generated.
flowchart TD
Request["HTTP Request"]
Router["Express Router"]
ViewHandler["View Handler<br>res.render()"]
APIHandler["API Handler<br>res.json()"]
RedirectHandler["Redirect Handler<br>res.redirect()"]
PDFHandler["PDF Handler<br>res.send(buffer)"]
EJSEngine["EJS Template Engine"]
HTMLResponse["HTML Response"]
JSONResponse["JSON Response"]
HTTPRedirect["302/301 Response"]
PDFEngine["Puppeteer or PDFKit"]
PDFResponse["PDF Binary Response"]
Request --> Router
Router --> ViewHandler
Router --> APIHandler
Router --> RedirectHandler
Router --> PDFHandler
ViewHandler --> EJSEngine
EJSEngine --> HTMLResponse
APIHandler --> JSONResponse
RedirectHandler --> HTTPRedirect
PDFHandler --> PDFEngine
PDFEngine --> PDFResponse
Sources: src/router.js L59-L604
View Handlers¶
View handlers render EJS templates and return HTML responses. They query the database when needed and pass data to templates via the res.render() method.
Example: Home Page Handler
// Lines 59-74
router.get("/", (req, res) => {
if (req.cookies.token) {
const payload = jwt.verify(req.cookies.token, process.env.JWT_SECRET);
req.user = payload;
res.render("index", {
user: req.user?.name || "Usuario",
login: true,
});
} else {
res.render("index", {
user: "Debe iniciar sesión",
login: false,
});
}
});
View Handler Routes:
/- Rendersindex.ejs/login- Renderslogin.ejs/registro- Rendersregister.ejs/admin- Rendersadmin.ejswith product data/pdfAdmin- RenderspdfTabla.ejsfor PDF preview/create- Renderscreate.ejs/edit/:id- Rendersedit.ejswith product data/soporte- Renderssoporte.ejswith user data
Sources: src/router.js L59-L80
API Handlers¶
API handlers return JSON responses for data retrieval. These endpoints are consumed by client-side JavaScript for dynamic functionality.
Example: Get User Messages Handler
// Lines 256-280
router.get("/api/mensajes/mios", verifyToken, (req, res) => {
const usuario = req.user.user;
if (!usuario) {
return res.status(403).json({ error: "No autorizado" });
}
const sql = `
SELECT de_usuario, para_usuario, mensaje, fecha
FROM mensajes
WHERE
(de_usuario = ? OR para_usuario = ?)
ORDER BY fecha ASC
`;
db.query(sql, [usuario, usuario], (err, results) => {
if (err) {
console.error("❌ Error al obtener mensajes:", err);
return res.status(500).json({ error: "Error interno" });
}
res.json(results);
});
});
API Handler Routes:
/api/mensajes?con=<username>- Returns messages for specific user (admin only)/api/mensajes/mios- Returns current user's messages/api/usuarios-conversaciones- Returns list of users with conversations (admin only)
Sources: src/router.js L229-L253
Redirect Handlers¶
Redirect handlers perform an action and redirect the user to another page using res.redirect().
Example: Logout Handler
// Lines 215-218
router.get("/logout", (req, res) => {
res.clearCookie("token");
res.redirect('/');
});
Redirect Handler Routes:
/delete/:id- Deletes product and redirects to/admin/logout- Clears JWT cookie and redirects to//set-lang/:lang- Sets language cookie and redirects toreturnToparameter
Sources: src/router.js L198-L208
PDF Generation Handlers¶
PDF handlers generate PDF documents and return them as binary responses with appropriate headers. The system implements two PDF generation approaches.
Puppeteer-based Handler (HTML to PDF):
// Lines 317-353
router.get("/pdf/descargar", verifyToken, async (req, res) => {
db.query("SELECT * FROM productos", async (error, results) => {
if (error) {
return res.status(500).send("Error al obtener productos");
}
try {
const html = await ejs.renderFile(path.join(__dirname, "../views/pdfTabla.ejs"), {
productos: results
});
const browser = await puppeteer.launch({
headless: true,
args: ["--no-sandbox", "--disable-setuid-sandbox"],
});
const page = await browser.newPage();
await page.setContent(html, { waitUntil: "networkidle0" });
const pdfBuffer = await page.pdf({
format: "A4",
printBackground: true,
margin: { top: "20px", bottom: "20px" },
});
await browser.close();
res.setHeader("Content-Type", "application/pdf");
res.setHeader("Content-Disposition", 'attachment; filename="productos.pdf"');
res.send(pdfBuffer);
} catch (err) {
console.error("❌ Error al generar el PDF:", err);
res.status(500).send("Error interno al generar el PDF");
}
});
});
PDFKit-based Handler (Programmatic PDF):
// Lines 355-396
router.get("/pdfkit/descargar", verifyToken, (req, res) => {
db.query("SELECT * FROM productos", (error, results) => {
if (error) {
return res.status(500).send("Error al obtener productos");
}
const doc = new PDFDocument({ margin: 40, size: 'A4' });
res.setHeader("Content-Disposition", 'attachment; filename="productos_desde_cero.pdf"');
res.setHeader("Content-Type", "application/pdf");
doc.pipe(res);
// Title
doc.fontSize(18).text("Listado de Productos", { align: "center" }).moveDown();
// Table headers
doc.font("Helvetica-Bold").fontSize(12);
let y = doc.y;
doc.text("Referencia", 50, y);
doc.text("Nombre", 150, y);
doc.text("Precio", 300, y);
doc.text("Stock", 380, y);
y += 20;
doc.font("Helvetica").fontSize(11);
results.forEach((p) => {
doc.text(p.ref.toString(), 50, y);
doc.text(p.nombre, 150, y);
doc.text(Number(p.precio).toFixed(2), 300, y);
doc.text(p.stock.toString(), 380, y);
y += 20;
});
doc.end();
});
});
Sources: src/router.js L317-L353
Middleware Integration¶
The routing system integrates five types of middleware to handle authentication, authorization, file uploads, rate limiting, and input validation.
flowchart TD
IncomingRequest["HTTP Request"]
RouteDefinition["Route Definition"]
MW_Check["Middleware<br>Specified?"]
MW_Chain["Middleware Chain"]
Handler["Route Handler"]
VerifyToken["verifyToken<br>JWT Validation"]
VerifyAdmin["verifyAdmin<br>Role Check"]
Upload["upload.single()<br>File Upload"]
Limiter["limiter<br>Rate Limiting"]
Validator["express-validator<br>Input Validation"]
TokenValid["Token Valid?"]
NextMW["next()"]
Reject401["401 Response"]
IsAdmin["User is Admin?"]
NextMW2["next()"]
Reject403["403 Response"]
IncomingRequest --> RouteDefinition
RouteDefinition --> MW_Check
MW_Check --> MW_Chain
MW_Check --> Handler
VerifyToken --> TokenValid
TokenValid --> NextMW
TokenValid --> Reject401
VerifyAdmin --> IsAdmin
IsAdmin --> NextMW2
IsAdmin --> Reject403
NextMW --> Handler
NextMW2 --> Handler
subgraph subGraph0 ["Middleware Types"]
MW_Chain
VerifyToken
VerifyAdmin
Upload
Limiter
Validator
MW_Chain --> VerifyToken
MW_Chain --> VerifyAdmin
MW_Chain --> Upload
MW_Chain --> Limiter
MW_Chain --> Validator
end
Sources: src/router.js L16-L21
Authentication Middleware (verifyToken)¶
The verifyToken middleware validates JWT tokens from cookies and attaches user information to req.user. Applied to routes requiring any authenticated user.
Routes using verifyToken:
/admin- Product management (line 119)/pdfAdmin- PDF preview (line 136)/soporte- Support chat (line 220)/api/mensajes/mios- User's messages (line 256)/pdf/descargar- PDF download (line 317)/pdfkit/descargar- PDFKit download (line 355)
Sources: src/router.js L16
Authorization Middleware (verifyAdmin)¶
The verifyAdmin middleware checks if the authenticated user has the admin role. Applied after verifyToken to restrict access to administrative functions.
Routes using verifyAdmin:
/api/mensajes?con=<user>- Get any user's messages (line 229)/api/usuarios-conversaciones- Get conversation list (line 283)
Sources: src/router.js L17
File Upload Middleware (upload)¶
The upload middleware from multer handles multipart form data for file uploads. Configured to accept a single file with the field name profileImage.
Routes using upload:
- POST
/register- Profile image upload (line 414)
Sources: src/router.js L19
Rate Limiting Middleware (limiter)¶
The limiter middleware implements rate limiting to prevent brute force attacks on authentication endpoints.
Routes using limiter:
- POST
/auth- Login rate limiting (line 532)
Sources: src/router.js L21
Input Validation Middleware¶
The express-validator library provides validation middleware through the body() function. Validation rules are defined inline and checked using validationResult().
Routes using validation:
- POST
/register- Validates user, name, pass, email, edad fields (lines 415-428)
Validation Rules:
// Lines 415-428
[
body("user")
.exists()
.isLength({ min: 4 })
.withMessage("El usuario debe tener al menos 4 caracteres"),
body("name")
.isLength({ min: 4 })
.withMessage("El nombre debe tener al menos 4 caracteres"),
body("pass")
.isLength({ min: 4 })
.withMessage("La contraseña debe tener al menos 4 caracteres"),
body("email").isEmail().withMessage("El email no es valido"),
body("edad").isNumeric().withMessage("La edad debe ser un número"),
]
Sources: src/router.js L3
POST Route Handlers¶
POST routes handle form submissions and data modifications. They implement authentication, file uploads, validation, and business logic before responding with views or redirects.
User Registration Handler¶
The registration handler is the most complex POST route, combining file upload, input validation, password hashing, and database insertion.
flowchart TD
POST_Register["POST /register"]
Upload_MW["upload.single('profileImage')"]
Validation_MW["Validation Middleware Array"]
Handler["Registration Handler"]
Validate_Check["Validation<br>Errors?"]
Render_Errors["res.render('register')<br>with errors and values"]
Extract_Data["Extract Form Data<br>user, name, rol, pass, profileImage"]
Hash_Password["bcrypt.hash(pass, 8)"]
DB_Insert["db.query('INSERT INTO usuarios')"]
Success_Check["Insert<br>Success?"]
Render_Success["res.render('register')<br>with success alert"]
Log_Error["console.log(error)"]
POST_Register --> Upload_MW
Upload_MW --> Validation_MW
Validation_MW --> Handler
Handler --> Validate_Check
Validate_Check --> Render_Errors
Validate_Check --> Extract_Data
Extract_Data --> Hash_Password
Hash_Password --> DB_Insert
DB_Insert --> Success_Check
Success_Check --> Render_Success
Success_Check --> Log_Error
Sources: src/router.js L414-L484
Handler Details:
- File Upload (line 414):
upload.single("profileImage")processes multipart form data - Validation (lines 415-428): 5 validation rules for user, name, pass, email, edad
- Error Handling (lines 430-442): If validation fails, re-render form with errors and previous values
- Password Hashing (line 453):
bcrypt.hash(pass, 8)with 8 salt rounds - Database Insert (lines 456-480): Insert new user record with hashed password and profile image filename
- Success Response (lines 469-478): Render registration page with SweetAlert success message
Sources: src/router.js L414-L484
Authentication Handler¶
The authentication handler validates credentials, generates JWT tokens, and sets secure HTTP-only cookies.
flowchart TD
POST_Auth["POST /auth"]
Limiter_MW["Rate Limiter Middleware"]
Auth_Handler["Authentication Handler"]
Extract_Creds["Extract user and pass<br>from req.body"]
Creds_Check["Credentials<br>Provided?"]
Render_Error1["res.render('login')<br>with error alert"]
DB_Query["db.query('SELECT * FROM usuarios<br>WHERE usuario = ?')"]
User_Check["User Found &<br>Password Valid?"]
Render_Error2["res.render('login')<br>with incorrect credentials alert"]
Create_Payload["Create JWT Payload<br>user, name, rol, imagen"]
Sign_Token["jwt.sign(payload, secret,<br>{expiresIn: '1h'})"]
Set_Cookie["res.cookie('token', token,<br>{httpOnly: true, maxAge: 3600000})"]
Render_Success["res.render('login')<br>with success alert"]
POST_Auth --> Limiter_MW
Limiter_MW --> Auth_Handler
Auth_Handler --> Extract_Creds
Extract_Creds --> Creds_Check
Creds_Check --> Render_Error1
Creds_Check --> DB_Query
DB_Query --> User_Check
User_Check --> Render_Error2
User_Check --> Create_Payload
Create_Payload --> Sign_Token
Sign_Token --> Set_Cookie
Set_Cookie --> Render_Success
Sources: src/router.js L532-L601
Handler Details:
- Rate Limiting (line 532): Prevent brute force attacks
- Credential Extraction (lines 533-534): Get username and password from form
- Database Query (lines 537-540): Fetch user record by username
- Password Verification (line 543):
bcrypt.compare(pass, results[0].pass)validates password - JWT Creation (lines 559-567): Create payload and sign with
JWT_SECRET - Cookie Setup (lines 570-574): Store token in HTTP-only cookie with 1-hour expiration
- Response (lines 577-586): Render login page with success alert and auto-redirect
Sources: src/router.js L532-L601
Controller Delegation¶
Two POST routes delegate to the controllers.js module for product CRUD operations.
Controller Routes:
- POST
/save- Delegates tocrud.savefor product creation (line 603) - POST
/update- Delegates tocrud.updatefor product editing (line 604)
Sources: src/router.js L13
Dynamic Route Parameters¶
Several routes use Express route parameters (:param) to capture dynamic values from URLs.
Parameter Extraction Pattern¶
| Route | Parameter | Extraction | Usage |
|---|---|---|---|
/edit/:id |
:id |
req.params.id |
Product reference for editing |
/delete/:id |
:id |
req.params.id |
Product reference for deletion |
/set-lang/:lang |
:lang |
req.params.lang |
Language code (es/en) |
Example: Edit Product Route
// Lines 186-196
router.get("/edit/:id", (req, res) => {
const ref = req.params.id; // Capture parameter
db.query("SELECT * FROM productos WHERE ref = ?", [ref], (error, results) => {
if (error) {
throw error;
} else {
res.render("edit", { producto: results[0] });
}
});
});
Sources: src/router.js L186-L196
Query Parameters¶
API routes use query parameters for filtering and data retrieval.
Query Parameter Usage:
/api/mensajes?con=<username>- Query parameterconspecifies user for message retrieval (line 230)/set-lang/:lang?returnTo=<path>- Query parameterreturnTospecifies redirect destination (line 400)
Example: Messages Query
// Line 230
const usuario = req.query.con; // Extract query parameter
Sources: src/router.js L230
Database Integration¶
The router directly executes MySQL queries for most operations using the db connection object imported from database/db.js.
Database Query Pattern¶
flowchart TD
RouteHandler["Route Handler"]
DBQuery["db.query(sql, params, callback)"]
Callback["Callback Function"]
ErrorCheck["error<br>parameter?"]
ErrorHandler["throw error or<br>res.status(500)"]
ProcessResults["Process results"]
Response["Send Response<br>res.render() or res.json()"]
RouteHandler --> DBQuery
DBQuery --> Callback
Callback --> ErrorCheck
ErrorCheck --> ErrorHandler
ErrorCheck --> ProcessResults
ProcessResults --> Response
Sources: src/router.js L5
Query Examples by Route Type¶
View Rendering Queries:
// Lines 121-133 - Admin page
db.query("SELECT * FROM productos", (error, results) => {
if (error) {
throw error;
} else {
res.render("admin", {
productos: results,
user: req.user,
login: true,
rol: req.user.rol,
});
}
});
API Endpoint Queries:
// Lines 236-252 - Get messages for user
const sql = `
SELECT de_usuario, para_usuario, mensaje, fecha
FROM mensajes
WHERE
(de_usuario = ? OR para_usuario = ?)
ORDER BY fecha ASC
`;
db.query(sql, [usuario, usuario], (err, results) => {
if (err) {
console.error("❌ Error al consultar mensajes:", err);
return res.status(500).json({ error: "Error al obtener mensajes" });
}
res.json(results);
});
Sources: src/router.js L121-L133
Complex SQL Queries¶
The /api/usuarios-conversaciones endpoint uses a complex SQL query with UNION and subqueries to find all non-admin users who have conversations with admins.
// Lines 292-304
const sql = `
SELECT DISTINCT usuario
FROM (
SELECT de_usuario AS usuario FROM mensajes
WHERE para_usuario IN (SELECT usuario FROM usuarios WHERE rol = 'admin')
UNION
SELECT para_usuario AS usuario FROM mensajes
WHERE de_usuario IN (SELECT usuario FROM usuarios WHERE rol = 'admin')
) AS conversaciones
WHERE usuario NOT IN (SELECT usuario FROM usuarios WHERE rol = 'admin')
`;
Query Logic:
- First subquery: Users who sent messages TO admins
- Second subquery: Users who received messages FROM admins
- UNION: Combine both sets
- WHERE: Exclude admin users from results
- DISTINCT: Remove duplicates
Sources: src/router.js L292-L314
Language Switching System¶
The /set-lang/:lang route implements internationalization by storing language preferences in cookies and redirecting back to the originating page.
flowchart TD
Request["GET /set-lang/:lang?returnTo=/page"]
ExtractParams["Extract :lang and<br>?returnTo parameters"]
ValidateLang["lang in<br>['es', 'en']?"]
SetCookie["res.cookie('lang', lang,<br>{maxAge: 900000, httpOnly: true})"]
SkipCookie["Skip cookie setting"]
Redirect["res.redirect(returnTo || '/')"]
Request --> ExtractParams
ExtractParams --> ValidateLang
ValidateLang --> SetCookie
ValidateLang --> SkipCookie
SetCookie --> Redirect
SkipCookie --> Redirect
Sources: src/router.js L398-L407
Implementation:
// Lines 398-407
router.get('/set-lang/:lang', (req, res) => {
const lang = req.params.lang;
const returnTo = req.query.returnTo || '/';
if (['es', 'en'].includes(lang)) {
res.cookie('lang', lang, { maxAge: 900000, httpOnly: true });
}
res.redirect(returnTo);
});
Cookie Settings:
maxAge: 900000- 15 minutes (900,000 milliseconds)httpOnly: true- Not accessible via JavaScript for security
Sources: src/router.js L398-L407
Swagger/OpenAPI Documentation¶
Several routes include JSDoc-style Swagger annotations for API documentation. These annotations describe request/response schemas, authentication requirements, and response codes.
Documented Routes:
- GET
/- Home page (lines 40-58) - GET
/admin- Admin page (lines 83-118) - GET
/edit/:id- Edit product (lines 157-184) - POST
/auth- Authentication (lines 486-530)
Example Swagger Annotation:
// Lines 486-530
/**
* @swagger
* /auth:
* post:
* summary: Autentica al usuario y establece una cookie JWT
* description: Valida las credenciales del usuario. Si son correctas, genera un token JWT y lo guarda en una cookie HTTP (`token`). Luego renderiza la vista `/`.
* tags:
* - Autenticación
* requestBody:
* required: true
* content:
* application/x-www-form-urlencoded:
* schema:
* type: object
* required:
* - user
* - pass
* properties:
* user:
* type: string
* description: Nombre de usuario
* pass:
* type: string
* description: Contraseña del usuario
* responses:
* 200:
* description: Autenticación exitosa. Se establece una cookie JWT y se renderiza la vista `/`.
* headers:
* Set-Cookie:
* description: Cookie HTTP que contiene el JWT (token válido por 1 hora)
* schema:
* type: string
* example: token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...; Path=/; HttpOnly; Max-Age=3600
* content:
* text/html:
* schema:
* type: string
* example: "<html>...</html>"
* 400:
* description: Usuario o contraseña faltantes
* 401:
* description: Credenciales incorrectas
* 500:
* description: Error interno del servidor o de base de datos
*/
Sources: src/router.js L40-L58
Error Handling Patterns¶
The router implements multiple error handling patterns depending on the route type and error scenario.
Error Handling by Route Type¶
| Route Type | Error Pattern | Response |
|---|---|---|
| View Routes | throw error or conditional render |
500 error or error alert in view |
| API Routes | res.status(500).json({ error: "..." }) |
JSON error object with status code |
| PDF Routes | res.status(500).send("Error message") |
Plain text error with status code |
| Database Errors | throw error or console.error + status |
Varies by route type |
View Route Error Example:
// Lines 188-195 - Edit product
db.query("SELECT * FROM productos WHERE ref = ?", [ref], (error, results) => {
if (error) {
throw error; // Handled by Express error handler
} else {
res.render("edit", { producto: results[0] });
}
});
API Route Error Example:
// Lines 244-248 - Get messages API
db.query(sql, [usuario, usuario], (err, results) => {
if (err) {
console.error("❌ Error al consultar mensajes:", err);
return res.status(500).json({ error: "Error al obtener mensajes" });
}
res.json(results);
});
Sources: src/router.js L188-L195
Validation Error Handling¶
The registration route has special handling for validation errors, re-rendering the form with error messages and preserving user input.
// Lines 430-442
const errors = validationResult(req);
if (!errors.isEmpty()) {
const valores = req.body; // Preserve form values
const validacionErrores = errors.array(); // Extract errors
res.render("register", {
validaciones: validacionErrores, // Pass errors to template
valores: valores, // Pass values to template
});
}
Sources: src/router.js L430-L442
Module Export¶
The router is exported as a CommonJS module and imported by index.js where it is mounted at the root path.
// Line 607
module.exports = router;
Usage in index.js:
const router = require('./src/router');
app.use('/', router);
Sources: src/router.js L607