can someone explain me why we are using this code in square brackets and why its assign to a const middlewares , Can we use it without const middlewares = [..]
const middlewares = [
layout(),
express.static(path.join(__dirname,'views')),
bodyParser.urlencoded({extended: false})
]
Sorry for the inconvenience, i am new to this field
This code creates an array of 3 elements.
In this case an array of 3 function pointers.
We can't know exactly why the code you are looking at would have it but my guess is there is a system somewhere that wants to use this array so you create the array.
const is used to indicate that it won't be changed.
You should read about closure in node in order to understand more about how this works.
The "square brackets" you mention are used to declare an Array literal.
const indicates that it's a constant and can't be changed once declared.
In this context (with your express tag), this array amalgamates several middlewares into a single structure to be applied at once, usually to a particular route. This is detailed in the official documentation on Using Express middleware:
Middleware can also be declared in an array for reusability.
This example shows an array with a middleware sub-stack that handles
GET requests to the /user/:id path
function logOriginalUrl (req, res, next) {
console.log('Request URL:', req.originalUrl)
next()
}
function logMethod (req, res, next) {
console.log('Request Type:', req.method)
next()
}
var logStuff = [logOriginalUrl, logMethod]
app.get('/user/:id', logStuff, function (req, res, next) {
res.send('User Info')
})
Related
Based on express documentation here we can attach HTTP method to express instance, and also execute callback function when the route matches.
We can also execute multiple callback route handlers. Route handlers can be in the form of a function, an array of functions, or combinations of both, as shown in the following examples.
app.get('/', function (req, res) {
res.send('GET request to the homepage');
});
or using array
var cb0 = function (req, res, next) {
console.log('CB0');
next();
}
var cb1 = function (req, res, next) {
console.log('CB1');
next();
}
var cb2 = function (req, res) {
res.send('Hello from C!');
}
app.get('/example/c', [cb0, cb1, cb2])
However,in our application i see the syntax developer has used is
app.get('/example/c',cb0, cb1)
Notice there is no array [] but 2 callback functions are passed as comma separated. This is working. But just curious how?
In Javascript you can pass any number of arguments into a function call no matter what the function definition is. For example function x(a, b){} could be called with more than two arguments. Programmers take advantage of the arguments special variable when they don't know in advance how many arguments a function call will receive. This is the case with the routing functions in express (.get, .put, .post, etc). They take any number of arguments you pass in and treat them as middleware functions as you can see in the documentation.
Its working due to middlewares. check this out
I am using Express 4 with the new router. At least one thing continues to confuse me, and it is a syntax problem - I am wondering if there is a regex that can do what I want. I have a standard REST api, but I want to add batch updates, so that I can send all the info to update some users models with one request, instead of one PUT request per user, for example. Anyway, I currently route all requests to the users resources, like so:
app.use('/users, userRoutes);
in userRoutes.js:
router.get('/', function (req, res, next) {
//gets all users
});
router.put('/:user_id', function (req, res, next) {
//updates a single user
});
but now I want a route that captures a batch request, something like this:
router.put('/Batch', function (req, res, next) {
//this picks up an array of users from the JSON in req.body and updates all
});
in other words, I want something which translates to:
app.use('/usersBatch, function(req,res,next){
}
...but with the new router. I can't get the syntax right.
I tried this:
app.use('/users*, userRoutes);
but that doesn't work. Does anyone know how to design this?
I'm guessing that the call to [PUT] /users/Batch is being picked up by the [PUT] /users/:user_id route. The string /:user_id is used as a regular expression causing it to also collect /Batch.
You can either move /Batch before /:user_id in the route order, refine the regex of /:user_id to not catch /Batch or change /Batch to something that won't get picked up too early.
(plus all the stuff Michael said)
REST doesn't include a POST as a list syntax. That's because each URL in REST point to an individual resource.
As an internet engineer I haven't seen any bulk PUTs or POSTs, but that said, it's your app, so you can make whatever API you like. There are definitely use cases for it.
You'll still need to describe it to Express. I would do it like this:
var express = require('express');
var router = express.Router();
router.get('/', function (req, res) {}); // gets all users
router.post('/:user_id', function (req, res) {}); // one user
router.put('/:user_id', function (req, res) {}); // one user
router.patch('/:user_id', function (req, res) {}); // one user
router.delete('/:user_id', function (req, res) {}); // one user
app.use('/user', router); // Notice the /user/:user_id is *singular*
var pluralRouter = express.Router();
pluralRouter.post('/', function (req, res) {
// req.body is an array. Process this array with a foreach
// using more or less the same code you used in router.post()
});
pluralRouter.put('/', function (req, res) {
// req.body is another array. Have items in the array include
// their unique ID's. Process this array with a foreach
// using +/- the same code in router.put()
});
app.use('/users', pluralRouter); // Notice the PUT /users/ is *plural*
There are other ways to do this. Including putting comma-delimited parameters in the URL. E.g.
GET /user/1,2,3,4
But this isn't that awesome to use, and vague in a PUT or POST. Parallel arrays are evil.
All in all, it's a niche use case, so do what works best. Remember, the server is built to serve the client. Figure out what the client needs and serve.
Is there a canonical way to remove middleware added with app.use from the stack? It seems that it should be possible to just modify the app.stack array directly, but I am wondering if there is a documented method I should be considering first.
use actually comes from Connect (not Express), and all it really does is push the middleware function onto the app's stack.
So you should be just fine splicing the function out of the array.
However, keep in mind there is no documentation around app.stack nor is there a function to remove middleware. You run the risk of a future version of Connect making changes incompatible with your code.
This is a useful functionality if you are inheriting some unwanted middleware from a framework built on express.
Building on some of the answers that came before me: In express 4.x the middleware can be found in app._router.stack. Note that the middleware are invoked in order.
// app is your express service
console.log(app._router.stack)
// [Layer, Layer, Layer, ...]
Tip: You can search the individual layers for the one you want to remove/move
const middlewareIndex = app._router.stack.findIndex(layer => {
// logic to id the specific middleware
});
Then you can just move/remove them with standard array methods like splice/unshift/etc
// Remove the matched middleware
app._router.stack.splice(middlewareIndex, 1);
There seems to be no built in way to do that, but you can manage to get the same result with a small trick. Create your own array of middleware (let's call it dynamicMiddleware) but don't push that into express, instead push just 1 middleware that will execute all the handlers in dynamicMiddleware asynchronously and in order.
const async = require('async')
// Middleware
const m1 = (req, res, next) => {
// do something here
next();
}
const m2 = (req, res, next) => {
// do something here
next();
}
const m3 = (req, res, next) => {
// do something here
next();
}
let dynamicMiddleware = [m1, m2, m3]
app.use((req, res, next) => {
// execute async handlers one by one
async.eachSeries(
// array to iterate over
dynamicMiddleware,
// iteration function
(handler, callback) => {
// call handler with req, res, and callback as next
handler(req, res, callback)
},
// final callback
(err) => {
if( err ) {
// handle error as needed
} else {
// call next middleware
next()
}
}
);
})
The code is a bit rough as I don't have a chance to test it right now, but the idea should be clear: wrap all dynamic handlers array in 1 middleware, that will loop through the array. And as you add or remove handlers to the array, only the ones left in the array will be called.
You can use the express-dynamic-middleware to make this.
https://github.com/lanbomo/express-dynamic-middleware
Use it like this
const express = require('express');
// import express-dynamic-middleware
const dynamicMiddleware = require('express-dynamic-middleware');
// create auth middleware
const auth = function(req, res, next) {
if (req.get('Authorization') === 'Basic') {
next();
} else {
res.status(401).end('Unauthorization');
}
};
// create dynamic middleware
const dynamic = dynamicMiddleware.create(auth);
// create express app
const app = express();
// use the dynamic middleware
app.use(dynamic.handle());
// unuse auth middleware
dynamic.unuse(auth);
No way of removing a middleware as far as I know. however, you can assign a boolean flag to 'deactivate' a middleware at anytime you want.
let middlewareA_isActivate = true;
// Your middleware code
function(req, res, next) {
if (!middlewareA_isActivate) next();
// .........
}
// Deactivate middleware
middlewareA_isActivate = false;
EDIT :
After reading through ExpressJs (4.x) code, I notice that you can access the middlewares stack via app._router.stack, manipulation goes from there I guess. Still, I think this 'trick' might not be able to work in future Express
P/s: Not tested how Express behaves when manipulate the middlewares stack directly though
Following from the hints above, I've add success with the following on express 4.x. My use case was logging what was coming in with Slack Bolt, so I could capture and then mock it:
// Define a handy function for re-ordering arrays
Array.prototype.move = function(from, to) {
this.splice(to, 0, this.splice(from, 1)[0]);
};
// Use the normal use mechanism, so that 'extra' stuff can be done
// For example, to log further up the order, use app.use(morgan("combined"))
app.use([my-middleware]);
// Now adjust the position of what I just added forward
const numElements = app._router.stack.length;
app._router.stack.move(numElements - 1, 1);
You can use
console.log("Stack after adjustment", app._router.stack)
to confirm the new order is what you want. (For Slack Bolt, I had to use app.receiver.app because the Bolt app wraps the express app.)
We can write like this.
// route outside middleware
route.get("/list", (req, res)=>{
res.send("from listing route");
});
//use middleware
router.use(Middlewares.AuthMiddleware.isValidToken);
//routes inside the middleware
route.post("/create", (req, res)=>{
res.send("from create route");
});
route.delete("/delete", (req, res)=>{
res.send("from delete route");
});
So basically, write routes before injecting middleware into your route.
I have very simple node.js noob question. How do I pass a variable to an exported route function?
Routes file
exports.gettop = function(n, req, res) {
console.log(n);
res.send(200);
};
Server file
app.get('/api/v1/top100', routes.gettop(100));
Error: .get() requires callback functions but got a [object Undefined]
For your example, you want to create a new function that will close around your value of n. In your case, you are executing gettop and passing the returned value to express as your route, which means gettop needs to return the route handler.
exports.gettop = function(n){
return function(req, res) {
console.log(n);
res.send(200);
};
};
As your code looks like you're using express you can use express app locals and express result locals to pass variables to your route. While the other answers propose working solutions I think that it's less obtrusive to use express mechanisms to set these variables.
With response locals (See Express API reference) you first have to set a variable somewhere in a middleware or route. I'll show the middleware approach
app.use(function(req,res, next) {
res.locals.top = 200;
next();
});
then in your route you can access this property via res.locals.variablename
exports.gettop = function(req, res) {
console.log(res.locals.top);
res.send(200);
};
In case you want to make these settings application wide a better approach is to use app locals (See Express API reference)
To set an app locals variable you can use
app.locals.top = 100;
To access this variable from your route use
exports.gettop = function(req, res){
console.log(req.app.locals.top);
res.send(200);
};
As an alternative to loganfsmyth's (very valid!) solution, you could leave your gettop function as-is and create a partial function:
app.get('/api/v1/top100', routes.gettop.bind(null, 100));
Try
app.post('/find_user',
require('./naas/autentication'),
require('./naas/authorization')(paramForRouter),
require('./routes/users'));
Where
require('./naas/autentication') is for example
module.exports = function (req, res, next) {next();}
And require('./naas/authorization')(paramForRouter) is
module.exports = function (paramForRouter) {
return function (req, res, next) {
this.param = paramForRouter;
console.log("Param value",this.param);
next();
};
};
I see a lot of use next in node.js.
What is it, where does it come from? What does it do? Can I use it client side?
Sorry it's used for example here:
http://dailyjs.com/2010/12/06/node-tutorial-5/
look for the loadUser function.
This appears to be a variable naming convention in Node.js control-flow code, where a reference to the next function to execute is given to a callback for it to kick-off when it's done.
See, for example, the code samples here:
http://blog.mixu.net/2011/02/02/essential-node-js-patterns-and-snippets/
Let's look at the example you posted:
function loadUser(req, res, next) {
if (req.session.user_id) {
User.findById(req.session.user_id, function(user) {
if (user) {
req.currentUser = user;
return next();
} else {
res.redirect('/sessions/new');
}
});
} else {
res.redirect('/sessions/new');
}
}
app.get('/documents.:format?', loadUser, function(req, res) {
// ...
});
The loadUser function expects a function in its third argument, which is bound to the name next. This is a normal function parameter. It holds a reference to the next action to perform and is called once loadUser is done (unless a user could not be found).
There's nothing special about the name next in this example; we could have named it anything.
It is naming convention used when passing callbacks in situations that require serial execution of actions, e.g. scan directory -> read file data -> do something with data. This is in preference to deeply nesting the callbacks. The first three sections of the following article on Tim Caswell's HowToNode blog give a good overview of this:
http://howtonode.org/control-flow
Also see the Sequential Actions section of the second part of that posting:
http://howtonode.org/control-flow-part-ii
It's basically like a callback that express.js use after a certain part of the code is executed and done, you can use it to make sure that part of code is done and what you wanna do next thing, but always be mindful you only can do one res.send in your each REST block...
So you can do something like this as a simple next() example:
app.get("/", (req, res, next) => {
console.log("req:", req, "res:", res);
res.send(["data": "whatever"]);
next();
},(req, res) =>
console.log("it's all done!");
);
It's also very useful when you'd like to have a middleware in your app...
To load the middleware function, call app.use(), specifying the
middleware function. For example, the following code loads the
myLogger middleware function before the route to the root path (/).
var express = require('express');
var app = express();
var myLogger = function (req, res, next) {
console.log('LOGGED');
next();
}
app.use(myLogger);
app.get('/', function (req, res) {
res.send('Hello World!');
})
app.listen(3000);