Hapi.js ist ein Framework zum Erstellen von Webanwendungen. Dieser Beitrag enthält alle wichtigen Informationen für einen heißen Start. Leider ist der Autor überhaupt kein Schriftsteller, daher wird es viel Code und wenige Wörter geben.
MVP
Setzen Sie eine Reihe von Abhängigkeiten:
npm i @hapi/hapi @hapi/boom filepaths hapi-boom-decorators
- hapi / hapi - eigentlich unser server
- Hapi / Boom - Modul zur Generierung von Standardantworten
- Hapi-Boom-Dekorateure - Helfer für Hapi / Boom
- Dateipfade - ein Dienstprogramm, das Ordner rekursiv liest
Erstellen Sie eine Ordnerstruktur und eine Reihe von Startdateien:

In ./src/routes/ fügen wir eine Beschreibung der API-Endpunkte hinzu, 1 Datei - 1 Endpunkt:
./src/server.js - das Modul, das den Server selbst exportiert.
In ./server.js rufen wir nur createServer () auf
#!/usr/bin/env node const createServer = require('./src/server'); createServer();
Wir starten
node server.js
Und überprüfen Sie:
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"}
In freier Wildbahn
In einem realen Projekt benötigen wir mindestens eine Datenbank, einen Logger, eine Autorisierung, eine Fehlerbehandlung und vieles mehr.
Sequelize hinzufügen
ORM Sequelize ist als Modul verbunden:
... const Sequelize = require('sequelize'); ... await server.register([ ... { plugin: require('hapi-sequelizejs'), options: [ { name: config.db.database,
Die Datenbank wird innerhalb der Route durch einen Anruf verfügbar:
async function response(request) { const model = request.getModel('_', '_'); }
Fügen Sie zusätzliche Module in die Anforderung ein
Es ist notwendig, das "onRequest" -Ereignis abzufangen, in das wir die Konfiguration und den Logger in das Anforderungsobjekt einfügen:
... 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; } }); ... }
Danach haben wir im Request-Handler Zugriff auf die Konfiguration, den Logger und die Datenbank, ohne dass zusätzlich etwas in den Modulkörper aufgenommen werden muss:
Somit erhält der Anforderungshandler an der Eingabe alles, was für seine Verarbeitung erforderlich ist, und es ist nicht erforderlich, von Zeit zu Zeit dieselben Module einzuschließen.
Login
Die Autorisierung in Hapi erfolgt in Form von Modulen.
... const AuthBearer = require('hapi-auth-bearer-token'); ... async function createServer(logLVL=config.logLVL) { ... await server.register([ AuthBearer, ... ]); server.auth.strategy('token', 'bearer-access-token', {
Außerdem müssen Sie innerhalb der Route angeben, welche Art von Autorisierung verwendet werden soll:
module.exports = { method: 'GET', path: '/', auth: 'token',
Wenn mehrere Arten von Berechtigungen verwendet werden:
auth: { strategies: ['token1', 'token2', 'something_else'] },
Fehlerbehandlung
Standardmäßig generiert boom Fehler auf standardmäßige Weise. Oft müssen diese Antworten in einem eigenen Format verpackt werden.
server.ext('onPreResponse', function (request, h) {
Datenschemata
Dies ist ein kleines, aber sehr wichtiges Thema. Mithilfe von Datenschemata können Sie die Gültigkeit der Anforderung und die Richtigkeit der Antwort überprüfen. Wie gut Sie diese Schemata beschreiben, werden auch Prahlereien und Autotests von solcher Qualität sein.
Alle Datenschemata werden durch joi beschrieben. Machen wir ein Beispiel für die Benutzerautorisierung:
const Joi = require('@hapi/joi'); const Boom = require('boom'); async function response(request) {
Testen:
curl -X GET "http://localhost:3030/auth?login=pupkin@gmail.com&password=12345"

Jetzt senden statt mailen, nur anmelden:
curl -X GET "http://localhost:3030/auth?login=pupkin&password=12345"

Wenn die Antwort nicht mit dem Antwortschema übereinstimmt, wird der Server ebenfalls in einen 500-Fehler geraten.
Wenn das Projekt mehr als eine Anfrage pro Stunde verarbeitet hat, muss möglicherweise die Überprüfung der Antworten eingeschränkt werden Die Überprüfung ist eine ressourcenintensive Operation. Hierfür gibt es einen Parameter: "sample"
module.exports = { method: 'GET', path: '/auth', options: { handler: response, validate: { query: requestScheme }, response: { sample: 50, schema: responseScheme } } };
Daher werden nur 50% der Anfragen validierte Antworten sein.
Es ist sehr wichtig, die Standardwerte und Beispiele zu beschreiben. In Zukunft werden sie zum Generieren von Dokumentation und Autotests verwendet.
Swagger / OpenAPI
Wir brauchen eine Reihe zusätzlicher Module:
npm i hapi-swagger @hapi/inert @hapi/vision
Wir verbinden sie mit 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 }, ... ]); ... });
Und in jeder Route müssen Sie das Tag "api" setzen:
module.exports = { method: 'GET', path: '/auth', options: { handler: response, tags: [ 'api' ],
Jetzt steht unter http: // localhost: 3030 / documentation ein Webface mit Dokumentation zur Verfügung und unter http: // localhost: 3030 / documentation.json .json eine Beschreibung.

Automatische Testgenerierung
Wenn wir die Anforderungs- und Antwortschemata qualitativ beschrieben und eine Startdatenbank erstellt haben, die den in den Anforderungsbeispielen beschriebenen Beispielen entspricht, können Sie nach bekannten Schemata automatisch Anforderungen generieren und Server-Antwortcodes überprüfen.
Wenn beispielsweise in GET: / auth Login- und Kennwortparameter erwartet werden, werden diese den Beispielen entnommen, die wir im Diagramm angegeben haben:
const requestScheme =Joi.object({ login: Joi.string().email().required().example('pupkin@gmail.com'), password: Joi.string().required().example('12345') });
Wenn der Server mit HTTP-200-OK antwortet, gehen wir davon aus, dass der Test bestanden wurde.
Leider gab es kein vorgefertigtes geeignetes Modul, man muss ein wenig reden:
Vergessen Sie nicht die Abhängigkeiten:
npm i request-promise mocha sync-request
Und über package.json
... "scripts": { "test": "mocha", "dbinit": "node ./scripts/dbInit.js" }, ...
Wir prüfen:
npm test

Und wenn die Sperre eine Art Datenschema ist oder die Antwort nicht mit dem Schema übereinstimmt:

Und vergessen Sie nicht, dass die Tests früher oder später empfindlich auf die Daten in der Datenbank reagieren. Bevor Sie die Tests ausführen, müssen Sie mindestens die Datenbank löschen.
Ganze Quellen