jerkjs 2.0.1 → 2.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -6
- package/docs/EXTENSION_MANUAL.md +955 -0
- package/docs/FIREWALL_MANUAL.md +416 -0
- package/docs/HOOKS_REFERENCE_IMPROVED.md +596 -0
- package/docs/MANUAL_API_SDK.md +536 -0
- package/docs/MARIADB_TOKENS_IMPLEMENTATION.md +110 -0
- package/docs/MIDDLEWARE_MANUAL.md +518 -0
- package/docs/OAUTH2_GOOGLE_MANUAL.md +405 -0
- package/docs/frontend-and-sessions.md +6 -6
- package/examples/advanced/controllers/productController.js +64 -0
- package/examples/advanced/controllers/userController.js +85 -0
- package/examples/advanced/routes.json +51 -0
- package/examples/advanced_example.js +93 -0
- package/examples/basic/controllers/userController.js +85 -0
- package/examples/basic_example.js +72 -0
- package/examples/mvc_example/app.js +138 -0
- package/examples/mvc_example/views/home/index.html +26 -0
- package/examples/mvc_example/views/home/simple.html +3 -0
- package/examples/mvc_example/views/layout.html +23 -0
- package/examples/mvc_example/views/test.html +3 -0
- package/examples/mvc_example/views/user/invalid.html +6 -0
- package/examples/mvc_example/views/user/list.html +36 -0
- package/examples/mvc_example/views/user/notfound.html +6 -0
- package/examples/mvc_example/views/user/profile.html +11 -0
- package/examples/mvc_routes_example/app.js +34 -0
- package/examples/mvc_routes_example/controllers/mainController.js +27 -0
- package/examples/mvc_routes_example/controllers/productController.js +47 -0
- package/examples/mvc_routes_example/controllers/userController.js +76 -0
- package/examples/mvc_routes_example/routes.json +30 -0
- package/examples/mvc_routes_example/views/layout.html +31 -0
- package/examples/mvc_routes_example/views/main/index.html +11 -0
- package/examples/mvc_routes_example/views/product/catalog.html +24 -0
- package/examples/mvc_routes_example/views/user/invalid.html +6 -0
- package/examples/mvc_routes_example/views/user/list.html +40 -0
- package/examples/mvc_routes_example/views/user/notfound.html +6 -0
- package/examples/mvc_routes_example/views/user/profile.html +18 -0
- package/examples/mvc_welcome/README.md +34 -0
- package/examples/mvc_welcome/app.js +50 -0
- package/examples/mvc_welcome/controllers/welcomeController.js +41 -0
- package/examples/mvc_welcome/package.json +26 -0
- package/examples/mvc_welcome/views/home/welcome.html +82 -0
- package/examples/v2/README.md +72 -0
- package/examples/v2/app.js +74 -0
- package/examples/v2/app_fixed.js +74 -0
- package/examples/v2/controllers/authController.js +64 -0
- package/examples/v2/controllers/mainController.js +24 -0
- package/examples/v2/controllers/protectedController.js +12 -0
- package/examples/v2/controllers/userController.js +16 -0
- package/examples/v2/package.json +27 -0
- package/examples/v2/routes.json +30 -0
- package/examples/v2/test_api.sh +47 -0
- package/examples/v2/tokens_example.sqlite +0 -0
- package/examples/v2.1_firewall_demo/README.md +113 -0
- package/examples/v2.1_firewall_demo/app.js +182 -0
- package/examples/v2.1_firewall_demo/package.json +27 -0
- package/examples/v2.1_hooks_demo/README.md +85 -0
- package/examples/v2.1_hooks_demo/app.js +101 -0
- package/examples/v2.1_hooks_demo/controllers/hooksController.js +29 -0
- package/examples/v2.1_hooks_demo/controllers/mainController.js +18 -0
- package/examples/v2.1_hooks_demo/package.json +27 -0
- package/examples/v2.1_hooks_demo/routes.json +16 -0
- package/examples/v2.1_openapi_demo/README.md +82 -0
- package/examples/v2.1_openapi_demo/app.js +296 -0
- package/examples/v2.1_openapi_demo/package.json +26 -0
- package/examples/v2_cors/README.md +82 -0
- package/examples/v2_cors/app.js +108 -0
- package/examples/v2_cors/package.json +23 -0
- package/examples/v2_json_auth/README.md +83 -0
- package/examples/v2_json_auth/app.js +72 -0
- package/examples/v2_json_auth/controllers/authController.js +67 -0
- package/examples/v2_json_auth/controllers/mainController.js +16 -0
- package/examples/v2_json_auth/controllers/protectedController.js +12 -0
- package/examples/v2_json_auth/controllers/tokenController.js +28 -0
- package/examples/v2_json_auth/controllers/userController.js +15 -0
- package/examples/v2_json_auth/package.json +26 -0
- package/examples/v2_json_auth/routes.json +37 -0
- package/examples/v2_json_auth/tokens.json +20 -0
- package/examples/v2_mariadb_auth/README.md +94 -0
- package/examples/v2_mariadb_auth/app.js +81 -0
- package/examples/v2_mariadb_auth/controllers/authController.js +95 -0
- package/examples/v2_mariadb_auth/controllers/mainController.js +31 -0
- package/examples/v2_mariadb_auth/controllers/protectedController.js +12 -0
- package/examples/v2_mariadb_auth/controllers/userController.js +17 -0
- package/examples/v2_mariadb_auth/package.json +27 -0
- package/examples/v2_mariadb_auth/routes.json +37 -0
- package/examples/v2_no_auth/README.md +75 -0
- package/examples/v2_no_auth/app.js +72 -0
- package/examples/v2_no_auth/controllers/healthController.js +14 -0
- package/examples/v2_no_auth/controllers/mainController.js +19 -0
- package/examples/v2_no_auth/controllers/productController.js +31 -0
- package/examples/v2_no_auth/controllers/publicController.js +16 -0
- package/examples/v2_no_auth/package.json +22 -0
- package/examples/v2_no_auth/routes.json +37 -0
- package/examples/v2_oauth/README.md +70 -0
- package/examples/v2_oauth/app.js +90 -0
- package/examples/v2_oauth/controllers/mainController.js +45 -0
- package/examples/v2_oauth/controllers/oauthController.js +247 -0
- package/examples/v2_oauth/controllers/protectedController.js +13 -0
- package/examples/v2_oauth/controllers/userController.js +17 -0
- package/examples/v2_oauth/package.json +26 -0
- package/examples/v2_oauth/routes.json +44 -0
- package/examples/v2_openapi/README.md +77 -0
- package/examples/v2_openapi/app.js +222 -0
- package/examples/v2_openapi/controllers/authController.js +52 -0
- package/examples/v2_openapi/controllers/mainController.js +26 -0
- package/examples/v2_openapi/controllers/productController.js +17 -0
- package/examples/v2_openapi/controllers/userController.js +27 -0
- package/examples/v2_openapi/package.json +26 -0
- package/examples/v2_openapi/routes.json +37 -0
- package/index.js +11 -3
- package/lib/core/handler.js +1 -1
- package/lib/core/hooks.js +1 -1
- package/lib/core/router.js +1 -1
- package/lib/core/server.js +1 -1
- package/lib/loader/controllerLoader.js +1 -1
- package/lib/loader/routeLoader.js +1 -1
- package/lib/middleware/auditLogger.js +1 -1
- package/lib/middleware/authenticator.js +1 -1
- package/lib/middleware/compressor.js +1 -1
- package/lib/middleware/cors.js +1 -1
- package/lib/middleware/firewall.js +1 -1
- package/lib/middleware/rateLimiter.js +1 -1
- package/lib/middleware/session.js +1 -1
- package/lib/middleware/validator.js +1 -1
- package/lib/mvc/controllerBase.js +207 -0
- package/lib/mvc/viewEngine.js +752 -0
- package/lib/utils/configParser.js +1 -1
- package/lib/utils/logger.js +1 -1
- package/lib/utils/openapiGenerator.js +1 -1
- package/lib/utils/tokenManager.js +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Ejemplo real de uso del framework JERK
|
|
3
|
+
* Este script demuestra cómo cargar rutas desde un archivo JSON
|
|
4
|
+
* y usar los controladores definidos en el archivo de rutas
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
const path = require('path');
|
|
8
|
+
const { JERK, RouteLoader, Authenticator, Logger } = require('../index');
|
|
9
|
+
|
|
10
|
+
// Crear instancia del logger
|
|
11
|
+
const logger = new Logger({ level: 'info', timestamp: true });
|
|
12
|
+
|
|
13
|
+
logger.info('Iniciando ejemplo real de carga de rutas desde JSON');
|
|
14
|
+
|
|
15
|
+
// Crear instancia del servidor
|
|
16
|
+
const server = new JERK({
|
|
17
|
+
port: 6000,
|
|
18
|
+
host: 'localhost'
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
// Crear instancia del autenticador
|
|
22
|
+
const authenticator = new Authenticator();
|
|
23
|
+
|
|
24
|
+
// Registrar estrategias de autenticación que se usan en routes.json
|
|
25
|
+
authenticator.use('apiKey', authenticator.apiKeyStrategy('X-API-Key', ['secret-key-123']));
|
|
26
|
+
authenticator.use('jwt', authenticator.jwtStrategy('secret-jwt-key'));
|
|
27
|
+
|
|
28
|
+
// Cargar rutas desde el archivo JSON
|
|
29
|
+
const routeLoader = new RouteLoader();
|
|
30
|
+
|
|
31
|
+
// Middleware de logging
|
|
32
|
+
server.use((req, res, next) => {
|
|
33
|
+
logger.info(`${req.method} ${req.url} - IP: ${req.connection.remoteAddress}`);
|
|
34
|
+
next();
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
logger.info('Cargando rutas desde advanced/routes.json...');
|
|
38
|
+
|
|
39
|
+
// Cargar las rutas desde el archivo JSON
|
|
40
|
+
// Cambiamos temporalmente el directorio de trabajo para que las rutas relativas funcionen correctamente
|
|
41
|
+
const originalCwd = process.cwd();
|
|
42
|
+
process.chdir(__dirname); // Cambiar al directorio actual (examples)
|
|
43
|
+
|
|
44
|
+
routeLoader.loadRoutes(server, './advanced/routes.json')
|
|
45
|
+
.then(routes => {
|
|
46
|
+
process.chdir(originalCwd); // Restaurar directorio original
|
|
47
|
+
|
|
48
|
+
logger.info(`Cargadas ${routes.length} rutas desde el archivo JSON:`);
|
|
49
|
+
routes.forEach((route, index) => {
|
|
50
|
+
logger.info(` ${index + 1}. ${route.method} ${route.path} -> ${route.controller}#${route.handler}`);
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
logger.info('\nIniciando servidor en http://localhost:6000');
|
|
54
|
+
|
|
55
|
+
// Iniciar el servidor
|
|
56
|
+
const httpServer = server.start();
|
|
57
|
+
|
|
58
|
+
logger.info('\nENDPOINTS DISPONIBLES (cargados desde routes.json):');
|
|
59
|
+
logger.info('GET /api/users - Obtener todos los usuarios (JWT req)');
|
|
60
|
+
logger.info('GET /api/users/:id - Obtener usuario por ID (JWT req)');
|
|
61
|
+
logger.info('POST /api/users - Crear usuario (API Key req)');
|
|
62
|
+
logger.info('GET /api/products - Obtener productos (sin auth)');
|
|
63
|
+
logger.info('PUT /api/products/:id - Actualizar producto (API Key req)');
|
|
64
|
+
|
|
65
|
+
logger.info('\nEJEMPLOS DE USO:');
|
|
66
|
+
logger.info('# Obtener productos (sin autenticación):');
|
|
67
|
+
logger.info('curl -X GET http://localhost:6000/api/products');
|
|
68
|
+
|
|
69
|
+
logger.info('\nEl servidor se detendrá automáticamente en 120 segundos...');
|
|
70
|
+
|
|
71
|
+
// Programar apagado automático para la demostración
|
|
72
|
+
setTimeout(() => {
|
|
73
|
+
logger.info('Finalizando ejemplo...');
|
|
74
|
+
httpServer.close(() => {
|
|
75
|
+
logger.info('Servidor detenido. Ejemplo completado.');
|
|
76
|
+
console.log('\nEjemplo real completado exitosamente!');
|
|
77
|
+
console.log('El framework JERK ha demostrado su capacidad para:');
|
|
78
|
+
console.log(' - Cargar rutas dinámicamente desde archivos JSON');
|
|
79
|
+
console.log(' - Usar controladores definidos externamente');
|
|
80
|
+
console.log(' - Aplicar diferentes tipos de autenticación');
|
|
81
|
+
process.exit(0);
|
|
82
|
+
});
|
|
83
|
+
}, 120000);
|
|
84
|
+
|
|
85
|
+
})
|
|
86
|
+
.catch(error => {
|
|
87
|
+
process.chdir(originalCwd); // Asegurarse de restaurar el directorio en caso de error
|
|
88
|
+
logger.error('Error cargando rutas:', error.message);
|
|
89
|
+
process.exit(1);
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
// Mantener el proceso activo
|
|
93
|
+
process.stdin.resume();
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Controlador de ejemplo para usuarios
|
|
3
|
+
* Archivo: examples/basic/controllers/userController.js
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
// Simulación de base de datos
|
|
7
|
+
let users = [
|
|
8
|
+
{ id: 1, name: 'John Doe', email: 'john@example.com' },
|
|
9
|
+
{ id: 2, name: 'Jane Smith', email: 'jane@example.com' }
|
|
10
|
+
];
|
|
11
|
+
|
|
12
|
+
// Obtener todos los usuarios
|
|
13
|
+
function getUsers(req, res) {
|
|
14
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
15
|
+
res.end(JSON.stringify({
|
|
16
|
+
success: true,
|
|
17
|
+
data: users
|
|
18
|
+
}));
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
// Obtener un usuario por ID
|
|
22
|
+
function getUserById(req, res) {
|
|
23
|
+
const userId = parseInt(req.params.id);
|
|
24
|
+
const user = users.find(u => u.id === userId);
|
|
25
|
+
|
|
26
|
+
if (!user) {
|
|
27
|
+
res.writeHead(404, { 'Content-Type': 'application/json' });
|
|
28
|
+
res.end(JSON.stringify({
|
|
29
|
+
success: false,
|
|
30
|
+
message: 'Usuario no encontrado'
|
|
31
|
+
}));
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
36
|
+
res.end(JSON.stringify({
|
|
37
|
+
success: true,
|
|
38
|
+
data: user
|
|
39
|
+
}));
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// Crear un nuevo usuario
|
|
43
|
+
function createUser(req, res) {
|
|
44
|
+
try {
|
|
45
|
+
const { name, email } = req.body;
|
|
46
|
+
|
|
47
|
+
// Validar datos
|
|
48
|
+
if (!name || !email) {
|
|
49
|
+
res.writeHead(400, { 'Content-Type': 'application/json' });
|
|
50
|
+
res.end(JSON.stringify({
|
|
51
|
+
success: false,
|
|
52
|
+
message: 'Nombre y correo electrónico son requeridos'
|
|
53
|
+
}));
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// Crear nuevo usuario
|
|
58
|
+
const newUser = {
|
|
59
|
+
id: users.length + 1,
|
|
60
|
+
name,
|
|
61
|
+
email
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
users.push(newUser);
|
|
65
|
+
|
|
66
|
+
res.writeHead(201, { 'Content-Type': 'application/json' });
|
|
67
|
+
res.end(JSON.stringify({
|
|
68
|
+
success: true,
|
|
69
|
+
data: newUser
|
|
70
|
+
}));
|
|
71
|
+
} catch (error) {
|
|
72
|
+
res.writeHead(500, { 'Content-Type': 'application/json' });
|
|
73
|
+
res.end(JSON.stringify({
|
|
74
|
+
success: false,
|
|
75
|
+
message: 'Error al crear usuario'
|
|
76
|
+
}));
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// Exportar handlers
|
|
81
|
+
module.exports = {
|
|
82
|
+
getUsers,
|
|
83
|
+
getUserById,
|
|
84
|
+
createUser
|
|
85
|
+
};
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Ejemplo basico de uso del framework JERK
|
|
3
|
+
* Este script demuestra cómo usar directamente los controladores
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
const { JERK, Logger } = require('../index');
|
|
7
|
+
const userController = require('./basic/controllers/userController');
|
|
8
|
+
|
|
9
|
+
// Crear instancia del logger
|
|
10
|
+
const logger = new Logger({ level: 'info', timestamp: true });
|
|
11
|
+
|
|
12
|
+
logger.info('Iniciando ejemplo basico con controladores');
|
|
13
|
+
|
|
14
|
+
// Crear instancia del servidor
|
|
15
|
+
const server = new JERK({
|
|
16
|
+
port: 6001,
|
|
17
|
+
host: 'localhost'
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
// Middleware de logging
|
|
21
|
+
server.use((req, res, next) => {
|
|
22
|
+
logger.info(`${req.method} ${req.url}`);
|
|
23
|
+
next();
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
// Usar los handlers directamente desde el controlador
|
|
27
|
+
server.addRoute('GET', '/api/users', userController.getUsers);
|
|
28
|
+
server.addRoute('GET', '/api/users/:id', userController.getUserById);
|
|
29
|
+
server.addRoute('POST', '/api/users', userController.createUser);
|
|
30
|
+
|
|
31
|
+
logger.info('Agregando rutas usando handlers del controlador userController');
|
|
32
|
+
|
|
33
|
+
logger.info('\nIniciando servidor en http://localhost:6001');
|
|
34
|
+
|
|
35
|
+
// Iniciar el servidor
|
|
36
|
+
const httpServer = server.start();
|
|
37
|
+
|
|
38
|
+
logger.info('\nENDPOINTS DISPONIBLES:');
|
|
39
|
+
logger.info('GET /api/users - Obtener todos los usuarios');
|
|
40
|
+
logger.info('GET /api/users/:id - Obtener usuario por ID');
|
|
41
|
+
logger.info('POST /api/users - Crear nuevo usuario');
|
|
42
|
+
|
|
43
|
+
logger.info('\nEJEMPLOS DE USO:');
|
|
44
|
+
logger.info('# Obtener todos los usuarios:');
|
|
45
|
+
logger.info('curl -X GET http://localhost:6001/api/users');
|
|
46
|
+
logger.info('');
|
|
47
|
+
logger.info('# Obtener usuario por ID:');
|
|
48
|
+
logger.info('curl -X GET http://localhost:6001/api/users/1');
|
|
49
|
+
logger.info('');
|
|
50
|
+
logger.info('# Crear nuevo usuario:');
|
|
51
|
+
logger.info('curl -X POST -H "Content-Type: application/json" \\');
|
|
52
|
+
logger.info(' -d \'{"name":"Juan Perez", "email":"juan@example.com"}\' \\');
|
|
53
|
+
logger.info(' http://localhost:6001/api/users');
|
|
54
|
+
|
|
55
|
+
logger.info('\nEl servidor se detendrá automáticamente en 60 segundos...');
|
|
56
|
+
|
|
57
|
+
// Programar apagado automático para la demostración
|
|
58
|
+
setTimeout(() => {
|
|
59
|
+
logger.info('Finalizando ejemplo basico...');
|
|
60
|
+
httpServer.close(() => {
|
|
61
|
+
logger.info('Servidor detenido. Ejemplo basico completado.');
|
|
62
|
+
console.log('\nEjemplo basico completado exitosamente!');
|
|
63
|
+
console.log('El framework JERK ha demostrado su capacidad para:');
|
|
64
|
+
console.log(' - Usar controladores directamente');
|
|
65
|
+
console.log(' - Manejar rutas parametrizadas');
|
|
66
|
+
console.log(' - Procesar solicitudes POST con cuerpo JSON');
|
|
67
|
+
process.exit(0);
|
|
68
|
+
});
|
|
69
|
+
}, 60000);
|
|
70
|
+
|
|
71
|
+
// Mantener el proceso activo
|
|
72
|
+
process.stdin.resume();
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Ejemplo de uso del sistema MVC para el framework JERK
|
|
3
|
+
* Demostración de vistas y controladores MVC
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
const { APIServer, Router, ControllerBase } = require('../../index');
|
|
7
|
+
|
|
8
|
+
// Crear un controlador personalizado que extienda ControllerBase
|
|
9
|
+
class HomeController extends ControllerBase {
|
|
10
|
+
constructor(options = {}) {
|
|
11
|
+
super(options);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
// Acción para mostrar la página de inicio
|
|
15
|
+
index(req, res) {
|
|
16
|
+
// Establecer variables para la vista
|
|
17
|
+
this.set('title', 'Página de Inicio');
|
|
18
|
+
this.set('message', '¡Bienvenido al framework JERK!');
|
|
19
|
+
this.set('users', [
|
|
20
|
+
{ name: 'Juan', email: 'juan@example.com' },
|
|
21
|
+
{ name: 'María', email: 'maria@example.com' },
|
|
22
|
+
{ name: 'Pedro', email: 'pedro@example.com' }
|
|
23
|
+
]);
|
|
24
|
+
|
|
25
|
+
// Renderizar la vista
|
|
26
|
+
this.render(res, 'home/index', {
|
|
27
|
+
currentTime: new Date().toISOString()
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// Acción para mostrar el perfil de un usuario
|
|
32
|
+
profile(req, res) {
|
|
33
|
+
// Obtener el ID del usuario de los parámetros
|
|
34
|
+
const userIdParam = this.input('id', '1');
|
|
35
|
+
|
|
36
|
+
// Validar que el ID sea un número entero positivo (no solo que empiece con un número)
|
|
37
|
+
if (!/^\d+$/.test(userIdParam) || parseInt(userIdParam) <= 0) {
|
|
38
|
+
// Si no es un ID válido, mostrar error
|
|
39
|
+
this.set('title', 'ID de usuario inválido');
|
|
40
|
+
this.render(res, 'user/invalid', {
|
|
41
|
+
userId: userIdParam
|
|
42
|
+
});
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const userId = parseInt(userIdParam);
|
|
47
|
+
|
|
48
|
+
// Array real de usuarios
|
|
49
|
+
const users = [
|
|
50
|
+
{ id: 1, name: 'Ana García', email: 'ana@example.com', registered: '2026-01-01T10:00:00Z', active: true },
|
|
51
|
+
{ id: 2, name: 'Carlos López', email: 'carlos@example.com', registered: '2026-01-02T11:30:00Z', active: false },
|
|
52
|
+
{ id: 3, name: 'Laura Martínez', email: 'laura@example.com', registered: '2026-01-03T14:20:00Z', active: true },
|
|
53
|
+
{ id: 4, name: 'Pedro Rodríguez', email: 'pedro@example.com', registered: '2026-01-04T09:15:00Z', active: true },
|
|
54
|
+
{ id: 5, name: 'María Sánchez', email: 'maria@example.com', registered: '2026-01-05T16:45:00Z', active: false }
|
|
55
|
+
];
|
|
56
|
+
|
|
57
|
+
// Buscar el usuario por ID
|
|
58
|
+
const user = users.find(u => u.id === userId);
|
|
59
|
+
|
|
60
|
+
if (!user) {
|
|
61
|
+
// Si no se encuentra el usuario, mostrar error
|
|
62
|
+
this.set('title', 'Usuario no encontrado');
|
|
63
|
+
this.render(res, 'user/notfound', {
|
|
64
|
+
userId: userId
|
|
65
|
+
});
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// Establecer variables para la vista
|
|
70
|
+
this.set('title', `Perfil de ${user.name}`);
|
|
71
|
+
this.set('user', user);
|
|
72
|
+
|
|
73
|
+
// Renderizar la vista de perfil
|
|
74
|
+
this.render(res, 'user/profile');
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// Acción para mostrar la lista de usuarios
|
|
78
|
+
users(req, res) {
|
|
79
|
+
// Array real de usuarios (el mismo que en profile para consistencia)
|
|
80
|
+
const users = [
|
|
81
|
+
{ id: 1, name: 'Ana García', email: 'ana@example.com', registered: '2026-01-01T10:00:00Z', active: true },
|
|
82
|
+
{ id: 2, name: 'Carlos López', email: 'carlos@example.com', registered: '2026-01-02T11:30:00Z', active: false },
|
|
83
|
+
{ id: 3, name: 'Laura Martínez', email: 'laura@example.com', registered: '2026-01-03T14:20:00Z', active: true },
|
|
84
|
+
{ id: 4, name: 'Pedro Rodríguez', email: 'pedro@example.com', registered: '2026-01-04T09:15:00Z', active: true },
|
|
85
|
+
{ id: 5, name: 'María Sánchez', email: 'maria@example.com', registered: '2026-01-05T16:45:00Z', active: false }
|
|
86
|
+
];
|
|
87
|
+
|
|
88
|
+
// Establecer variables para la vista
|
|
89
|
+
this.set('title', 'Lista de Usuarios');
|
|
90
|
+
this.set('users', users);
|
|
91
|
+
|
|
92
|
+
// Renderizar la vista de usuarios
|
|
93
|
+
this.render(res, 'user/list');
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// Crear instancia del servidor
|
|
98
|
+
const server = new APIServer({
|
|
99
|
+
port: 9000,
|
|
100
|
+
host: 'localhost'
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
// Crear instancia del router
|
|
104
|
+
const router = new Router();
|
|
105
|
+
|
|
106
|
+
// Crear instancia del controlador
|
|
107
|
+
const homeController = new HomeController({ viewsPath: './examples/mvc_example/views' });
|
|
108
|
+
|
|
109
|
+
// Definir rutas
|
|
110
|
+
router
|
|
111
|
+
.get('/', (req, res) => {
|
|
112
|
+
// Establecer la solicitud y respuesta en el controlador
|
|
113
|
+
homeController.setRequestResponse(req, res);
|
|
114
|
+
homeController.index(req, res);
|
|
115
|
+
})
|
|
116
|
+
.get('/profile', (req, res) => {
|
|
117
|
+
homeController.setRequestResponse(req, res);
|
|
118
|
+
homeController.profile(req, res);
|
|
119
|
+
})
|
|
120
|
+
.get('/users', (req, res) => {
|
|
121
|
+
homeController.setRequestResponse(req, res);
|
|
122
|
+
homeController.users(req, res);
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
// Agregar las rutas del router al servidor
|
|
126
|
+
const routes = router.getRoutes();
|
|
127
|
+
for (const route of routes) {
|
|
128
|
+
server.addRoute(route.method, route.path, route.handler);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// Iniciar el servidor
|
|
132
|
+
server.start(() => {
|
|
133
|
+
console.log('Servidor MVC iniciado en http://localhost:9000');
|
|
134
|
+
console.log('Rutas disponibles:');
|
|
135
|
+
console.log('- http://localhost:9000/ (Página de inicio)');
|
|
136
|
+
console.log('- http://localhost:9000/profile?id=1 (Perfil de usuario)');
|
|
137
|
+
console.log('- http://localhost:9000/users (Lista de usuarios)');
|
|
138
|
+
});
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
<h1>{{title}}</h1>
|
|
2
|
+
<p>{{message}}</p>
|
|
3
|
+
|
|
4
|
+
<h2>Usuarios Registrados</h2>
|
|
5
|
+
{{if users}}
|
|
6
|
+
<table>
|
|
7
|
+
<thead>
|
|
8
|
+
<tr>
|
|
9
|
+
<th>Nombre</th>
|
|
10
|
+
<th>Email</th>
|
|
11
|
+
</tr>
|
|
12
|
+
</thead>
|
|
13
|
+
<tbody>
|
|
14
|
+
{{foreach:users}}
|
|
15
|
+
<tr>
|
|
16
|
+
<td>{{item.name}}</td>
|
|
17
|
+
<td>{{item.email}}</td>
|
|
18
|
+
</tr>
|
|
19
|
+
{{endforeach}}
|
|
20
|
+
</tbody>
|
|
21
|
+
</table>
|
|
22
|
+
{{else}}
|
|
23
|
+
<p>No hay usuarios registrados.</p>
|
|
24
|
+
{{endif}}
|
|
25
|
+
|
|
26
|
+
<p>Hora actual: {{currentTime}}</p>
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="es">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
+
<title>{{title}}</title>
|
|
7
|
+
<style>
|
|
8
|
+
body { font-family: Arial, sans-serif; margin: 40px; background-color: #f5f5f5; }
|
|
9
|
+
.container { max-width: 800px; margin: 0 auto; background: white; padding: 20px; border-radius: 8px; box-shadow: 0 2px 10px rgba(0,0,0,0.1); }
|
|
10
|
+
h1 { color: #333; }
|
|
11
|
+
table { width: 100%; border-collapse: collapse; margin-top: 20px; }
|
|
12
|
+
th, td { padding: 10px; text-align: left; border-bottom: 1px solid #ddd; }
|
|
13
|
+
th { background-color: #f2f2f2; }
|
|
14
|
+
.active { color: green; }
|
|
15
|
+
.inactive { color: red; }
|
|
16
|
+
</style>
|
|
17
|
+
</head>
|
|
18
|
+
<body>
|
|
19
|
+
<div class="container">
|
|
20
|
+
{{content}}
|
|
21
|
+
</div>
|
|
22
|
+
</body>
|
|
23
|
+
</html>
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
<h1>{{title}}</h1>
|
|
2
|
+
|
|
3
|
+
{{if users}}
|
|
4
|
+
<table>
|
|
5
|
+
<thead>
|
|
6
|
+
<tr>
|
|
7
|
+
<th>ID</th>
|
|
8
|
+
<th>Nombre</th>
|
|
9
|
+
<th>Email</th>
|
|
10
|
+
<th>Estado</th>
|
|
11
|
+
<th>Acciones</th>
|
|
12
|
+
</tr>
|
|
13
|
+
</thead>
|
|
14
|
+
<tbody>
|
|
15
|
+
{{foreach:users}}
|
|
16
|
+
<tr>
|
|
17
|
+
<td>{{item.id}}</td>
|
|
18
|
+
<td>{{item.name}}</td>
|
|
19
|
+
<td>{{item.email}}</td>
|
|
20
|
+
<td>
|
|
21
|
+
{{if item.active}}
|
|
22
|
+
<span class="active">Activo</span>
|
|
23
|
+
{{else}}
|
|
24
|
+
<span class="inactive">Inactivo</span>
|
|
25
|
+
{{endif}}
|
|
26
|
+
</td>
|
|
27
|
+
<td><a href="/profile?id={{item.id}}">Ver Perfil</a></td>
|
|
28
|
+
</tr>
|
|
29
|
+
{{endforeach}}
|
|
30
|
+
</tbody>
|
|
31
|
+
</table>
|
|
32
|
+
{{else}}
|
|
33
|
+
<p>No hay usuarios registrados.</p>
|
|
34
|
+
{{endif}}
|
|
35
|
+
|
|
36
|
+
<a href="/">Volver a la página de inicio</a>
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
<h1>{{title}}</h1>
|
|
2
|
+
|
|
3
|
+
<div>
|
|
4
|
+
<h2>Información del Usuario</h2>
|
|
5
|
+
<p><strong>ID:</strong> {{user.id}}</p>
|
|
6
|
+
<p><strong>Nombre:</strong> {{user.name}}</p>
|
|
7
|
+
<p><strong>Email:</strong> {{user.email}}</p>
|
|
8
|
+
<p><strong>Registrado:</strong> {{user.registered}}</p>
|
|
9
|
+
</div>
|
|
10
|
+
|
|
11
|
+
<a href="/users">Volver a la lista de usuarios</a>
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Ejemplo de uso del sistema MVC con definición de rutas desde archivo JSON
|
|
3
|
+
* Demostración de vistas, helpers y filtros
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
const { APIServer, RouteLoader, ControllerLoader, ViewEngine } = require('../../index');
|
|
7
|
+
|
|
8
|
+
// Crear instancia del servidor
|
|
9
|
+
const server = new APIServer({
|
|
10
|
+
port: 9001,
|
|
11
|
+
host: 'localhost'
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
// Crear instancia del cargador de rutas
|
|
15
|
+
const routeLoader = new RouteLoader();
|
|
16
|
+
|
|
17
|
+
// Cargar las rutas desde el archivo JSON
|
|
18
|
+
routeLoader.loadRoutes(server, './examples/mvc_routes_example/routes.json')
|
|
19
|
+
.then(routes => {
|
|
20
|
+
console.log(`${routes.length} rutas cargadas exitosamente`);
|
|
21
|
+
console.log('Rutas disponibles:');
|
|
22
|
+
console.log('- http://localhost:9001/ (Página de inicio)');
|
|
23
|
+
console.log('- http://localhost:9001/users (Lista de usuarios)');
|
|
24
|
+
console.log('- http://localhost:9001/profile?id=1 (Perfil de usuario)');
|
|
25
|
+
console.log('- http://localhost:9001/products (Catálogo de productos)');
|
|
26
|
+
|
|
27
|
+
// Iniciar el servidor
|
|
28
|
+
server.start(() => {
|
|
29
|
+
console.log('Servidor MVC con rutas JSON iniciado en http://localhost:9001');
|
|
30
|
+
});
|
|
31
|
+
})
|
|
32
|
+
.catch(error => {
|
|
33
|
+
console.error('Error al cargar las rutas:', error);
|
|
34
|
+
});
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
const { ControllerBase } = require('../../../index');
|
|
2
|
+
|
|
3
|
+
class MainController extends ControllerBase {
|
|
4
|
+
constructor(options = {}) {
|
|
5
|
+
super(options);
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
index(req, res) {
|
|
9
|
+
this.set('title', 'Inicio - Ejemplo MVC con Routes');
|
|
10
|
+
this.set('message', '¡Bienvenido al ejemplo de MVC con definición de rutas!');
|
|
11
|
+
|
|
12
|
+
this.render(res, 'main/index', {
|
|
13
|
+
currentTime: new Date().toISOString(),
|
|
14
|
+
version: '2.3.1'
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
// Exportar métodos directamente para que el RouteLoader pueda acceder a ellos
|
|
20
|
+
const controllerInstance = new MainController({ viewsPath: './examples/mvc_routes_example/views' });
|
|
21
|
+
|
|
22
|
+
module.exports = {
|
|
23
|
+
index: (req, res) => {
|
|
24
|
+
controllerInstance.setRequestResponse(req, res);
|
|
25
|
+
controllerInstance.index(req, res);
|
|
26
|
+
}
|
|
27
|
+
};
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
const { ControllerBase } = require('../../../index');
|
|
2
|
+
|
|
3
|
+
class ProductController extends ControllerBase {
|
|
4
|
+
constructor(options = {}) {
|
|
5
|
+
super(options);
|
|
6
|
+
|
|
7
|
+
// Registrar helpers personalizados para este controlador
|
|
8
|
+
this.getViewEngine().addHelper('calculateDiscount', (price, discountPercent) => {
|
|
9
|
+
return price - (price * discountPercent / 100);
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
this.getViewEngine().addHelper('formatCurrency', (value, symbol = '$') => {
|
|
13
|
+
return `${symbol}${Number(value).toFixed(2)}`;
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
this.getViewEngine().addHelper('isOnSale', (product) => {
|
|
17
|
+
return product.discount > 0;
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
catalog(req, res) {
|
|
22
|
+
const products = [
|
|
23
|
+
{ id: 1, name: 'Laptop Pro', price: 1200, discount: 10, category: 'Electronics' },
|
|
24
|
+
{ id: 2, name: 'Mouse Inalámbrico', price: 25, discount: 15, category: 'Accessories' },
|
|
25
|
+
{ id: 3, name: 'Teclado Mecánico', price: 80, discount: 0, category: 'Accessories' },
|
|
26
|
+
{ id: 4, name: 'Monitor 4K', price: 400, discount: 20, category: 'Electronics' },
|
|
27
|
+
{ id: 5, name: 'Auriculares', price: 150, discount: 5, category: 'Audio' }
|
|
28
|
+
];
|
|
29
|
+
|
|
30
|
+
this.set('title', 'Catálogo de Productos');
|
|
31
|
+
this.set('products', products);
|
|
32
|
+
|
|
33
|
+
this.render(res, 'product/catalog', {
|
|
34
|
+
currencySymbol: 'USD'
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// Exportar métodos directamente para que el RouteLoader pueda acceder a ellos
|
|
40
|
+
const controllerInstance = new ProductController({ viewsPath: './examples/mvc_routes_example/views' });
|
|
41
|
+
|
|
42
|
+
module.exports = {
|
|
43
|
+
catalog: (req, res) => {
|
|
44
|
+
controllerInstance.setRequestResponse(req, res);
|
|
45
|
+
controllerInstance.catalog(req, res);
|
|
46
|
+
}
|
|
47
|
+
};
|