O Hapi.js é uma estrutura para criar aplicativos da web. Este post contém todos os elementos essenciais para um começo quente. Infelizmente, o autor não é um escritor, portanto haverá muito código e poucas palavras.
MVP
Coloque um monte de dependências:
npm i @hapi/hapi @hapi/boom filepaths hapi-boom-decorators
- hapi / hapi - na verdade, nosso servidor
- hapi / boom - módulo para gerar respostas padrão
- hapi-boom-decorators - ajudante para hapi / boom
- caminhos de arquivo - um utilitário que lê recursivamente pastas
Crie uma estrutura de pastas e vários arquivos de inicialização:

Em ./src/routes/, adicionamos uma descrição dos pontos de extremidade da API, 1 arquivo - 1 ponto de extremidade:
./src/server.js - o módulo que exporta o próprio servidor.
Em ./server.js, tudo o que fazemos é chamar createServer ()
#!/usr/bin/env node const createServer = require('./src/server'); createServer();
Lançamos
node server.js
E verifique:
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"}
Em estado selvagem
Em um projeto real, no mínimo, precisamos de um banco de dados, um criador de logs, autorização, tratamento de erros e muito mais.
Adicionar sequenciar
O ORM sequelize está conectado como um módulo:
... const Sequelize = require('sequelize'); ... await server.register([ ... { plugin: require('hapi-sequelizejs'), options: [ { name: config.db.database,
O banco de dados fica disponível dentro da rota por meio de uma chamada:
async function response(request) { const model = request.getModel('_', '_'); }
Injete módulos adicionais na solicitação
É necessário interceptar o evento "onRequest", dentro do qual injetaremos a configuração e o logger no objeto de solicitação:
... 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; } }); ... }
Depois disso, dentro do manipulador de solicitações, teremos acesso à configuração, ao logger e ao banco de dados, sem a necessidade de incluir adicionalmente algo no corpo do módulo:
Assim, o manipulador de solicitações na entrada receberá tudo o necessário para seu processamento, e não será necessário incluir os mesmos módulos de tempos em tempos.
Entrar
A autorização no hapi é feita na 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', {
E também dentro da rota, você precisa especificar qual tipo de autorização usar:
module.exports = { method: 'GET', path: '/', auth: 'token',
Se vários tipos de autorização forem usados:
auth: { strategies: ['token1', 'token2', 'something_else'] },
Tratamento de erros
Por padrão, o boom gera erros de maneira padrão, geralmente essas respostas precisam ser agrupadas em seu próprio formato.
server.ext('onPreResponse', function (request, h) {
Esquemas de dados
Este é um tópico pequeno, mas muito importante. Os esquemas de dados permitem verificar a validade da solicitação e a exatidão da resposta. Como você descreve esses esquemas, o arrogância e os autotestes têm essa qualidade.
Todos os esquemas de dados são descritos através do joi. Vamos fazer um exemplo para autorização do usuário:
const Joi = require('@hapi/joi'); const Boom = require('boom'); async function response(request) {
Teste:
curl -X GET "http://localhost:3030/auth?login=pupkin@gmail.com&password=12345"

Agora envie em vez de correio, apenas faça o login:
curl -X GET "http://localhost:3030/auth?login=pupkin&password=12345"

Se a resposta não corresponder ao esquema de resposta, o servidor também cairá em um erro 500.
Se o projeto começou a processar mais de 1 solicitação por hora, pode ser necessário limitar a verificação das respostas, conforme verificação é uma operação que consome muitos recursos. Há um parâmetro para isso: "sample"
module.exports = { method: 'GET', path: '/auth', options: { handler: response, validate: { query: requestScheme }, response: { sample: 50, schema: responseScheme } } };
Como tal, apenas 50% dos pedidos serão respostas validadas.
É muito importante descrever os valores e exemplos padrão, no futuro eles serão usados para gerar documentação e autoteste.
Swagger / OpenAPI
Precisamos de vários módulos adicionais:
npm i hapi-swagger @hapi/inert @hapi/vision
Nós os conectamos ao 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 }, ... ]); ... });
E em cada rota você precisa colocar a tag "api":
module.exports = { method: 'GET', path: '/auth', options: { handler: response, tags: [ 'api' ],
Agora, em http: // localhost: 3030 / documentation, uma face da Web com a documentação estará disponível, e em http: // localhost: 3030 / documentation.json .json uma descrição.

Geração de Teste Automático
Se descrevemos qualitativamente os esquemas de solicitação e resposta, preparamos um banco de dados semente correspondente aos exemplos descritos nos exemplos de solicitação, então, de acordo com esquemas conhecidos, é possível gerar automaticamente solicitações e verificar os códigos de resposta do servidor.
Por exemplo, nos parâmetros GET: / auth login e password são esperados, vamos tirá-los dos exemplos que especificamos no diagrama:
const requestScheme =Joi.object({ login: Joi.string().email().required().example('pupkin@gmail.com'), password: Joi.string().required().example('12345') });
E se o servidor responder com HTTP-200-OK, assumiremos que o teste foi aprovado.
Infelizmente, não havia um módulo adequado pronto; você precisa falar um pouco:
Não se esqueça das dependências:
npm i request-promise mocha sync-request
E sobre o package.json
... "scripts": { "test": "mocha", "dbinit": "node ./scripts/dbInit.js" }, ...
Verificamos:
npm test

E se o bloqueio for algum tipo de esquema de dados ou a resposta não corresponder ao esquema:

E não esqueça que mais cedo ou mais tarde os testes se tornarão sensíveis aos dados no banco de dados. Antes de executar os testes, você precisa pelo menos limpar o banco de dados.
Fontes inteiras