I use nestjs to build a REST API.
I have a middleware which loads data from redis cache and should save it in the request object to access it in the controller function.
If i use express as engine it works, but with fastify it doesn't work. The data is undefined in the controller function.
The code looks like:
function mymiddleware(req, res, next) => {
req.data = {...};
next();
};
this is a simple working example:
const fastify = require('fastify')({ logger: true })
fastify.use(function (req, res, next) {
console.log('middy')
req.data = { hello: 'world' }
next();
})
fastify.get('/', (req, res) => {
res.send(`hello ${req.raw.data.hello}`)
})
fastify.listen(3000)
I think that your problem is due to the req object: in middleware (registered using .use you will get the standard Node.js request, instead of augmented HTTPRequest in the fastify handler.
So, you can access the low-level Http request with .raw field.
Related
In Node Js, on the entry file e.g. index.js, How can I get requested data either as Form-data or Form-URL-encoded or Raw JSON data in middleware?
In my project, I am handling various API request,
Few requests contain file type so requesting as form-data.
Few requests do not contain file type so requests are coming as Form-URL-encoded.
Now the main problem is before routing, I need a specific field from req.body in the middleware.
But I am getting req.body as undefined.
For reference here is my index.js file:
const express = require('express');
const app = express();
app.use(express.raw());
app.use(express.urlencoded({ extended: false }));
app.use((req, res, next) => {
const routes_handler = require('./routes/index.js')(app, express, req);
next();
})
app.listen(3000, () => {
console.log("Server running at Port " + 3000);
});
and the routes/index.js file as follows:
module.exports = function (app, express, req) {
console.log(req.body);
//I need here data of req.body for all requests type (form data, URL-encoded, raw JSON)
app.post('/', function (req, res) {
console.log("Here I can get the requested body easily", req.body)
res.send('Hello World');
});
app.post('*', function (req, res) {
res.send({
code: 0,
message: 'No Content',
status_code: 204,
data: {
error: 'API not found!'
}
});
});
}
Also, I know for file type data, POSTMAN will send the request as Form-data, not as Form-url-encoded. So which I should choose Formidable or Multer?
The way you get all the data in index.js is by creating middlewares for your application, every time any routes that go into your application will be passed through this middleware.
Middleware functions are functions that have access to the request object (req), the response object (res), and the next function in the application’s request-response cycle. The next function is a function in the Express router which, when invoked, executes the middleware succeeding the current middleware.
The below middleware will simply listen to all routes & adds up request time to request time, here goes the code
let express = require('express')
let app = express()
let bodyParser = require("body-parser")
app.use(bodyParser.json())
let requestTime = function (req, res, next) { // simply updating add the requestBody using the middleware
req.requestTime = Date.now();
req.json_body = req.body;
next()
}
app.use(requestTime) // requestTime is the middleware here
app.get('/', function (req, res) {
var responseText = 'Hello World!<br>'
responseText += '<small>Requested at: ' + req.requestTime + '</small>'
res.send(responseText)
})
app.listen(3000)
Few things to note here
Always add interceptor above all routes
Don't forget to add next() inside the middleware, else it will not go to the next route.
Now, coming to the second part of your question which is accessing body,formdata, etc
You can use body-parser npm module to achieve that, something like this
Starting from Express 4, body-parser comes inbuilt with it, so you can try out something
app.use(express.json());
app.use(
bodyParser.urlencoded({
extended: false
})
);
Now, the last bit, you don't need Multer for formdata, but for file upload like multipart/form-data you will need this. Both are good in their own ways, I would go for Multer.
Hope this will help you :)
I believe the body-parser module is your answer.
https://www.npmjs.com/package/body-parser
Add the following line before the routes in your index.js after installing the body-parser package.
app.use(bodyParser.json())
I am trying to use passport.js to set up authorization in an api. I am having trouble checking if a user is already logged. In expressjs I would do something like:
router.get('/is_logged_in',
passport.authenticate('jwt', { session: false }),
function (req, res, err) {
...
}
that is, in expressjs you can add the middleware passport.authenticate(...),
Can this be done with restify?, for instance if I have the route:
server.get('/is_logged_in', (req, res, next) => {
...
});
Where do I put the middleware? (or is this supposed to be done differently?) I can not add it as a second parameter for what I understand.
I have an express sub app using http-errors module. When I pass new Forbidden() to the next() callback it disappears into the ether and doesn't callback. If I pass new Error() or { message: 'Forbidden' } it triggers the sub app error handler. Is this expected behaviour?
I've created my own Error objects and they all work. I see http-errors uses the inherits module, which works for me. Does the error handler check for anything on the error parameter?
I've used http-errors for years and not noticed this problem before.
const { Forbidden } = require('http-errors')
const express = require('express')
const app = express()
const subapp = express()
subapp.get((req, res, next) => {
next(new Forbidden()) // doesn't work
next(new Error()) // works
next({ message: 'Forbidden' }) // works
})
subapp.use((err, req, res, next) => {
// only called if new Error() or { message: 'Forbidden' }
})
app.use('/somepath', subapp)
app.use((err, req, res, next) => {
// not called
})
Edit:
I omitted that I was using swagger in the question above. Swagger was catching the error but not handling it appropriately; it was setting the correct headers but not sending a complete response. It was therefore missing my error middleware and passing on to the next non-error middleware.
// return response for http-errors error
subapp.use((req, res, next) => {
if (res.headersSent) {
return res.end()
}
next()
})
To answer the direct question, not it doesn't. We can test this with a simpler case shown in this code (tested).
const app = require('express')();
app.get('/test', (req, res, next) => {
const nonErrObj = {
hello: 'world'
};
return next(nonErrObj);
});
app.use((err, req, res, next) => {
console.log('Got an error');
console.table(err);
res.sendStatus(500);
});
app.listen(3000, () => {
console.log('listening on 3000');
});
By then running curl localhost:3000/test in another terminal we get the output:
listening on 3000
Got an error
┌─────────┬─────────┐
│ (index) │ Values │
├─────────┼─────────┤
│ hello │ 'world' │
└─────────┴─────────┘
This console.table is being output by our error handler, and the object we're passing to next is just a standard JS object. So the object passed to "next" can be anything and it will trigger the error handling code.
Now lets try and solve your issue. I have a hunch it's to do with your nested application which is good use of express but can get a bit confusing sometimes. I've created another test app using your code which shows the following. This code has only one global error handler.
const express = require('express');
const app = express();
const subapp = express();
// Create a top level route to test
app.get('/test', (req, res, next) => {
const nonErrObj = {
hello: 'world'
};
return next(nonErrObj);
});
// Create a sub express app to test
subapp.use('/test2', (req, res, next) => {
const nonErrObj = {
hello: 'world'
};
return next(nonErrObj);
});
// Mount the app, so we can now hit /subapp/test2
app.use('/subapp', subapp);
// A single global error handler for now
app.use((err, req, res, next) => {
console.log('Got an error');
console.table(err);
res.sendStatus(500);
});
app.listen(3000, () => {
console.log('listening on 3000');
});
If we now curl localhost:3000/subapp/test2 and curl localhost:3000/test we get the same response. Our global error handler is called with no problems. Now lets try adding an error handler to the sub app to see what happens.
In this case I just added the following under the /test2 route (not adding the full file for brevity.
subapp.use((err, req, res, next) => {
console.log('Sub app got error');
console.table(err);
res.sendStatus(500);
});
In this instance by doing the same thing, we can see that a request to localhost:3000/subapp/test2 only calls the the sub app error handler. This shows that the errors are being handled properly.
From the above we can see that there aren't any issues with random JS objects being passed through (you can dig through the Express Router code and see this as well). The only reason I can see that the http-errors wouldn't be working properly would be if they are causing a conflict with the error handling code.
Looking at the express router code we can see that it's picking up a few properties from the error object and acting based on that. I would check that your http-errors Forbidden error object isn't accidentally conflicting with one of these use cases. If that's the case, then I'd suggest finding a different error library.
I'm assuming you're also using the npm http-errors library. If that's the case, it looks like you should be providing a message on error creation. You could be getting yourself into a situation where your program is hanging or erroring in some other way because you're not providing a message.
I am using express and pug, there are some values that I would like to pass to pug on every request, for example: req.session and req.path. Passing these values to the render() method every time just seems too redundant.
So instead of doing something like this:
app.get('/', (req, res) => {
res.render('home', {session: req.session})
})
app.get('/profile', (req, res) => {
res.render('profile', {session: req.session})
})
The more routes that get added, the more of those items I need to manage. Is there a global way that I can set them once other than app.locals so they are unique per request?
You can set variables that are available to every template on each request using a bit of custom middleware and locals. This same approach works for all templating systems that Express can use, not just Pug.
Put the following before your routes.
app.use((req, res, next) => {
res.locals.session = req.session
next()
})
Then in your template you can call it like this.
h3= session.name
I want to pass the environment for Express to a routing module for Express. I want to key off of whether Express is running in development or production mode. To do so, I'm guessing I need to pass app.settings.env somehow to a routing module.
My routing module exports a function for each route. So:
app.get('/search', web.search);
Based upon a previous stackoverflow post, i have tried this:
var web = require('./web')({'mode': app.settings.env});
But node throws an type error (object is not a function).
I'm new to Node and Express. Can I pass a value to an express route and if so, how?
If you web.js looks like this:
module.exports.search = function(req, res, next) {
// ...
};
module.exports.somethingOther = function(req, res, next) {
// ...
};
then by calling
var web = require('./web')({'mode': app.settings.env});
you try to use object (module.exports) as function. Type error here.
You need to convert module.exports to function to pass parameters to it. Like this:
module.exports = function (env) {
return {
// env available here
search: function(req, res, next) {
// ...
},
somethingOther: function(req, res, next) {
// ...
};
};
};