Express: express-unless breaking with simple example - node.js

https://github.com/jfromaniello/express-unless
Two questions..
Any idea why this does not work?
It appears this library is abandoned. Are there any other alternatives?
handleExpiredTokens.unless({
path: [{
url: '/foo',
methods: ['POST']
}]
});
function handleExpiredTokens(err, req, res, next) {
// stuff
}
handleExpiredTokens.unless = unless;
module.exports = handleExpiredTokens;
handleExpiredTokens runs on every request including POST /foo
getting a protectWithCSRF.unless is not a function

Related

node js express - middleware next() is not triggering consecutive fm in mocha test cases

I have configured a middleware (router level) which checks for admin access, and if successful I am logging the information and calling next().
middleware:
const validateAdmin = function (scope) {
return function (req, res, next) {
if (req.admin) {
//log the information and using scope to log
next();
} else {
// send the response with 403
}
};
};
router level usage
router.use('/rule/:name', validateAdmin({ serviceScope: this.#serviceScope }), async (req, res) => {
await this._handleRequest(req, res);
});
working case
when i trigger the req from postman, i can see that middleware is called and after next getting executed, the control is coming to 'await this._handleRequest(req, res);' which is expected.
issue
Test case
it.only('shall get single rule', async function () {
const getSingleReq = {
method: 'GET',
admin: true,
originalUrl: '<some req>/rule/rule_1',
baseUrl: '<some_req>',
query: {},
params: { name: 'rule_1' },
headers: {
//token info
},
body: {}
};
const next = sinon.spy();
await router.use.args[1][1](getSingleReq, res, next);
}));
when await router.use.args[1][1](getSingleReq, res, next); is called, I can see the middleware is triggered but next() is not calling the subsequent middleware. I expect that await this._handleRequest(req, res); is called just like the scenario when triggered from postman.
I hope the issue is clear.
Referred many use cases but everywhere the scenario of just checking if next() is called is only done .

Loopback timeout(no response from server) when make a time consume request

I have a request which processes thousands of data. So sometimes It takes more then 5 minutes to complete.
But unfortunately loopback returns timeout(no response from server) before process is completed.
In nodejs request. You can remove request timeout for specific request by below code.
request.setTimeout(0)
Can anyone tell me how can i do this for loopback remote method?
It was quite easy then it looked like.
All i had to do is pass http req object in my remote method and then set timeout to 0.
Visit.remoteMethod(
'caculateDistance',
{
description: 'Calculate distance from beacon using rssi',
accepts: [
{ arg: "req", type: "object", http: { source: "req" } },
{ arg: 'activationId', type: 'string', required: true }
returns: { arg: 'data', type: 'Object', root: true },
http: { verb: 'patch', path: '/:activationId/calculate-distance' },
}
);
Visit.caculateDistance = function (httpReq, activationId, callbackFn) {
httpReq.setTimeout(0);
/////calculations....
});
Thanks anyway!
I am not quite sure of this but you can give it a try as i feel this might work
You can create a interceptor for that particular route or all the routes in the server.js file.
app.all('/api/*', function(req, res, next){
request.setTimeout(0); // this is the statement and pass it to the next middle ware func.
next();
});
If not you can also use a remote method for that route and add the
same there.
Update
If you want it for a single api just use
app.all('<exact api path>', function(req, res, next){
request.setTimeout(0); // this is the statement and pass it to the next middle ware func.
next();
});

Set current request route in vue-router for SRR in server-side with Node.js

