Hapi.js est un cadre pour la création d'applications Web. Ce message contient tous les éléments essentiels pour un démarrage à chaud. Malheureusement, l'auteur n'est pas du tout un écrivain, il y aura beaucoup de code et peu de mots.
MVP
Mettez un tas de dépendances:
npm i @hapi/hapi @hapi/boom filepaths hapi-boom-decorators
- hapi / hapi - en fait, notre serveur
- hapi / boom - module pour générer des réponses standard
- hapi-boom-decorators - assistant pour hapi / boom
- filepaths - un utilitaire qui lit récursivement les dossiers
Créez une structure de dossiers et un tas de fichiers de démarrage:

Dans ./src/routes/, nous ajoutons une description des points finaux api, 1 fichier - 1 point final:
./src/server.js - le module qui exporte le serveur lui-mĂȘme.
Dans ./server.js, tout ce que nous faisons est d'appeler createServer ()
#!/usr/bin/env node const createServer = require('./src/server'); createServer();
Nous lançons
node server.js
Et vérifiez:
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"}
Dans la nature
Dans un vrai projet, au minimum, nous avons besoin d'une base de données, d'un enregistreur, d'une autorisation, d'une gestion des erreurs et bien plus encore.
Ajouter séquelle
ORM sequelize est connecté en tant que module:
... const Sequelize = require('sequelize'); ... await server.register([ ... { plugin: require('hapi-sequelizejs'), options: [ { name: config.db.database,
La base de données devient disponible à l'intérieur de l'itinéraire via un appel:
async function response(request) { const model = request.getModel('_', '_'); }
Injecter des modules supplémentaires dans la demande
Il est nécessaire d'intercepter l'événement "onRequest", à l'intérieur duquel nous injecterons la config et le logger dans l'objet request:
... 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; } }); ... }
AprĂšs cela, Ă l'intĂ©rieur du gestionnaire de requĂȘtes, nous aurons accĂšs Ă la configuration, Ă l'enregistreur et Ă la base de donnĂ©es, sans avoir besoin d'inclure en outre quelque chose dans le corps du module:
Ainsi, le gestionnaire de requĂȘtes en entrĂ©e recevra tout le nĂ©cessaire pour son traitement, et il ne sera pas nĂ©cessaire d'inclure Ă chaque fois les mĂȘmes modules.
Se connecter
L'autorisation en hapi se fait sous forme de modules.
... const AuthBearer = require('hapi-auth-bearer-token'); ... async function createServer(logLVL=config.logLVL) { ... await server.register([ AuthBearer, ... ]); server.auth.strategy('token', 'bearer-access-token', {
Et également à l'intérieur de l'itinéraire, vous devez spécifier le type d'autorisation à utiliser:
module.exports = { method: 'GET', path: '/', auth: 'token',
Si plusieurs types d'autorisation sont utilisés:
auth: { strategies: ['token1', 'token2', 'something_else'] },
Gestion des erreurs
Par dĂ©faut, boom gĂ©nĂšre des erreurs de maniĂšre standard, souvent ces rĂ©ponses doivent ĂȘtre emballĂ©es dans leur propre format.
server.ext('onPreResponse', function (request, h) {
Schémas de données
C'est un sujet petit mais trÚs important. Les schémas de données vous permettent de vérifier la validité de la demande et l'exactitude de la réponse. Dans quelle mesure vous décrivez ces schémas, les tests et les autotests seront donc d'une telle qualité.
Tous les schémas de données sont décrits via joi. Faisons un exemple d'autorisation d'utilisateur:
const Joi = require('@hapi/joi'); const Boom = require('boom'); async function response(request) {
Test:
curl -X GET "http://localhost:3030/auth?login=pupkin@gmail.com&password=12345"

Maintenant, envoyez au lieu du courrier, connectez-vous uniquement:
curl -X GET "http://localhost:3030/auth?login=pupkin&password=12345"

Si la réponse ne correspond pas au schéma de réponse, le serveur tombera également dans une erreur 500.
Si le projet a commencĂ© Ă traiter plus d'une demande par heure, il peut ĂȘtre nĂ©cessaire de limiter la vĂ©rification des rĂ©ponses, car la vĂ©rification est une opĂ©ration gourmande en ressources. Il y a un paramĂštre pour cela: "Ă©chantillon"
module.exports = { method: 'GET', path: '/auth', options: { handler: response, validate: { query: requestScheme }, response: { sample: 50, schema: responseScheme } } };
Ainsi, seulement 50% des demandes seront des réponses validées.
Il est trÚs important de décrire les valeurs par défaut et les exemples, à l'avenir, ils seront utilisés pour générer de la documentation et des autotests.
Swagger / OpenAPI
Nous avons besoin d'un tas de modules supplémentaires:
npm i hapi-swagger @hapi/inert @hapi/vision
Nous les connectons Ă 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 }, ... ]); ... });
Et dans chaque itinéraire, vous devez mettre la balise "api":
module.exports = { method: 'GET', path: '/auth', options: { handler: response, tags: [ 'api' ],
Maintenant, sur http: // localhost: 3030 / documentation, une page Web avec documentation sera disponible, et sur http: // localhost: 3030 / documentation.json .json, une description.

Génération de test automatique
Si nous avons décrit qualitativement les schémas de demande et de réponse, préparé une base de données de départ correspondant aux exemples décrits dans les exemples de demande, puis, à l'aide de schémas bien connus, vous pouvez générer automatiquement des demandes et vérifier les codes de réponse du serveur.
Par exemple, dans GET: / les paramÚtres de connexion et de mot de passe sont attendus, nous les prendrons à partir des exemples que nous avons spécifiés dans le diagramme:
const requestScheme =Joi.object({ login: Joi.string().email().required().example('pupkin@gmail.com'), password: Joi.string().required().example('12345') });
Et si le serveur répond avec HTTP-200-OK, nous supposerons que le test a réussi.
Malheureusement, il n'y avait pas de module appropriĂ© prĂȘt Ă l'emploi; vous devez parler un peu:
N'oubliez pas les dépendances:
npm i request-promise mocha sync-request
Et Ă propos de package.json
... "scripts": { "test": "mocha", "dbinit": "node ./scripts/dbInit.js" }, ...
Nous vérifions:
npm test

Et si le verrou est une sorte de schéma de données, ou si la réponse ne correspond pas au schéma:

Et n'oubliez pas que tÎt ou tard les tests deviendront sensibles aux données de la base de données. Avant d'exécuter les tests, vous devez au moins effacer la base de données.
Sources entiĂšres