Set params on request when testing hapi routes - node.js

I am currently writing some tests for our hapi routes. The route I want to test looks like that:
server.route(
{
method: 'POST',
path: '/',
options: {
tags: ['api'],
cors: true,
handler: async (req: Hapi.Request | any, h: Hapi.ResponseObject) => {
if (!req.params.userId) {
throw Boom.badRequest();
}
return 200;
}
}});
So my test looks like this:
it('should return 200', async () => {
const request : ServerInjectOptions = {
url: '/user',
method: 'POST',
payload: {
email: 'e#email.de',
password: 'secred',
firstname: 'John',
lastname: 'Doe'
},
app: {}
};
const response = await server.inject(request);
expect(response.statusCode).toEqual(200);
});
As you can see the route expects a param in the params array with the name userId but i am not able to set the parameter on the ServerInjectOptions object. The error I get is that the property does not exist on the ServerInjectOptions type.
Is there any other way i can set the params array? I didn`t find something in the docs maybe i missed it and someone can tell me where to find it.
Thanks in advance

For the route I believe you add the name of the parameter to the path like so:
server.route(
{
method: 'POST',
path: '/:userId',
//
}});
And for the test you should be able to add your parameter to the url option:
const request : ServerInjectOptions = {
url: '/user/parameterYouNeedToAdd',
//
};
Or if the parameter is a variable:
const request : ServerInjectOptions = {
url: '/user/' + parameterYouNeedToAdd,
//
};

Related

Hapjs Route Prerequisite is executed and route is always returning 404

I am building a web application using Hapijs. I am using route prerequisites to do something before the route handler is executed.
This is my route
server.route([
{
method: 'GET',
path: '/users',
pre: {
assign: 'Test',
method: async (request, h) => {
console.log('Pre route is executed.');
return "test data";
}
},
handler: userController.getUsers,
options: {
auth: 'jwt-auth'
}
},
])
But when I execute the code, it is not executing the pre route method. When the pre route handler is included, it is always returning 404 not found response. Without it, it is working. What is wrong with my code and how can I fix it?
According to the "pre documentation", "pre" should be placed inside of the "options" property and should be an array
Here is an example how what it should look like for your code:
server.route([
{
method: 'GET',
path: '/users',
handler: userController.getUsers,
options: {
auth: 'jwt-auth',
pre: [{
assign: 'Test',
method: async (request, h) => {
console.log('Pre route is executed.');
return "test data";
}
}]
}
},
])
You can get access to your "pre" data in the handler like this: const data = req.pre.Test

Parsing Slack Interactive Message POST payload parameter to JSON in Azure Functions

I'm trying to create an Azure Function to take POST requests from Slack Message Interactions. I'm able to get a test request to come in following this guide using ngrok. However the payload is not coming in like a normal POST request body. Assuming this is because it's a "parameter" payload and not a body.
module.exports = async (context, req) => {
const { body } = req;
context.log(body);
context.res = {
body,
};
};
Output:
payload=%7B%22type%22%3A%22block_actions%22%2C%22user%22%3A%7B%22id%22%3A%22xxx%22%2C%22username%22%3A%22...
How do I parse this POST parameter payload into JSON in an Azure Function?
With help from this post I was able to figure this out for my use case.
Using qs package npm i qs
const { parse } = require('qs');
module.exports = async (context, req) => {
const payload = JSON.parse(parse(req.rawBody).payload);
context.log(payload);
context.res = {
payload,
};
};
Output:
{
type: 'block_actions',
user: {
id: 'xxx',
username: 'xxx',
name: 'xxx',
team_id: 'xxx'
},
api_app_id: 'xx',
...
}

How to parse querystring parameter from URL in Fastify server?

I am a totally new to fastify but I have a fastify server running. I want to parse query string such as:
http://fake.com/?user=123&name=ali
I want to get "user" and "name" values from the URL above. My current code is like this:
fastify.route({
method: 'GET',
url: '/',
handler: async (request, reply) => getCompanyUsers(request, reply, services)
});
I want to get values of "user" and "name" and then pass the values to getCompanyUsers function.
Any help is appreciated.
Thanks
You can access the querystring using request.query
You can look at the official documentation here
https://github.com/fastify/fastify/blob/main/docs/Reference/Request.md
fastify.route({
method: 'GET',
url: '/',
schema: {
// request needs to have a querystring with a `name` parameter
querystring: {
name: { type: 'string' }
}
},
handler: async (request, reply) => {
// here you will get request.query if your schema validate
}
})

Swagger-hapi: path /models generate errors

The following NodeJS Hapi code generate an error when querying at http://localhost:3000/documentation
If I change the path of the endpoint to something else than /models, like /users for instance, everything works well. It looks like the endpoint /models is reserved.
Any idea why any other endpoint work except /models? How can I fix it? I can't change the URL as too many people use it.
var Hapi = require('hapi'),
Inert = require('inert'),
Vision = require('vision'),
Joi = require('joi'),
HapiSwagger = require('hapi-swagger')
var server = new Hapi.Server();
server.connection({
host: 'localhost',
port: 3000
});
var swaggerOptions = {
apiVersion: "1.0"
};
server.register([
Inert,
Vision,
{
register: HapiSwagger,
options: swaggerOptions
}], function (err) {
server.start(function(){
// Add any server.route() config here
console.log('Server running at:', server.info.uri);
});
});
server.route(
{
method: 'GET',
path: '/models',
config: {
handler: function (request, reply) {
reply("list of models")
},
description: 'Get todo',
notes: 'Returns a todo item by the id passed in the path',
tags: ['api'],
validate: {
params: {
username: Joi.number()
.required()
.description('the id for the todo item')
}
}
}
}
)
server.start(function(){
// Add any server.route() config here
console.log('Server running at:', server.info.uri);
});
Yes models is part of swagger's internal structure and it looks like there is an issue in the swagger.js file when dealing with endpoints that use models as part of the URL for an endpoint.
The easy fix for this is to use a nickname. This changes the internal ref in swagger, but the UI should still say models and it will fire against your endpoint correctly.
{
method: 'GET',
path: '/models/{username}',
config: {
handler: function (request, reply) {
reply("list of models")
},
description: 'Get todo',
notes: 'Returns a todo item by the id passed in the path',
tags: ['api'],
plugins: {
'hapi-swagger': {
nickname: 'modelsapi'
}
},
validate: {
params: {
username: Joi.number()
.required()
.description('the id for the todo item')
}
}
}
}

Can't call success function

I'm developing a Backbone Node.js with Express.js app. I'm trying to trigger a function after receiving a response from my server like the code bellow:
mainView.js
...
user: null,
initialize: function () {
_.bindAll(this, 'registerSuccess', 'loginSuccess');
this.user = new userModel();
}
registerSuccess: function () {
this.user.auth({
success: this.loginSuccess
});
});
loginSuccess: function () {
console.log('loginSuccess');
}
userModel.js
...
, auth: function (options) {
$.ajax({
url: 'users/auth'
, type: 'post'
}, options);
})
app.js
var api = require('./routes/apiController');
app.post('/users/auth', api.userAuth);
apiController.js
exports.userAuth = function (req, res) {
return res.send( {
status: 200
});
}
I´m getting the response:
But it doesn't print the console.log('loginSuccess') sentence from this function.
There are two ways to call $.ajax:
jQuery.ajax(url, settings)
jQuery.ajax(settings)
In the first case, url must be a string and settings is an optional object; in the second case, settings is again an optional object. You're calling $.ajax with two objects:
auth: function (options) {
$.ajax({
url: 'users/auth'
, type: 'post'
}, options);
}
Since the first argument is not a string, $.ajax will use the second calling form and ignore options completely. You probably want to use _.extend to merge the arguments:
$.ajax(_({
url: 'users/auth'
, type: 'post'
}).extend(options));
Or _.defaults if you want to avoid accidentally overwriting url and type:
$.ajax(_({
url: 'users/auth'
, type: 'post'
}).defaults(options));
Or, since you only have two things, just stuff them in manually:
options = _(options).clone(); // Avoid accidentally messing with the argument.
options.url = 'users/auth';
options.type = 'post';
$.ajax(options);

Resources