Introduction
I have this Node.js code from a function that handle the request/response. To explain my problem, I will use Express.js example. That piece of code is not a part of my problem but I can include to you a simple context to help you answer my question. So my code will be put in app.get handler, assuming app is an Express.js instance :
app.get("/", function (request, response, next) {
// The code below could be here...
});
app.get("/test/", function (request, response, next) {
// ...and here...
});
app.get("/*", function (request, response, next) {
// ...and here...
});
response is the representation of response I will send to the client and I will fill it with the Vue Renderer result.
request contains all information about the client that execute this part of code.
My code
Assuming my code is running from the / route, the code is for example the following :
app.get("/", function (request, response, next) {
var Vue = require("vue"),
VueRouter = require("vue-router"),
renderers = require("vue-server-renderer"),
renderer = renderers.createRenderer();
global.Vue = Vue;
Vue.use(VueRouter);
stream = renderer.renderToStream(new Vue({
template: "<div><router-view></router-view><div>",
router: new VueRouter({
routes: [{
path: '/',
component: { template: '<div>foo</div>' }
}, {
path: '/test/',
component: { template: '<div>bar</div>' }
}, {
path: '/*',
component: { template: '<div>baz</div>' }
}]
})
}));
response.write("<html><head><title>test</title></head><body>");
stream.on('data', function (chunk) {
response.write(chunk);
});
stream.on('end', function () {
response.end('</body></html>');
});
});
And when response.end is called, the content send to the client is
<html><head><title>test</title></head><body><div server-rendered="true"><!----></div></body></html>
We can see the part where the router should be display the component is <!----> so I guess it's because for router, no route actually match my code.
Questions
Why the result is not the following if no route matchs :
<html><head><title>test</title></head><body><div server-rendered="true"><div>baz</div></div></body></html>
and
How to inform my router the current url is / to generate this code in this case :
<html><head><title>test</title></head><body><div server-rendered="true"><div>foo</div></div></body></html>
and for exemple the following code if my current request come from /test/
<html><head><title>test</title></head><body><div server-rendered="true"><div>bar</div></div></body></html>
etc.
Answer
Thanks to the answer of Ilya Borovitinov (https://stackoverflow.com/a/42872542/2412797), my previous code become :
app.get("/", function (request, response, next) {
var Vue = require("vue"),
VueRouter = require("vue-router"),
renderers = require("vue-server-renderer"),
renderer = renderers.createRenderer(),
router = new VueRouter({
routes: [{
path: '/',
component: { template: '<div>foo</div>' }
}, {
path: '/test/',
component: { template: '<div>bar</div>' }
}, {
path: '/*',
component: { template: '<div>baz</div>' }
}]
});
global.Vue = Vue;
Vue.use(VueRouter);
stream = renderer.renderToStream(new Vue({
template: "<div><router-view></router-view><div>",
router: router
}));
/* THIS IS THE SOLUTION */
router.push(request.url);
response.write("<html><head><title>test</title></head><body>");
stream.on('data', function (chunk) {
response.write(chunk);
});
stream.on('end', function () {
response.end('</body></html>');
});
});
You are trying to use vue-router in an environment, which does not provide explicit address for the router to use. To actually force router to render proper path, you need to call router.push(currentUrl) for it to register.

how to generate a sitemap in expressjs

I downloaded my XML sitemap from the sitemap xml generator website. I placed my sitemap.xml on my public directory but when I tried to submit the sitemap.xml into google console i received the following error: General HTTP error: 404 not found
HTTP Error: 404So i codedapp.get('/sitemap.xml', function( req, res, next ) {
res.header('Content-Type', 'text/xml');
res.render( 'sitemap' );
)};And when i navigate to the 'website/sitemap.xml' I am getting the following error: This page contains the following errors:
error on line 1 at column 42: Specification mandate value for attribute itemscope
Thanks for your help
Generate your sitemap.xml file using a tool like https://www.xml-sitemaps.com/
upload the sitemap.xml in your project
then add this to your .js file:
router.get('/sitemap.xml', function(req, res) {
res.sendFile('YOUR_PATH/sitemap.xml');
});
make sure you change YOUR_PATH for the actual path where your sitemap.xml file is.
Sitemaps do not have to be XML documents. A simple text file with URLs is all you need so something like below works fine. In the following example, fetchMyUrls() would be a function/method that asynchronously gets and returns the available URLs as an array of strings (URL strings).
async function index (req, res){
return fetchMyUrls().then((urls) => {
var str = '';
for (var url of urls) {
str = str + url + '\n';
}
res.type('text/plain');
return res.send(str);
});
}
For those looking for a way to create the XML dynamically on your code and don't want to use another library nor have a file stored in the public folder, you can use this:
app.get('/sitemap.xml', async function(req, res, next){
let xml_content = [
'<?xml version="1.0" encoding="UTF-8"?>',
'<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">',
' <url>',
' <loc>http://www.example.com/</loc>',
' <lastmod>2005-01-01</lastmod>',
' </url>',
'</urlset>'
]
res.set('Content-Type', 'text/xml')
res.send(xml_content.join('\n'))
})
In my NodeJS express project and without installing any library I was able to add this to my routes with my preferred view engine (handlebar).
export const routes: RouteMapper[] = [
{
"/sitemap.xml": [
{
method: "get",
handler: (req, res) =>
res.sendFile("/src/views/sitemap.xml", { root: "." }),
},
],
},
];
Cheers!
The best way is to create a script that would automatically generate a sitemap. In a lot of cases, the URLs should be dynamic based on data from the database.
Great package for creating the sitemap in Express is sitemap package:
STEP 1
Create a middleware that will generate the sitemap dynamically and then cache it for each next call to the server. We can extract logic in separate file called sitemap_generator.js for example, and we can define and export generate_sitemap middleware for it:
const { SitemapStream, streamToPromise } = require('sitemap');
const { Readable } = require('stream');
let sitemap;
const generate_sitemap = async (req, res, next) => {
res.header('Content-Type', 'application/xml');
if (sitemap) return res.status(200).send(sitemap); // If we have a cached entry send it
let changefreq = 'weekly';
try {
let links = [
{ url: '', changefreq, priority: 1 },
{ url: 'aboutus', changefreq, priority: 0.9 },
{ url: 'blog', changefreq },
{ url: 'login', changefreq },
{ url: 'register', changefreq },
];
// Additionally, you can do database query and add more dynamic URLs to the "links" array.
const stream = new SitemapStream({ hostname: 'https://example.com', lastmodDateOnly: true })
return streamToPromise(Readable.from(links).pipe(stream)).then((data) => {
sitemap = data; // Cache the generated sitemap
stream.end();
return res.status(200).send(data.toString())
});
} catch (error) {
return res.status(500).end();
}
}
module.exports = { generate_sitemap };
STEP 2
Import generate_sitemap middleware from sitemap_generator.js in your server configuration file and mound it to the /sitemap.xml endpoint:
const { generate_sitemap } = require('./sitemap_generator');
...
app.get('/sitemap.xml', generate_sitemap);
That's it. Your sitemap should be available on /sitemap.xml endpoint now so navigate in the browser to that endpoint and check if it is there.

Efficient way to handle error cases in REST Apis

I am writing a REST API in node.js. I expect at max 5 parameters to arrive in my GET Request. If there are unidentified parameters I wish to send 400 Bad Request.
Currently I am handling it in the following way:
server.route({
method: "GET",
path : "/test",
handler : function (request, reply) {
if (request.query.a || request.query.b || request.query.c || request.query.d || request.query.e)
{
// do some processing
}
else {
reply("No valid parameters").code(400);
}
}
});
Right now this does not handle the case if there are some valid and some invalid cases. I can solve that by using more if conditions. But I was just wondering if there is a standard or more efficient method which is used by developers
Hapi has built-in validation support. You can use Joi to validate the query:
var Joi = require('joi');
...
server.route({
method: 'GET',
path: '/test',
config: {
validate: {
query: {
a: Joi.string(),
b: Joi.string(),
c: Joi.string(),
d: Joi.string(),
e: Joi.string()
}
}
},
handler: function (request, reply) {
return reply('ok');
}
});
If you send a request to /test?g=foo, then you get the following response:
{ statusCode: 400,
error: 'Bad Request',
message: '"g" is not allowed',
validation: { source: 'query', keys: [ 'g' ] } }
You can manually do this, but you are better off using a REST framework like mongoose or loopback (strongloop) to do the validation and error handling and other boilerplate code like model binding.
Perhaps you should consider the use of a framework, like Express, to use a middleware which is simply code you can reuse in different routes.
A simple pseudo/example looks like this
var app = express();
// a middleware with no mount path; gets executed for every request to the app
app.use(function (req, res, next) {
if (req.query.a && req.query.b) {
return next()
}
else {
return res.status(400).send('Not OK');
}
});
// a route and its handler function (middleware system) which handles GET requests to /user/:id
app.get('/user/:id', function (req, res, next) {
return res.send('OK');
});
// a different route, same middleware
app.get('/customer/:id', function (req, res, next) {
return res.send('OK');
});

Resources