Hapi.js es un marco para crear aplicaciones web. Esta publicación contiene todos los elementos esenciales para un arranque en caliente. Desafortunadamente, el autor no es escritor en absoluto, por lo que habrá mucho código y pocas palabras.
MVP
Pon un montón de dependencias:
npm i @hapi/hapi @hapi/boom filepaths hapi-boom-decorators
- hapi / hapi - en realidad, nuestro servidor
- hapi / boom - módulo para generar respuestas estándar
- decoradores hapi-boom - ayudante para hapi / boom
- filepaths: una utilidad que lee carpetas de forma recursiva
Cree una estructura de carpetas y un montón de archivos de inicio:

En ./src/routes/ agregamos una descripción de puntos finales api, 1 archivo - 1 punto final:
./src/server.js: el módulo que exporta el servidor en sí.
En ./server.js todo lo que hacemos es llamar a createServer ()
#!/usr/bin/env node const createServer = require('./src/server'); createServer();
Lanzamos
node server.js
Y verifica:
curl http://127.0.0.1:3030/ {"result":"ok","message":"Hello World!"} curl http://127.0.0.1:3030/test {"statusCode":404,"error":"Not Found","message":"Not Found"}
En la naturaleza
En un proyecto real, como mínimo, necesitamos una base de datos, un registrador, autorización, manejo de errores y mucho más.
Agregar secuencializar
ORM sequelize está conectado como un módulo:
... const Sequelize = require('sequelize'); ... await server.register([ ... { plugin: require('hapi-sequelizejs'), options: [ { name: config.db.database,
La base de datos está disponible dentro de la ruta a través de una llamada:
async function response(request) { const model = request.getModel('_', '_'); }
Inyecte módulos adicionales en la solicitud
Es necesario interceptar el evento "onRequest", dentro del cual inyectaremos la configuración y el registrador en el objeto de solicitud:
... const Logger = require('./libs/Logger'); ... async function createServer(logLVL=config.logLVL) { ... const logger = new Logger(logLVL, 'my-hapi-app'); ... server.ext({ type: 'onRequest', method: async function (request, h) { request.server.config = Object.assign({}, config); request.server.logger = logger; return h.continue; } }); ... }
Después de eso, dentro del controlador de solicitudes, tendremos acceso a la configuración, el registrador y la base de datos, sin la necesidad de incluir algo adicional en el cuerpo del módulo:
Por lo tanto, el controlador de solicitudes en la entrada recibirá todo lo necesario para su procesamiento, y no será necesario incluir los mismos módulos cada vez.
Iniciar sesión
La autorización en hapi se realiza en forma de módulos.
... const AuthBearer = require('hapi-auth-bearer-token'); ... async function createServer(logLVL=config.logLVL) { ... await server.register([ AuthBearer, ... ]); server.auth.strategy('token', 'bearer-access-token', {
Y también dentro de la ruta debe especificar qué tipo de autorización usar:
module.exports = { method: 'GET', path: '/', auth: 'token',
Si se utilizan varios tipos de autorización:
auth: { strategies: ['token1', 'token2', 'something_else'] },
Manejo de errores
Por defecto, boom genera errores de forma estándar, a menudo estas respuestas deben envolverse en su propio formato.
server.ext('onPreResponse', function (request, h) {
Esquemas de datos
Este es un tema pequeño pero muy importante. Los esquemas de datos le permiten verificar la validez de la solicitud y la exactitud de la respuesta. Qué tan bien describe estos esquemas, por lo que la arrogancia y las pruebas automáticas serán de tal calidad.
Todos los esquemas de datos se describen a través de joi. Hagamos un ejemplo para la autorización del usuario:
const Joi = require('@hapi/joi'); const Boom = require('boom'); async function response(request) {
Prueba:
curl -X GET "http://localhost:3030/auth?login=pupkin@gmail.com&password=12345"

Ahora envíe en lugar de correo, solo inicie sesión:
curl -X GET "http://localhost:3030/auth?login=pupkin&password=12345"

Si la respuesta no coincide con el esquema de respuesta, entonces el servidor también caerá en un error 500.
Si el proyecto comenzó a procesar más de 1 solicitud por hora, puede ser necesario limitar la verificación de respuestas, ya que La verificación es una operación que requiere muchos recursos. Hay un parámetro para esto: "muestra"
module.exports = { method: 'GET', path: '/auth', options: { handler: response, validate: { query: requestScheme }, response: { sample: 50, schema: responseScheme } } };
Como tal, solo el 50% de las solicitudes serán respuestas validadas.
Es muy importante describir los valores y ejemplos predeterminados, en el futuro se utilizarán para generar documentación y pruebas automáticas.
Swagger / OpenAPI
Necesitamos un montón de módulos adicionales:
npm i hapi-swagger @hapi/inert @hapi/vision
Los conectamos a server.js
... const Inert = require('@hapi/inert'); const Vision = require('@hapi/vision'); const HapiSwagger = require('hapi-swagger'); const Package = require('../package'); ... const swaggerOptions = { info: { title: Package.name + ' API Documentation', description: Package.description }, jsonPath: '/documentation.json', documentationPath: '/documentation', schemes: ['https', 'http'], host: config.swaggerHost, debug: true }; ... async function createServer(logLVL=config.logLVL) { ... await server.register([ ... Inert, Vision, { plugin: HapiSwagger, options: swaggerOptions }, ... ]); ... });
Y en cada ruta debes poner la etiqueta "api":
module.exports = { method: 'GET', path: '/auth', options: { handler: response, tags: [ 'api' ],
Ahora en http: // localhost: 3030 / documentation , estará disponible una cara web con documentación , y en http: // localhost: 3030 / documentation.json .json una descripción.

Auto Test Generation
Si hemos descrito cualitativamente los esquemas de solicitud y respuesta, hemos preparado una base de datos inicial correspondiente a los ejemplos descritos en los ejemplos de solicitud, luego, utilizando esquemas conocidos, puede generar automáticamente solicitudes y verificar los códigos de respuesta del servidor.
Por ejemplo, en GET: / auth se esperan parámetros de inicio de sesión y contraseña, los tomaremos de los ejemplos que especificamos en el diagrama:
const requestScheme =Joi.object({ login: Joi.string().email().required().example('pupkin@gmail.com'), password: Joi.string().required().example('12345') });
Y si el servidor responde con HTTP-200-OK, entonces asumimos que la prueba ha pasado.
Desafortunadamente, no había un módulo adecuado listo para usar; tienes que hablar un poco:
No te olvides de las dependencias:
npm i request-promise mocha sync-request
Y sobre package.json
... "scripts": { "test": "mocha", "dbinit": "node ./scripts/dbInit.js" }, ...
Comprobamos:
npm test

Y si el bloqueo es algún tipo de esquema de datos, o la respuesta no coincide con el esquema:

Y no olvide que tarde o temprano las pruebas se volverán sensibles a los datos de la base de datos. Antes de ejecutar las pruebas, debe al menos borrar la base de datos.
Fuentes enteras