HAPI 17: Routes not registered - javascript

Hi I am migrating to Hapi 17 from 16. I have my routes defined in a different file which I am trying to register as a plugin. But I get a 404 when I call the API. The routes are not registered with the server.
This is my Server code.
'use strict'
const Hapi = require('hapi')
const server = new Hapi.Server({ port: 1234, host: 'localhost' });
const plugins = [{
plugin: require('vision'),
plugin: require('./methods/exampleMethod'),
plugin: require('./routes/devices')
}]
async function registerPlugin(){
await server.register(plugins)
}
registerPlugin().then( () => {server.start()})
This is my routes file devices.js:
exports.plugin = {
register: (server, options) =>
{
server.routes = [{
method: 'GET',
path: '/v1/devices',
handler: async function (request, h) {
const val = server.methods.testMethod("ankur")
const response = h.response('hello world ankur')
response.type('text/plain')
return response
}
}]
},
name: 'devices'
}
Methods file
exports.plugin = {
register: (server, options) => {
server.method(
{
name: 'testMethod',
method: function (id) {
return new Promise(function (resolve, reject) {
return resolve("Test method called")
})
}
})
},
name: "exampleMethod"
I am following the release notes for Hapi 17 and trying to register the routes as a custom plugin. However, when I hit the Get v1/devices I get a 404.

Following code for your routes file will work:
exports.plugin = {
register: (server, options) => {
server.route(
{
method: "GET",
path: "/v1/devices",
handler: async function(request, h) {
//const val = server.methods.testMethod("ankur")
const response = h.response("hello world ankur");
response.type("text/plain");
return response;
}
}
);
},
name: "devices"
};
You should call server.route() function with your route object.
If you like to register more than one function through your routes plugin use something like this:
exports.plugin = {
register: (server, options) => {
const routes = [
{
method: "GET",
path: "/v1/devices",
handler: async function(request, h) {
const response = h.response("hello world");
response.type("text/plain");
return response;
}
},
{
method: "GET",
path: "/v1/another",
handler: async function(request, h) {
const response = h.response("hello another world");
response.type("text/plain");
return response;
}
}
];
server.route(routes);
},
name: "devices"
};
Edit:
Methods plugin
exports.plugin = {
register: (server, options) => {
server.method("testMethod", async function(id) {
return "Test method called";
});
},
name: "exampleMethod"
};
Call the method:
{
method: "GET",
path: "/v1/example",
handler: async function(request, h) {
const response = await request.server.methods.testMethod();
return response;
}
}

Related

TypeError: axios.post(...).then is not a function

I have following Node.js script.
const axios = require('axios');
const https = require('https');
const postRequest = (url, data) => {
gLogger.debug('postRequest started');
// try {
const headers = {
'Content-Type': 'application/json',
'Content-Length': JSON.stringify(data).length,
};
const load = {
headers,
httpsAgent: agent,
};
gLogger.debug(`postRequest load: ${JSON.stringify(load)}`);
const result = axios.post(url, data, load).then((response) => {
return result;
})
.catch((error) => {
return error;
});
};
And this is for unit test:
const axios = require('axios');
const personalRecords = {
data: { peopleDomain: { paom: { data: { persons: [], delta: 1, recordsFetched: 10 } } } },
};
const tockenData = {
data: {
access_token: 'access_token',
expires_in: 1000,
},
};
// jest.useFakeTimers();
jest.setTimeout(8000);
jest.mock('axios', () => ({
post: jest.fn().mockReturnValue(tockenData),
get: jest.fn().mockReturnValue(personalRecords),
defaults: jest.fn().mockReturnValue(),
}));
The problem when I am running unit test yarn test, I keep getting the following error:
TypeError: axios.post(...).then is not a function.
What is the problem and how to fix it?
This is because you mock post function to be a function that returns a value instead of a promise. Remember post returns promise
This is the line that causes trouble:
post: jest.fn().mockReturnValue(tockenData),
To mock axios, there is an answer here:
How do I test axios in Jest?

Error: Missing helper: "handlebars": Missing helper: "handlebars"

I trying to serve dynamic file using Hapi framework, but I got error like this => Error: Missing helper: "handlebars": Missing helper: "handlebars"
Tutorial that I watched : https://www.youtube.com/watch?v=NTrro_tLzu4&list=PLkqiWyX-_LotaQ9AuppIAXl0xyV-P5Ms-&index=6
Here's my code:
📁server.js
/* eslint-disable linebreak-style */
/* eslint-disable max-len */
'use strict';
const Hapi = require('#hapi/hapi');
const Inert = require('#hapi/inert');
const Vision = require('#hapi/vision');
const Handlebars = require('handlebars');
const path = require('path');
const routes = require('./routes');
const init = async () => {
// BUILD SERVER
// eslint-disable-next-line new-cap
const server = Hapi.Server({
host: 'localhost',
port: 1234,
routes: {
files: {
relativeTo: path.join(__dirname, 'static'),
},
},
});
// PLUGIN CONFIGURATION
// Add Hapi Plugin - Only Hapi Plugin Can Be Registered and Don't Forget
// To Install The Plugin First
// 'plugin' key is must
await server.register([
{
plugin: require('hapi-geo-locate'),
options: {
// to able track the user ip
enabledByDefault: true,
},
},
{
plugin: Inert,
},
{
plugin: Vision,
},
]);
// MAKE HANDLEBARS AVAILABLE
server.views({
engines: {
html: Handlebars,
},
path: path.join(__dirname, 'views'),
});
// ROUTE
server.route(routes);
// SERVER CONFIGURATION
await server.start();
console.log(`Server started on: ${server.info.uri}`);
};
process.on('unhandleRejection', (err) => {
console.log(err);
process.exit(1);
});
init();
📁routes.js
/* eslint-disable linebreak-style */
/* eslint-disable max-len */
const {welcomePage,
servingDynmaicPage,
loginPage,
downloadPage,
locationPage,
usersPage,
gradePage,
unavailablePage} = require('./handler');
const routes = [
{
method: 'GET',
path: '/',
handler: welcomePage,
// options: {
// files: {
// relativeTo: path.join(__dirname, 'static'),
// },
// },
},
{
method: 'GET',
path: '/dynamicPage',
handler: servingDynmaicPage,
},
{
method: 'POST',
path: '/loginPage',
handler: loginPage,
},
{
method: 'GET',
path: '/downloads',
handler: downloadPage,
},
{
method: 'GET',
path: '/locationPage',
handler: locationPage,
},
{
method: 'GET',
path: '/users/{name?}',
handler: usersPage,
},
{
method: 'GET',
path: '/School',
handler: gradePage,
},
{
method: 'GET',
path: '/{any*}',
handler: unavailablePage,
},
];
module.exports = routes;
📁handler.js
/* eslint-disable linebreak-style */
/* eslint-disable max-len */
const welcomePage = (request, h) => {
return h.file('welcome.html');
};
const servingDynmaicPage = (request, h) => {
const data = {
name: 'Adit',
};
return h.view('index', data);
};
const loginPage = (request, h) => {
if (request.payload.username === 'Adit' && request.payload.password === '123') {
return h.file('login.html');
} else {
return h.redirect('/');
}
};
const downloadPage = (request, h) => {
return h.file('welcome.html', {
mode: 'attachment',
filename: 'welcome-download.html',
});
};
const locationPage = (request, h) => {
if (request.location) {
return request.location.ip;
} else {
return '<h1>Your Location is not enabled by default!</h1>';
}
};
const usersPage = (request, h) => {
if (request.params.name) {
return `<h1>Hello! ${request.params.name}</h1>`;
} else {
return `<h1>Hello! Stranger</h1>`;
}
};
const gradePage = (request, h) => {
return `<h1>Welcome to grade ${request.query.grade}</h1>`;
};
const unavailablePage = (request, h) => {
return h.redirect('/');
};
module.exports = {welcomePage,
servingDynmaicPage,
loginPage,
downloadPage,
locationPage,
usersPage,
gradePage,
unavailablePage};

How to use authenticated proxies with undici

Hello so am trying to use undici with a proxy but it doesn't work i tired this
const client = new Client({
url: 'www.google.com',
proxy: 'http://user:pass#host:port'
})
as well as this
const { HttpsProxyAgent } = require("https-proxy-agent");
const proxy = new HttpsProxyAgent("http://user:pass#host:port");
time = new Date()
client.request({
path: '/',
method: 'GET',
httpsAgent: proxy
},
but nothing seems to work
See this link here:
https://github.com/nodejs/undici/blob/01302e6d2b2629cca4ad9327abe0f7a317f8399f/docs/best-practices/proxy.md#connect-with-authentication
import { Client } from 'undici'
import { createServer } from 'http'
import proxy from 'proxy'
const server = await buildServer()
const proxy = await buildProxy()
const serverUrl = `http://localhost:${server.address().port}`
const proxyUrl = `http://localhost:${proxy.address().port}`
proxy.authenticate = function (req, fn) {
fn(null, req.headers['proxy-authorization'] === `Basic ${Buffer.from('user:pass').toString('base64')}`)
}
server.on('request', (req, res) => {
console.log(req.url) // '/hello?foo=bar'
res.setHeader('content-type', 'application/json')
res.end(JSON.stringify({ hello: 'world' }))
})
const client = new Client(proxyUrl)
const response = await client.request({
method: 'GET',
path: serverUrl + '/hello?foo=bar',
headers: {
'proxy-authorization': `Basic ${Buffer.from('user:pass').toString('base64')}`
}
})
response.body.setEncoding('utf8')
let data = ''
for await (const chunk of response.body) {
data += chunk
}
console.log(response.statusCode) // 200
console.log(JSON.parse(data)) // { hello: 'world' }
server.close()
proxy.close()
client.close()
function buildServer () {
return new Promise((resolve, reject) => {
const server = createServer()
server.listen(0, () => resolve(server))
})
}
function buildProxy () {
return new Promise((resolve, reject) => {
const server = proxy(createServer())
server.listen(0, () => resolve(server))
})
}

How to mock nested function in Jest?

I am getting this error
Cannot find module 'httpsGet' from 'functions/getSecureString.test.js'
httpsGet() is my own function, and is at the button of getSecureString.js, and called by getSecureString(). httpsGet() uses the https module to get content from a website that requires client side certificates.
Question
I am trying to mock httpsGet() and I am guessing the problem I have is because it isn't included with require() and hence jest.mock('httpsGet') fails.
Can anyone figure out if that is the case, and how I should fix it?
Live example at: https://repl.it/#SandraSchlichti/jest-playground-4
getSecureString.test.js
const getStatusCode = require('./getSectureString');
jest.mock('httpsGet');
describe("getSecureString ", () => {
describe('when httpsGet returns expected statusCode and body includes expected string', () => {
let result;
beforeAll(async () => {
httpsGet.mockResolvedValue({
statusCode: 200,
body: 'xyz secret_string xyz'
})
result = await getSecureString({
hostname: 'encrypted.google.com',
path: '/',
string: 'secret_string',
statusCode: 200,
aftaleId: 1234,
certFile: 1234,
keyFile: 1234,
timeout: 1000,
})
});
it('should return 1', () => {
expect(result).toEqual(1)
})
});
describe('when httpsGet returns expected statusCode and body includes expected string', () => {
let result;
beforeAll(async () => {
httpsGet.mockResolvedValue({
statusCode: 200,
body: 'xyz secret_string xyz'
})
result = await getSecureString({
hostname: 'encrypted.google.com',
path: '/',
string: 'not_secret_string',
statusCode: 201,
aftaleId: 1234,
certFile: 1234,
keyFile: 1234,
timeout: 1000,
})
});
it('should return 0', () => {
expect(result).toEqual(0)
})
});
describe("when an exception is thrown", () => {
let result;
beforeAll(async () => {
// mockRejected value returns rejected promise
// which will be handled by the try/catch
httpsGet.mockRejectedValue({
statusCode: 200,
body: 'xyz secret_string xyz'
})
result = await getSecureString();
})
it('should return -1', () => {
expect(result).toEqual(-1)
})
});
});
getSecureString.js
const fs = require('fs');
const https = require('https');
var uuid = require('uuid');
const {v4: uuidv4} = require('uuid');
module.exports = async function getSecureString(options) {
options = options || {};
options.hostname = options.hostname || {};
options.path = options.path || '/';
options.string = options.string || {};
options.statusCode = options.statusCode || {};
options.aftaleId = options.aftaleId || {};
options.certFile = options.certFile || {};
options.keyFile = options.keyFile || {};
options.timeout = options.timeout || 0;
const opt = {
hostname: options.hostname,
port: 443,
path: options.path,
method: 'GET',
cert: fs.readFileSync(options.certFile),
key: fs.readFileSync(options.keyFile),
headers: {'AID': options.aftaleId
},
};
opt.agent = new https.Agent(opt);
try {
const r = await httpsGet(opt, options.timeout);
return (r.statusCode === options.statusCode && r.body.includes(options.string)) ? 1 : 0;
} catch (error) {
console.error(error);
}
};
function httpsGet(opts, timeout) {
return new Promise((resolve, reject) => {
const req = https.get(opts, (res) => {
let body = '';
res.on('data', (data) => {
body += data.toString();
});
res.on('end', () => {
resolve({body, statusCode: res.statusCode});
});
});
req.setTimeout(timeout, function() {
req.destroy('error');
});
req.on('error', (e) => {
console.error(e);
reject(e);
});
});
};
A function that is used in the same module it was declared cannot be spied mocked, unless it's consistently as a method of some object, which is cumbersome and incompatible with ES modules:
module.exports.httpsGet = ...
...
module.exports.httpsGet(...);
Otherwise a function should be moved to another module that can mocked, or should be tested as is. In this case underlying API (https.get) can be mocked instead.

In azure functions (js) POST request after async/await call does not work

I am currently working with azure functions in javascript. In my function, I am first getting a specific element from my CosmoDB (this is the async/await part). I get a result and then I want to do an https POST request. However, my problem is, that it never finished the HTTPs request and I don't really know why. What am I doing wrong?
(As you can see I tried 2 different ways of doing the request, once with the standard https function and the commented out the part with npm request package. However, both ways won't work).
Here is my code:
const CosmosClient = require('#azure/cosmos').CosmosClient;
var https = require('https');
var http = require('http');
var request = require('request');
const endpoint = "someEndpoint";
const masterKey = "anymasterkey";
const database = {
"id": "Database"
};
const container = {
"id": "Container1"
};
const databaseId = database.id;
const containerId = container.id;
const client = new CosmosClient({
endpoint: endpoint,
auth: {
masterKey: masterKey
}
});
module.exports = function (context, req) {
const country = "de";
const bban = 12345678;
const querySpec = {
query: "SELECT * FROM Container1 f WHERE f.country = #country AND f.bban = #bban",
parameters: [{
name: "#country",
value: country
},
{
name: "#bban",
value: bban
}
]
};
getContainers(querySpec).then((results) => {
const result = results[0];
context.log('here before request');
var options = {
host: 'example.com',
port: '80',
path: '/test',
method: 'POST'
};
// Set up the request
var req = http.request(options, (res) => {
var body = "";
context.log('request');
res.on("data", (chunk) => {
body += chunk;
});
res.on("end", () => {
context.res = body;
context.done();
});
}).on("error", (error) => {
context.log('error');
context.res = {
status: 500,
body: error
};
context.done();
});
req.end();
// request({
// baseUrl: 'someURL',
// port: 443,
// uri: 'someuri',
// method: 'POST',
// headers: {
// 'Content-Type': 'text/xml;charset=UTF-8',
// 'SOAPAction': 'someaction'
// },
// function (error, response, body) {
// context.log('inside request')
// if (error) {
// context.log('error', error);
// } else {
// context.log('response');
// }
// }
// })
})
};
async function getContainers(querySpec) {
const {container, database} = await init();
return new Promise(async (resolve, reject) => {
const {
result: results
} = await container.items.query(querySpec).toArray();
resolve(results);
})
}
async function init() {
const {
database
} = await client.databases.createIfNotExists({
id: databaseId
});
const {
container
} = await database.containers.createIfNotExists({
id: containerId
});
return {
database,
container
};
}
The last thing that happens is the print of "here before request". After that the function just does nothing until it timesout. So what am I doing wrong? Can't I just this combination of await/async and requests?
As commented you are not sending any data to the POST call. You need to have a req.write before the req.end
req.write(data);
req.end();
That is why the POST call is failing for you. After this fix, it should work

Categories