I've got an Azure node.js app. I wanted to add 'multer' middleware, for dealing with file uploads, to only one POST easy-api.
For example, I have the file ./api/upload-files.js, which is supposed to look something like this:
module.exports = {
"post" : async (req, res, next) => {
// ...
}
};
And I can quite easily add the multer middleware to the ./app.js file, where the express app is initialized:
const multer = require('multer');
app.post('*', multer({ storage: multer.memoryStorage() }).any());
But if I don't want to add multer middleware to every post endpoint, but just to the one in ./api/upload-files.js, how do I do that?
Original comment
This is something related with the way you are instanciating the express instance in your app.
If you do not wish to use the multer middleware for some request you can just use the function you want in the request itself, avoiding to call the multer function when passing the arguments to the request method.
One example for a get endpoint:
app.get('/getrequest', (req, res, next) => {
console.log('Someone made a get request to your app');
})
One example for a post endpoint:
app.post('/postrequest', (req, res, next) => {
console.log('Someone made a POST request to your app');
})
Keep in mind that you add or remove middleware functions in express this way.
app.use('/user/:id', function (req, res, next) {
console.log('I am a middleware!')
next()
}, function (req, res, next) {
console.log('I am another function')
next()
})
Here are the docs
Edit
Could maybe this code adapt to your usecase?
app.post('*', checkUseMulter);
function checkUseMulter(req, res, next) {
if (['/mypathwithoutmulter', '/myotherpath'].includes(req.path)) {
return next();
}
return multer({ storage: multer.memoryStorage() }).any();
}
Related
Working on my backend in node.js and express, newly using multer to upload a file.
I want to check if my user has a valid token: If yes he can upload a file, if not, get a 401 back. With my following code, this works, but the file still gets uploaded, even if the user has no valid token.
I guess my check should happen before the parameter upload.single('image'), but I don't really know how. Any tips?
My code:
router.post("/", upload.single('image'), (req, res, next) => {
if (!req.isAuth) {
res.status(401).json({error: "Unauthenticated"});
} else {
console.log('file', req.file);
res.status(200).json({resultFileName: req.file.filename });
}
});
Create a middlewares or helper and create authorize.js file in it and add jwt auth code in it like below
authorize.js
const jwt = require('jsonwebtoken');
module.exports = {
jwtAuth: (req, res, next) => {
//Jwt verification code according to your configuration
}
}
And import that file in your route folder and use it like below
Users.js
const authorize = require('../middlewares/authorize')
router.post("/", authorize.jwtAuth, upload.single('image'), (req, res, next) => {
console.log('file', req.file);
res.status(200).json({resultFileName: req.file.filename });
});
You can try this but i haven't tested it and haven't used express in a while.
router.post("/", (req, res, next) => {
if (!req.isAuth)
return res.status(401).json({error: "Unauthenticated"});
next();
}, upload.single('image'), (req, res, next) => {
console.log('file', req.file);
res.status(200).json({resultFileName: req.file.filename });
});
what I want it to do.
router.post('/xxxx', authorize , xxxx);
function authorize(req, res, next)
{
if(xxx)
res.send(500);
else
next();
}
I want to check for session in each route.
But since the routers are written in this way.
router.route('/xxx/xxxx').post(function(req, res) {
// blah lah here...
//
});
So how can I set up a middleware that will check for session and I wanted to make things a bit more generic and wanted to have a single authorize function doing a single thing instead of checking in every request.Any suggestions.
Define a middlware function before you define / include your routes, this will avoid you checking for a valid session in every route. See code below for an example on how to do this.
If some routes are public, i.e. they do not require a user to have a valid session then define these BEFORE you 'use' your middlware function
var app = require("express")();
//This is the middleware function which will be called before any routes get hit which are defined after this point, i.e. in your index.js
app.use(function (req, res, next) {
var authorised = false;
//Here you would check for the user being authenticated
//Unsure how you're actually checking this, so some psuedo code below
if (authorised) {
//Stop the user progressing any further
return res.status(403).send("Unauthorised!");
}
else {
//Carry on with the request chain
next();
}
});
//Define/include your controllers
As per your comment, you have two choices with regards to having this middleware affect only some routes, see two examples below.
Option 1 - Declare your specific routes before the middleware.
app.post("/auth/signup", function (req, res, next) { ... });
app.post("/auth/forgotpassword", function (req, res, next) { ... });
//Any routes defined above this point will not have the middleware executed before they are hit.
app.use(function (req, res, next) {
//Check for session (See the middlware function above)
next();
});
//Any routes defined after this point will have the middlware executed before they get hit
//The middlware function will get hit before this is executed
app.get("/someauthorisedrouter", function (req, res, next) { ... });
Option 2 Define your middlware function somewhere and require it where needed
/middleware.js
module.exports = function (req, res, next) {
//Do your session checking...
next();
};
Now you can require it wherever you want it.
/index.js
var session_check = require("./middleware"),
router = require("express").Router();
//No need to include the middlware on this function
router.post("/signup", function (req, res, next) {...});
//The session middleware will be invoked before the route logic is executed..
router.get("/someprivatecontent", session_check, function (req, res, next) { ... });
module.exports = router;
Hope that gives you a general idea of how you can achieve this feature.
Express routers have a neat use() function that lets you define middleware for all routes. router.use('/xxxxx', authorize); router.post('/xxxx', 'xxxx'); should work.
Middleware:
sampleMiddleware.js
export const verifyUser = (req, res, next) => {
console.log('Verified')
next();
}
Routes
import express from 'express';
import { verifyUser } from './sampleMiddleware.js';
const userRoutes = express.Router();
userRoutes.route('/update').put(verifyUser, async function(){
//write your function heere
});
You've probably gotten the answer you need but I'll still drop this
router.route('/xxx/xxxx').get(authorize, function(req, res) {...});
I want to just verify something but have't been able to find anything in the Express docs or online regarding this (although I know it's a feature).
I could just test this out but I don't really have a nice template and would like to hear from the community.
If I define a route in express like such:
app.get('/', function (req, res) {
res.send('GET request to homepage');
});
I can also define a middleware and load it directly, such as
middleware = function(req, res){
res.send('GET request to homepage');
});
app.get('/', middleware)
However, I can also chain at least one of these routes to run extra middleware, such as authentication, as such:
app.get('/', middleware, function (req, res) {
res.send('GET request to homepage');
});
Are these infinitely chainable? Could I stick 10 middleware functions on a given route if I wanted to? I want to see the parameters that app.get can accept but like mentioned I can't find it in the docs.
Consider following example:
const middleware = {
requireAuthentication: function(req, res, next) {
console.log('private route list!');
next();
},
logger: function(req, res, next) {
console.log('Original request hit : '+req.originalUrl);
next();
}
}
Now you can add multiple middleware using the following code:
app.get('/', [middleware.requireAuthentication, middleware.logger], function(req, res) {
res.send('Hello!');
});
So, from the above piece of code, you can see that requireAuthentication and logger are two different middlewares added.
It's not saying "infinitely", but it does say that you can add multiple middleware functions (called "callbacks" in the documentation) here:
router.METHOD(path, [callback, ...] callback)
...
You can provide multiple callbacks, and all are treated equally, and behave just like middleware, except that these callbacks may invoke next('route') to bypass the remaining route callback(s). You can use this mechanism to perform pre-conditions on a route then pass control to subsequent routes when there is no reason to proceed with the route matched.
As you can see, there's not distinction between a middleware function and the function that commonly handles the request (the one which is usually the last function added to the list).
Having 10 shouldn't be a problem (if you really need to).
Express version "express": "^4.17.1" or above
From the document: Series of Middleware
var r1 = express.Router();
r1.get('/', function (req, res, next) {
next();
});
var r2 = express.Router();
r2.get('/', function (req, res, next) {
next();
});
app.use(r1, r2);
Let's try a real life example:
tourController.js
exports.checkBody = (req, res, next)=>{ // middleware 1
if (!req.body.price){
return res.status(400).json({
status:'fail',
message:'Missing price!!!'
})
}
next();
}
exports.createTour = (req, res) => { // middleware 2
tours.push(req.body);
fs.writeFile(
`${__dirname}/dev-data/data/tours-simple.json`,
JSON.stringify(tours),
(err) => {
res.status(201).json({
status: 'success',
data: {
tour: newTour,
},
});
}
);
};
tourRouter.js
const express = require('express');
const tourController = require('./../controller/tourController')
const router = express.Router();
router.route('/')
.get(tourController.getAllTours)
.post(tourController.checkBody, tourController.createTour);
//muliple Middleware in post route
module.exports = router //need this or the following step will break
app.js
const express = require('express');
const tourRouter = require('./route/tourRouter');
const app = express();
app.use(express.json());
app.use('/api/v1/tours', tourRouter);
module.exports = app;
Instead of attaching multer to the entire express app, i am trying to include it just for specific routes, which is better since you will be preventing uploads to every route handling post.
Problem is, i am unable to set it properties inside a route.
var router = require('express').Router(),
multer = require('multer');
router.post('/uploads', function (req, res, next) {
multer({
dest: req.app.get('cfg').uploads.dir
});
console.log(req.files); process.exit();
});
Here, req.files is undefined.
The same thing happens if i put multer in a seperate middleware and attach it to the above route.
function initMulter(req, res, next) {
multer({
dest: req.app.get('cfg').uploads.dir
});
next();
}
router.post('/uploads', initMulter, function (req, res, next) {
console.log(req.files); process.exit();
});
Also in this case, req.files is undefined.
Is there something really wrong that i am doing or should i start blaming the beer?
Multer is it's own middleware.
You can add it to a route via:
router.post('/uploads', multer({
dest: './my/destination' //req.app.get('cfg').uploads.dir
}), function (req, res, next) {
console.log(req.files);
process.exit();
});
Though you're going to have to find another way to access your config.
One way would be to pass the config or app through an export function.
module.exports = function(config) {
router.post('/uploads', multer({
dest: config.uploads.dir
}), function (req, res, next) {
console.log(req.files);
process.exit();
});
return router;
});
Then when you're requiring,
var route = require('./route')(app.get('cfg'));
I currently have a few router routes
router.route('/invite/token/:inviteToken')
.get(function (req, res) {
res.status(200).json(req.invite);
});
router.route('/invite/:inviteId')
.get(function (req, res) {
res.status(200).json(req.invite);
});
And the following simple router params:
router.param('inviteToken', function (req, res, next, inviteToken) {
console.log('inviteToken');
// populate req.invite
next();
});
router.param('inviteId', function (req, res, next, inviteId) {
console.log('inviteId');
// populate req.invite
next();
});
However when I try to fetch an invite by token the inviteId param handler is always triggered first with the literal value "token". Is there an issue with the way I've set up the routes and params?
Update 1 For more clarification
Route order definition matters, so the best practice is to go from most specific to most grabby.
app.get('/invite/token/:token', tokenHandler);
app.get('/invite/:inviteId', inviteHandler);
where tokenHandler and inviteHandler are appropriately formatted callback functions.