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,85 @@
|
|
|
1
|
+
# Ejemplo de Sistema de Hooks en Framework JERK
|
|
2
|
+
|
|
3
|
+
Este ejemplo demuestra cómo usar el sistema de hooks como el core de WordPress para extender la funcionalidad del Framework JERK en diferentes puntos del ciclo de vida.
|
|
4
|
+
|
|
5
|
+
## Características del Sistema de Hooks
|
|
6
|
+
|
|
7
|
+
- **Acciones (Actions)**: Puntos de extensión donde se pueden ejecutar funciones
|
|
8
|
+
- **Filtros (Filters)**: Puntos donde se pueden modificar datos antes de ser procesados
|
|
9
|
+
- **Extensibilidad**: Capacidad para agregar funcionalidades en múltiples puntos del ciclo de vida
|
|
10
|
+
- **Ciclo de Vida**: Hooks disponibles en diferentes etapas del proceso
|
|
11
|
+
|
|
12
|
+
## Hooks Disponibles
|
|
13
|
+
|
|
14
|
+
### Hooks de Servidor
|
|
15
|
+
- `framework_init`: Se ejecuta cuando se inicializa el framework
|
|
16
|
+
- `pre_server_start`: Antes de iniciar el servidor
|
|
17
|
+
- `post_server_start`: Después de iniciar el servidor
|
|
18
|
+
|
|
19
|
+
### Hooks de Carga de Rutas
|
|
20
|
+
- `pre_route_load`: Antes de cargar rutas desde archivo
|
|
21
|
+
- `post_route_load`: Después de cargar rutas desde archivo
|
|
22
|
+
|
|
23
|
+
### Hooks de Carga de Controladores
|
|
24
|
+
- `pre_controller_load`: Antes de cargar un controlador
|
|
25
|
+
- `post_controller_load`: Después de cargar un controlador
|
|
26
|
+
|
|
27
|
+
## Configuración
|
|
28
|
+
|
|
29
|
+
No se requieren dependencias adicionales más allá del Framework JERK.
|
|
30
|
+
|
|
31
|
+
## Uso
|
|
32
|
+
|
|
33
|
+
1. Inicia el servidor:
|
|
34
|
+
```bash
|
|
35
|
+
node app.js
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
2. El servidor escuchará en `http://localhost:8096`
|
|
39
|
+
|
|
40
|
+
## Endpoints
|
|
41
|
+
|
|
42
|
+
- `GET /` - Página de inicio con información del sistema de hooks
|
|
43
|
+
- `GET /hooks-info` - Información sobre el sistema de hooks
|
|
44
|
+
|
|
45
|
+
## Ejemplo de uso de Hooks
|
|
46
|
+
|
|
47
|
+
```javascript
|
|
48
|
+
const { hooks } = require('jerkjs');
|
|
49
|
+
|
|
50
|
+
// Registrar una acción
|
|
51
|
+
hooks.addAction('nombre_del_hook', (param1, param2) => {
|
|
52
|
+
console.log('Hook ejecutado con:', param1, param2);
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
// Registrar un filtro
|
|
56
|
+
hooks.addFilter('nombre_del_filtro', (valor, parametroAdicional) => {
|
|
57
|
+
return valor + parametroAdicional;
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
// Ejecutar una acción
|
|
61
|
+
hooks.doAction('nombre_del_hook', 'dato1', 'dato2');
|
|
62
|
+
|
|
63
|
+
// Aplicar un filtro
|
|
64
|
+
const resultado = hooks.applyFilters('nombre_del_filtro', 'valorInicial', 'datoAdicional');
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
## Estructura del proyecto
|
|
68
|
+
|
|
69
|
+
```
|
|
70
|
+
examples/v2.1_hooks_demo/
|
|
71
|
+
├── app.js # Punto de entrada de la aplicación con hooks
|
|
72
|
+
├── routes.json # Definición de rutas
|
|
73
|
+
├── controllers/ # Controladores de las rutas
|
|
74
|
+
│ ├── mainController.js
|
|
75
|
+
│ └── hooksController.js
|
|
76
|
+
└── README.md
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
## Beneficios del Sistema de Hooks
|
|
80
|
+
|
|
81
|
+
1. **Extensibilidad**: Permite extender la funcionalidad sin modificar el código base
|
|
82
|
+
2. **Modularidad**: Módulos pueden añadir funcionalidades sin interferir entre sí
|
|
83
|
+
3. **Flexibilidad**: Hooks disponibles en múltiples puntos del ciclo de vida
|
|
84
|
+
4. **Personalización**: Capacidad para modificar comportamientos predeterminados
|
|
85
|
+
5. **Integración**: Fácil integración con sistemas de terceros
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Ejemplo de uso del sistema de hooks en el Framework JERK
|
|
3
|
+
* Demostrando extensibilidad en diferentes puntos del ciclo de vida
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
const jerk = require('../../index.js');
|
|
7
|
+
const {
|
|
8
|
+
APIServer,
|
|
9
|
+
Logger
|
|
10
|
+
} = jerk;
|
|
11
|
+
const RouteLoader = require('../../lib/loader/routeLoader.js');
|
|
12
|
+
const ControllerLoader = require('../../lib/loader/controllerLoader.js');
|
|
13
|
+
const hooks = jerk.hooks;
|
|
14
|
+
|
|
15
|
+
async function startServer() {
|
|
16
|
+
// Crear instancia del servidor
|
|
17
|
+
const server = new APIServer({
|
|
18
|
+
port: 8096,
|
|
19
|
+
host: 'localhost'
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
// Crear instancia del logger
|
|
23
|
+
const logger = new Logger({ level: 'info' });
|
|
24
|
+
|
|
25
|
+
try {
|
|
26
|
+
// Registrar hooks para diferentes eventos del ciclo de vida
|
|
27
|
+
|
|
28
|
+
// Hook que se ejecuta cuando se inicializa el framework
|
|
29
|
+
hooks.addAction('framework_init', () => {
|
|
30
|
+
logger.info('[[FRAMEWORK]] - El framework ha sido inicializado');
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
// Hook que se ejecuta antes de iniciar el servidor
|
|
34
|
+
hooks.addAction('pre_server_start', (serverInstance) => {
|
|
35
|
+
logger.info('[[HOOK]] - Antes de iniciar el servidor');
|
|
36
|
+
logger.info('[[HOOK]] - Puerto configurado:', serverInstance.port);
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
// Hook que se ejecuta después de iniciar el servidor
|
|
40
|
+
hooks.addAction('post_server_start', (serverInstance) => {
|
|
41
|
+
logger.info('[[HOOK]] - Servidor iniciado exitosamente');
|
|
42
|
+
logger.info('[[HOOK]] - Escuchando en:', `http://${serverInstance.host}:${serverInstance.port}`);
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
// Hook que se ejecuta antes de cargar rutas
|
|
46
|
+
hooks.addAction('pre_route_load', (filePath, serverInstance) => {
|
|
47
|
+
logger.info('[[HOOK]] - A punto de cargar rutas desde:', filePath);
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
// Hook que se ejecuta después de cargar rutas
|
|
51
|
+
hooks.addAction('post_route_load', (routes, serverInstance) => {
|
|
52
|
+
logger.info('[[HOOK]] - Rutas cargadas exitosamente:', routes.length, 'rutas');
|
|
53
|
+
routes.forEach((route, index) => {
|
|
54
|
+
logger.info(`[[HOOK]] - Ruta ${index + 1}: ${route.method} ${route.path}`);
|
|
55
|
+
});
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
// Hook que se ejecuta antes de cargar un controlador
|
|
59
|
+
hooks.addAction('pre_controller_load', (controllerPath) => {
|
|
60
|
+
logger.info('[[HOOK]] - A punto de cargar controlador:', controllerPath);
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
// Hook que se ejecuta después de cargar un controlador
|
|
64
|
+
hooks.addAction('post_controller_load', (controllerModule, absolutePath) => {
|
|
65
|
+
logger.info('[[HOOK]] - Controlador cargado exitosamente:', absolutePath);
|
|
66
|
+
// Podríamos inspeccionar las funciones disponibles en el módulo
|
|
67
|
+
const availableHandlers = Object.keys(controllerModule).filter(key =>
|
|
68
|
+
typeof controllerModule[key] === 'function'
|
|
69
|
+
);
|
|
70
|
+
logger.info('[[HOOK]] - Handlers disponibles en el controlador:', availableHandlers);
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
// Ejemplo de uso de filtros
|
|
74
|
+
hooks.addFilter('modify_response_data', (data, endpoint) => {
|
|
75
|
+
// Añadir información de auditoría a todas las respuestas
|
|
76
|
+
return {
|
|
77
|
+
...data,
|
|
78
|
+
_hook_processed: true,
|
|
79
|
+
_timestamp: new Date().toISOString(),
|
|
80
|
+
_endpoint: endpoint
|
|
81
|
+
};
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
// Cargar rutas desde archivo JSON
|
|
85
|
+
const routeLoader = new RouteLoader();
|
|
86
|
+
await routeLoader.loadRoutes(server, './routes.json');
|
|
87
|
+
|
|
88
|
+
// Iniciar el servidor
|
|
89
|
+
server.start();
|
|
90
|
+
|
|
91
|
+
logger.info('Servidor iniciado con sistema de hooks activo');
|
|
92
|
+
} catch (error) {
|
|
93
|
+
logger.error('Error iniciando el servidor:', error.message);
|
|
94
|
+
process.exit(1);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// Iniciar el servidor
|
|
99
|
+
startServer();
|
|
100
|
+
|
|
101
|
+
module.exports = { startServer };
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
const jerk = require('../../../index.js');
|
|
2
|
+
const hooks = jerk.hooks;
|
|
3
|
+
|
|
4
|
+
const hooksController = {
|
|
5
|
+
getHooksInfo: (req, res) => {
|
|
6
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
7
|
+
res.end(JSON.stringify({
|
|
8
|
+
message: 'Información sobre el sistema de hooks',
|
|
9
|
+
hooksSystem: {
|
|
10
|
+
'actionsRegistradas': hooks.actions ? hooks.actions.size : 0,
|
|
11
|
+
'filtersRegistrados': hooks.filters ? hooks.filters.size : 0,
|
|
12
|
+
'accionesDisponibles': [
|
|
13
|
+
'framework_init',
|
|
14
|
+
'pre_server_start',
|
|
15
|
+
'post_server_start',
|
|
16
|
+
'pre_route_load',
|
|
17
|
+
'post_route_load',
|
|
18
|
+
'pre_controller_load',
|
|
19
|
+
'post_controller_load'
|
|
20
|
+
],
|
|
21
|
+
'ejemploUso': 'hooks.addAction(nombreHook, funcionCallback)',
|
|
22
|
+
'ejemploFiltro': 'hooks.addFilter(nombreFiltro, funcionCallback)'
|
|
23
|
+
},
|
|
24
|
+
timestamp: new Date().toISOString()
|
|
25
|
+
}));
|
|
26
|
+
}
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
module.exports = hooksController;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
const mainController = {
|
|
2
|
+
home: (req, res) => {
|
|
3
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
4
|
+
res.end(JSON.stringify({
|
|
5
|
+
message: 'API con sistema de hooks activo',
|
|
6
|
+
features: [
|
|
7
|
+
'Pre/Post hooks para carga de rutas',
|
|
8
|
+
'Pre/Post hooks para carga de controladores',
|
|
9
|
+
'Pre/Post hooks para inicio de servidor',
|
|
10
|
+
'Filtros para modificar datos de respuesta',
|
|
11
|
+
'Extensibilidad en múltiples puntos del ciclo de vida'
|
|
12
|
+
],
|
|
13
|
+
timestamp: new Date().toISOString()
|
|
14
|
+
}));
|
|
15
|
+
}
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
module.exports = mainController;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "jerk-hooks-demo",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Ejemplo de API con sistema de hooks para extensibilidad usando el Framework JERK",
|
|
5
|
+
"main": "app.js",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"start": "node app.js",
|
|
8
|
+
"dev": "nodemon app.js"
|
|
9
|
+
},
|
|
10
|
+
"keywords": [
|
|
11
|
+
"api",
|
|
12
|
+
"sdk",
|
|
13
|
+
"hooks",
|
|
14
|
+
"filters",
|
|
15
|
+
"extensibility",
|
|
16
|
+
"wordpress",
|
|
17
|
+
"framework"
|
|
18
|
+
],
|
|
19
|
+
"author": "JERK Framework",
|
|
20
|
+
"license": "MIT",
|
|
21
|
+
"dependencies": {
|
|
22
|
+
"jsonwebtoken": "^9.0.0"
|
|
23
|
+
},
|
|
24
|
+
"devDependencies": {
|
|
25
|
+
"nodemon": "^3.0.0"
|
|
26
|
+
}
|
|
27
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
[
|
|
2
|
+
{
|
|
3
|
+
"path": "/",
|
|
4
|
+
"method": "GET",
|
|
5
|
+
"controller": "./controllers/mainController.js",
|
|
6
|
+
"handler": "home",
|
|
7
|
+
"auth": "none"
|
|
8
|
+
},
|
|
9
|
+
{
|
|
10
|
+
"path": "/hooks-info",
|
|
11
|
+
"method": "GET",
|
|
12
|
+
"controller": "./controllers/hooksController.js",
|
|
13
|
+
"handler": "getHooksInfo",
|
|
14
|
+
"auth": "none"
|
|
15
|
+
}
|
|
16
|
+
]
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
# Ejemplo API con Funcionalidades OpenAPI (v2.1.0)
|
|
2
|
+
|
|
3
|
+
Este ejemplo demuestra cómo crear una API con funcionalidades OpenAPI integradas utilizando el Framework JERK.
|
|
4
|
+
|
|
5
|
+
## Características de OpenAPI
|
|
6
|
+
|
|
7
|
+
- **Generación automática de documentación OpenAPI 3.0**
|
|
8
|
+
- **Interfaz Swagger UI interactiva**
|
|
9
|
+
- **Definición de esquemas de datos**
|
|
10
|
+
- **Documentación de seguridad y autenticación**
|
|
11
|
+
- **Especificación de endpoints, parámetros y respuestas**
|
|
12
|
+
- **Soporte para diferentes formatos de contenido**
|
|
13
|
+
- **Validación de peticiones y respuestas**
|
|
14
|
+
|
|
15
|
+
## Configuración
|
|
16
|
+
|
|
17
|
+
No se requieren dependencias adicionales más allá del Framework JERK.
|
|
18
|
+
|
|
19
|
+
## Uso
|
|
20
|
+
|
|
21
|
+
1. Inicia el servidor:
|
|
22
|
+
```bash
|
|
23
|
+
node app.js
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
2. El servidor escuchará en `http://localhost:8096`
|
|
27
|
+
|
|
28
|
+
## Endpoints
|
|
29
|
+
|
|
30
|
+
- `GET /` - Página de inicio con información de OpenAPI
|
|
31
|
+
- `POST /login` - Iniciar sesión y obtener token
|
|
32
|
+
- `GET /users` - Lista de usuarios (requiere token)
|
|
33
|
+
- `GET /products` - Lista de productos (requiere token)
|
|
34
|
+
- `GET /docs` - Documentación interactiva OpenAPI/Swagger
|
|
35
|
+
- `GET /openapi.json` - Especificación OpenAPI
|
|
36
|
+
|
|
37
|
+
## Ejemplo de uso
|
|
38
|
+
|
|
39
|
+
1. Iniciar sesión:
|
|
40
|
+
```bash
|
|
41
|
+
curl -X POST http://localhost:8096/login \
|
|
42
|
+
-H "Content-Type: application/json" \
|
|
43
|
+
-d '{"username": "admin", "password": "password"}'
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
2. Acceder a usuarios con el token:
|
|
47
|
+
```bash
|
|
48
|
+
curl -X GET http://localhost:8096/users \
|
|
49
|
+
-H "Authorization: Bearer TU_TOKEN_AQUI"
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
3. Ver documentación interactiva:
|
|
53
|
+
Visita `http://localhost:8096/docs` en tu navegador
|
|
54
|
+
|
|
55
|
+
4. Obtener especificación OpenAPI:
|
|
56
|
+
```bash
|
|
57
|
+
curl -X GET http://localhost:8096/openapi.json
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
## Estructura del proyecto
|
|
61
|
+
|
|
62
|
+
```
|
|
63
|
+
examples/v2.1_openapi_demo/
|
|
64
|
+
├── app.js # Punto de entrada de la aplicación
|
|
65
|
+
├── controllers/ # Controladores de las rutas
|
|
66
|
+
│ ├── mainController.js
|
|
67
|
+
│ ├── authController.js
|
|
68
|
+
│ ├── userController.js
|
|
69
|
+
│ └── productController.js
|
|
70
|
+
└── README.md
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
## Documentación OpenAPI
|
|
74
|
+
|
|
75
|
+
El framework genera automáticamente:
|
|
76
|
+
|
|
77
|
+
- Una especificación OpenAPI 3.0 en `/openapi.json`
|
|
78
|
+
- Una interfaz Swagger UI interactiva en `/docs`
|
|
79
|
+
- Esquemas de datos definidos para reutilización
|
|
80
|
+
- Documentación detallada de endpoints, parámetros y respuestas
|
|
81
|
+
- Soporte para diferentes códigos de respuesta HTTP
|
|
82
|
+
- Definición de esquemas de seguridad
|
|
@@ -0,0 +1,296 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Ejemplo de API con funcionalidades OpenAPI (v2.1.0)
|
|
3
|
+
* Demostrando la generación automática de documentación OpenAPI
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
const {
|
|
7
|
+
APIServer,
|
|
8
|
+
Authenticator,
|
|
9
|
+
Logger,
|
|
10
|
+
OpenApiGenerator
|
|
11
|
+
} = require('../../index.js');
|
|
12
|
+
|
|
13
|
+
async function startServer() {
|
|
14
|
+
// Crear instancia del servidor
|
|
15
|
+
const server = new APIServer({
|
|
16
|
+
port: 8096,
|
|
17
|
+
host: 'localhost'
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
// Crear instancia del logger
|
|
21
|
+
const logger = new Logger({ level: 'info' });
|
|
22
|
+
|
|
23
|
+
// Crear instancia del autenticador
|
|
24
|
+
const authenticator = new Authenticator({ logger });
|
|
25
|
+
|
|
26
|
+
// Registrar estrategia de autenticación JWT
|
|
27
|
+
authenticator.use('jwt-openapi', authenticator.jwtStrategy('super-secret-key-for-openapi-example'));
|
|
28
|
+
|
|
29
|
+
try {
|
|
30
|
+
// Crear instancia del generador de OpenAPI
|
|
31
|
+
const openApiGenerator = new OpenApiGenerator({
|
|
32
|
+
title: 'API de Ejemplo con OpenAPI',
|
|
33
|
+
description: 'API que demuestra la funcionalidad OpenAPI del Framework JERK',
|
|
34
|
+
version: '2.1.0',
|
|
35
|
+
servers: [
|
|
36
|
+
{ url: 'http://localhost:8096', description: 'Servidor de desarrollo' }
|
|
37
|
+
]
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
// Definir esquemas para la documentación
|
|
41
|
+
openApiGenerator.addSchema('User', {
|
|
42
|
+
type: 'object',
|
|
43
|
+
properties: {
|
|
44
|
+
id: { type: 'integer', example: 1 },
|
|
45
|
+
name: { type: 'string', example: 'John Doe' },
|
|
46
|
+
email: { type: 'string', example: 'john@example.com' },
|
|
47
|
+
role: { type: 'string', example: 'user' }
|
|
48
|
+
},
|
|
49
|
+
required: ['id', 'name', 'email']
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
openApiGenerator.addSchema('Product', {
|
|
53
|
+
type: 'object',
|
|
54
|
+
properties: {
|
|
55
|
+
id: { type: 'integer', example: 1 },
|
|
56
|
+
name: { type: 'string', example: 'Laptop' },
|
|
57
|
+
price: { type: 'number', example: 999.99 },
|
|
58
|
+
category: { type: 'string', example: 'Electronics' }
|
|
59
|
+
},
|
|
60
|
+
required: ['id', 'name', 'price']
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
openApiGenerator.addSchema('LoginRequest', {
|
|
64
|
+
type: 'object',
|
|
65
|
+
properties: {
|
|
66
|
+
username: { type: 'string', example: 'admin' },
|
|
67
|
+
password: { type: 'string', example: 'password' }
|
|
68
|
+
},
|
|
69
|
+
required: ['username', 'password']
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
openApiGenerator.addSchema('LoginResponse', {
|
|
73
|
+
type: 'object',
|
|
74
|
+
properties: {
|
|
75
|
+
message: { type: 'string', example: 'Inicio de sesión exitoso' },
|
|
76
|
+
token: { type: 'string', example: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...' },
|
|
77
|
+
user: { $ref: '#/components/schemas/User' }
|
|
78
|
+
}
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
// Agregar rutas a la documentación OpenAPI
|
|
82
|
+
openApiGenerator.addRoute({
|
|
83
|
+
path: '/',
|
|
84
|
+
method: 'GET',
|
|
85
|
+
config: {
|
|
86
|
+
summary: 'Página de inicio',
|
|
87
|
+
description: 'Devuelve información básica sobre la API y sus funcionalidades OpenAPI',
|
|
88
|
+
responses: {
|
|
89
|
+
'200': {
|
|
90
|
+
description: 'Información de la API',
|
|
91
|
+
content: {
|
|
92
|
+
'application/json': {
|
|
93
|
+
schema: {
|
|
94
|
+
type: 'object',
|
|
95
|
+
properties: {
|
|
96
|
+
message: { type: 'string' },
|
|
97
|
+
features: { type: 'array', items: { type: 'string' } },
|
|
98
|
+
timestamp: { type: 'string', format: 'date-time' }
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
openApiGenerator.addRoute({
|
|
109
|
+
path: '/login',
|
|
110
|
+
method: 'POST',
|
|
111
|
+
config: {
|
|
112
|
+
summary: 'Iniciar sesión',
|
|
113
|
+
description: 'Autenticación de usuario y obtención de token JWT',
|
|
114
|
+
requestBody: {
|
|
115
|
+
content: {
|
|
116
|
+
'application/json': {
|
|
117
|
+
schema: { $ref: '#/components/schemas/LoginRequest' }
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
},
|
|
121
|
+
responses: {
|
|
122
|
+
'200': {
|
|
123
|
+
description: 'Inicio de sesión exitoso',
|
|
124
|
+
content: {
|
|
125
|
+
'application/json': {
|
|
126
|
+
schema: { $ref: '#/components/schemas/LoginResponse' }
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
},
|
|
130
|
+
'401': {
|
|
131
|
+
description: 'Credenciales inválidas'
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
openApiGenerator.addRoute({
|
|
138
|
+
path: '/users',
|
|
139
|
+
method: 'GET',
|
|
140
|
+
config: {
|
|
141
|
+
summary: 'Obtener usuarios',
|
|
142
|
+
description: 'Lista de usuarios registrados (requiere autenticación JWT)',
|
|
143
|
+
security: [{ bearerAuth: [] }],
|
|
144
|
+
responses: {
|
|
145
|
+
'200': {
|
|
146
|
+
description: 'Lista de usuarios',
|
|
147
|
+
content: {
|
|
148
|
+
'application/json': {
|
|
149
|
+
schema: {
|
|
150
|
+
type: 'array',
|
|
151
|
+
items: { $ref: '#/components/schemas/User' }
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
openApiGenerator.addRoute({
|
|
161
|
+
path: '/products',
|
|
162
|
+
method: 'GET',
|
|
163
|
+
config: {
|
|
164
|
+
summary: 'Obtener productos',
|
|
165
|
+
description: 'Lista de productos disponibles (requiere autenticación JWT)',
|
|
166
|
+
security: [{ bearerAuth: [] }],
|
|
167
|
+
responses: {
|
|
168
|
+
'200': {
|
|
169
|
+
description: 'Lista de productos',
|
|
170
|
+
content: {
|
|
171
|
+
'application/json': {
|
|
172
|
+
schema: {
|
|
173
|
+
type: 'array',
|
|
174
|
+
items: { $ref: '#/components/schemas/Product' }
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
// Agregar esquema de seguridad
|
|
184
|
+
openApiGenerator.addSecurityScheme('bearerAuth', {
|
|
185
|
+
type: 'http',
|
|
186
|
+
scheme: 'bearer',
|
|
187
|
+
bearerFormat: 'JWT',
|
|
188
|
+
description: 'Autenticación por token JWT'
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
// Agregar rutas de documentación al servidor
|
|
192
|
+
openApiGenerator.addDocumentationRoute(server);
|
|
193
|
+
|
|
194
|
+
// Ruta pública
|
|
195
|
+
server.addRoute('GET', '/', (req, res) => {
|
|
196
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
197
|
+
res.end(JSON.stringify({
|
|
198
|
+
message: 'API con funcionalidades OpenAPI (v2.1.0)',
|
|
199
|
+
features: [
|
|
200
|
+
'Generación automática de documentación OpenAPI 3.0',
|
|
201
|
+
'Interfaz Swagger UI interactiva',
|
|
202
|
+
'Esquemas de datos definidos',
|
|
203
|
+
'Documentación de seguridad',
|
|
204
|
+
'Especificación de endpoints, parámetros y respuestas'
|
|
205
|
+
],
|
|
206
|
+
timestamp: new Date().toISOString()
|
|
207
|
+
}));
|
|
208
|
+
});
|
|
209
|
+
|
|
210
|
+
// Ruta de login
|
|
211
|
+
server.addRoute('POST', '/login', (req, res) => {
|
|
212
|
+
let body = req.body;
|
|
213
|
+
|
|
214
|
+
// Si body es string, intentar parsear como JSON
|
|
215
|
+
if (typeof body === 'string') {
|
|
216
|
+
try {
|
|
217
|
+
body = JSON.parse(body);
|
|
218
|
+
} catch (parseError) {
|
|
219
|
+
res.writeHead(400, { 'Content-Type': 'application/json' });
|
|
220
|
+
res.end(JSON.stringify({ error: 'Formato de solicitud inválido' }));
|
|
221
|
+
return;
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
const { username, password } = body;
|
|
226
|
+
|
|
227
|
+
// Simulación de autenticación
|
|
228
|
+
if (username === 'admin' && password === 'password') {
|
|
229
|
+
// Generar token JWT
|
|
230
|
+
const jwt = require('jsonwebtoken');
|
|
231
|
+
const token = jwt.sign(
|
|
232
|
+
{ userId: 1, username: username, role: 'admin' },
|
|
233
|
+
'super-secret-key-for-openapi-example',
|
|
234
|
+
{ expiresIn: '1h' }
|
|
235
|
+
);
|
|
236
|
+
|
|
237
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
238
|
+
res.end(JSON.stringify({
|
|
239
|
+
message: 'Inicio de sesión exitoso',
|
|
240
|
+
token: token,
|
|
241
|
+
user: { userId: 1, username: username, role: 'admin' }
|
|
242
|
+
}));
|
|
243
|
+
} else {
|
|
244
|
+
res.writeHead(401, { 'Content-Type': 'application/json' });
|
|
245
|
+
res.end(JSON.stringify({ error: 'Credenciales inválidas' }));
|
|
246
|
+
}
|
|
247
|
+
});
|
|
248
|
+
|
|
249
|
+
// Ruta protegida - Usuarios
|
|
250
|
+
server.addRoute('GET', '/users', (req, res) => {
|
|
251
|
+
authenticator.authenticate('jwt-openapi')(req, res, () => {
|
|
252
|
+
if (req.user) {
|
|
253
|
+
const users = [
|
|
254
|
+
{ id: 1, name: 'John Doe', email: 'john@example.com', role: 'admin' },
|
|
255
|
+
{ id: 2, name: 'Jane Smith', email: 'jane@example.com', role: 'user' },
|
|
256
|
+
{ id: 3, name: 'Robert Johnson', email: 'robert@example.com', role: 'user' }
|
|
257
|
+
];
|
|
258
|
+
|
|
259
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
260
|
+
res.end(JSON.stringify(users));
|
|
261
|
+
}
|
|
262
|
+
});
|
|
263
|
+
});
|
|
264
|
+
|
|
265
|
+
// Ruta protegida - Productos
|
|
266
|
+
server.addRoute('GET', '/products', (req, res) => {
|
|
267
|
+
authenticator.authenticate('jwt-openapi')(req, res, () => {
|
|
268
|
+
if (req.user) {
|
|
269
|
+
const products = [
|
|
270
|
+
{ id: 1, name: 'Laptop', price: 999.99, category: 'Electronics' },
|
|
271
|
+
{ id: 2, name: 'Mouse', price: 29.99, category: 'Electronics' },
|
|
272
|
+
{ id: 3, name: 'Keyboard', price: 79.99, category: 'Electronics' }
|
|
273
|
+
];
|
|
274
|
+
|
|
275
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
276
|
+
res.end(JSON.stringify(products));
|
|
277
|
+
}
|
|
278
|
+
});
|
|
279
|
+
});
|
|
280
|
+
|
|
281
|
+
// Iniciar el servidor
|
|
282
|
+
server.start();
|
|
283
|
+
|
|
284
|
+
logger.info('Servidor OpenAPI iniciado en http://localhost:8096');
|
|
285
|
+
logger.info('Documentación OpenAPI disponible en http://localhost:8096/docs');
|
|
286
|
+
logger.info('Especificación OpenAPI disponible en http://localhost:8096/openapi.json');
|
|
287
|
+
} catch (error) {
|
|
288
|
+
logger.error('Error iniciando el servidor:', error.message);
|
|
289
|
+
process.exit(1);
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
// Iniciar el servidor
|
|
294
|
+
startServer();
|
|
295
|
+
|
|
296
|
+
module.exports = { startServer };
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "jerk-openapi-demo",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Ejemplo de API con funcionalidades OpenAPI usando el Framework JERK",
|
|
5
|
+
"main": "app.js",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"start": "node app.js",
|
|
8
|
+
"dev": "nodemon app.js"
|
|
9
|
+
},
|
|
10
|
+
"keywords": [
|
|
11
|
+
"api",
|
|
12
|
+
"sdk",
|
|
13
|
+
"openapi",
|
|
14
|
+
"swagger",
|
|
15
|
+
"documentation",
|
|
16
|
+
"framework"
|
|
17
|
+
],
|
|
18
|
+
"author": "JERK Framework",
|
|
19
|
+
"license": "MIT",
|
|
20
|
+
"dependencies": {
|
|
21
|
+
"jsonwebtoken": "^9.0.0"
|
|
22
|
+
},
|
|
23
|
+
"devDependencies": {
|
|
24
|
+
"nodemon": "^3.0.0"
|
|
25
|
+
}
|
|
26
|
+
}
|