Is possible to extend express router function? I need to send soket.io along with response and request.
In one file i have router:
var contoller = require('controller');
...
module.exports = function(app, io) {
router.post('/', controller.postAction);
}
Controller file look something like this:
...
controler.prototype.postAction = function(req, res) {
}
...
So from first file I need to send ´io´ to controller, how can I do that?
you can define the actual postAction function which itself returns a function and pass io to the postAction function, like below:
controler.prototype.postAction = function(io) { // you receive io as an argument
return function(req, res){
// your midleware code here
}
}
and you can require this in your router like:
var contoller = require('controller');
...
module.exports = function(app, io) {
router.post('/', controller.postAction(io)); // note here we pass io
}
What happens here is the function postAction acts as a wrapper which returns the actual middleware, so you can easily pass any argument to it.
Let me know if this is not what you are looking for!
Related
librarys like express-validation and passport add methods to the req-variable, like req.assert and req.user. I know I can do this from inside a route:
app.get('/', (req,res,next) => {
req.foo = bar;
next();
}
But how can I do it from a library or external module?
In short: You expose a handler function which your consumers will need to app.use().
Here's the general approach. Consider the following module:
module.exports = function myExtension() {
return function myExtensionHandler(req, res, next) {
// This is called for every request - you can extend req or res here
req.myFun = myFun
// Make sure to call next() in order to continue the
// chain of handlers
return next()
}
}
function myFun() {
// My magic function
}
Now, from a consumer perspective:
const express = require('express')
const myExtension = require('my-extension')
const app = express()
// Here you tell Express to use your extension for incoming requests
app.use(myExtension())
// ...
I'd like to write a test that a given Express controller endpoint gets hit for a given HTTP request. Or, say, an authenticated request makes it through every middleware and hits the controller.
I don't actually care about the controller, in fact the controller is expensive, so I'd rather not run it.
Say something like:
UsersController.js
module.exports = {
get: function(req, res) {
// Simplified for example purposes. Assume this does something complex.
res.status(200).json({id: "user123"});
}
}
Then I have a Router:
var router;
module.exports = router = new express.Router();
router.get('/users/:id', isAuthenticated, isAdmin, logRequest, UsersController.get);
I'd like to write something like this in the test:
controllerStub = sinon.stub(UsersController, 'get', function(req, res) {
res.status(418).json(message: "I'm a teapot");
});
request.get('http://localhost:port/users/user123', function(err, response, body) {
response.statusCode.should.equal(418);
controllerStub.callCount.should.equal(1);
});
Unfortunately I think Express modifies the function pointer in a way that stubbing the controller with Sinon doesn't actually affect the function called by Express.
Is there any way I can "reach" into the Express router and get/replace/stub the running route?
I'd like to add some functionality to /module that gets executed for any matching route under that directory.
So for a given set of routes:
/module/
/module/page
/module/things
/module/things/:thingid
I want code in a router for /module to run for all of the above routes. /module doesn't render, it just fetches some common data and configures the view context. Then one of the other routes runs and renders the page.
Is this possible with koa-router? Or is there a better package?
Edit:
I think maybe I have to do a nested router and add middleware prior to the nesting like so:
var subRouter = new Router();
subRouter.get('/', function *(next){ doSomething(); });
subRouter.get('/page', function *(next){ doSomething(); });
subRouter.get('/things', function *(next){ doSomething(); });
subRouter.get('/things/thingid', function *(next){ doSomething(); });
mainRouter.use('/module',
function *(next) { doPreRouteSteps(); yield next; },
subRouter.routes()
);
Seems to be working, but I'm not sure if this is an ugly hack or what. If there is a better way, please advise.
You might consider using koa-mount to create a separate app, and then mount it under /module. The sub-app can have any pre- or post- middleware you'd like.
var mount = require('koa-mount');
var koa = require('koa');
var koaRouter = require('koa-router');
var subApp = koa();
var router = koaRouter();
router.get('/page', function *(next){ ... });
subApp.use(function*() { ...pre-route stuff... });
subApp.use(router.routes());
var mainApp = koa();
mainApp.use(mount('/module', subApp));
I like this approach because the way it encourages modularity.
koa-router can do this, i guess better.
router.use('/module/', function *(next) {
// code here
next();
});
router.get('/module/page', function *() {
this.body = 'your view';
});
on this sample, everytime the router encounters '/module'. even if there are trailing or additional params on the url. it will run the first function then proceed to any meet condition.
This is Rei Dien's response updated to 2021. Also you can pass an array of routes or "/" which will call your router.use() before any route. Example with array of routes:
router.use(["/user", "/posts"], async (ctx, next) => {
// Your code before routes...
await next();
});
router.get("/user/likes", async ctx => {
ctx.body = "Your rute code...";
});
I know what this require statement does.
var express = require('express');
var app = express();
But sometimes i have seen two parentheses after the require.
var routes = require('./routes')(app);
Q) What does this mean, and how does it work?
This is a pattern in which the module.exports of the module you are requiring is set to a function. Requiring that module returns a function, and the parentheses after the require evaluates the function with an argument.
In your example above, your ./routes/index.js file would look something like the following:
module.exports = function(app) {
app.get('/', function(req, res) {
});
// ...
};
This pattern is often used to pass variables to modules, as can bee seen above with the app variable.
Well, require is a function provided by Node.js that basically loads a module for you and it returns whatever you expose in the module that you loaded.
If what you expose (through the use of module.exports) in a given module is a function, then that is what requires returns. For instance.
//moduleX.js
module.exports = function(){
return "Helo World";
}
Then if you require it, you get a function back
var f = require('./moduleX');
console.log(f()); //hello world
Of course, you could invoke the function directly once you require it.
var greet = require('./moduleX')();
console.log(greet);
That mean that behind that, there is a function that is exported using module.exports:
module.exports = function(app) {
app.get("/", function(req, res){});
}
See also http://www.choskim.me/understanding-module-exports-and-exports-in-node-js/
Sidenote:
You could create function on the fly:
A.js
module.exports = function(data) {
return function(req, res, next) {
// Do something with data
next();
}
main.js
...
app.use(require("A")(data));
...
I am writing a web app in node.js using Express. I have defined a route as follows:
app.get("/firstService/:query", function(req,res){
//trivial example
var html = "<html><body></body></html>";
res.end(html)
});
How do I reuse that route from within express?
app.get("/secondService/:query", function(req,res){
var data = app.call("/firstService/"+query);
//do something with the data
res.end(data);
});
I couldn't find anything in the API documentation and would rather not use another library like "request" because that seems kludgey. I am trying to keep my app as modular as possible. Thoughts?
Thanks
Similar to what Gates said, but I would keep the function(req, res){} in your routes file. So I would do something like this instead:
routes.js
var myModule = require('myModule');
app.get("/firstService/:query", function(req,res){
var html = myModule.firstService(req.params.query);
res.end(html)
});
app.get("/secondService/:query", function(req,res){
var data = myModule.secondService(req.params.query);
res.end(data);
});
And then in your module have your logic split up like so:
myModule.js
var MyModule = function() {
var firstService= function(queryParam) {
var html = "<html><body></body></html>";
return html;
}
var secondService= function(queryParam) {
var data = firstService(queryParam);
// do something with the data
return data;
}
return {
firstService: firstService
,secondService: secondService
}
}();
module.exports = MyModule;
Can you simply break this out into another function, put it in a shared spot and go from there?
var queryHandler = require('special_query_handler');
// contains a method called firstService(req, res);
app.get('/firstService/:query', queryHandler.firstService);
// second app
app.get('/secondService/:query', queryHandler.secondService);
Honestly, this whole business of nesting the call back inside of the app.get(...) is not really a great practice. You end up with a giant file containing all of the core code.
What you really want is a file filled with app.get() and app.post() statements with all of the callback handlers living in different, better organized files.
If you have a lot of middleware on your route, you can benefit from spreading:
const router = express.Router();
const myMiddleware = [
authenticationMiddleware(),
validityCheckMiddleware(),
myActualRequestHandler
];
router.get( "/foo", ...myMiddleware );
router.get( "/v1/foo", ...myMiddleware );
You can use run-middleware module exactly for that
app.runMiddleware('/firstService/query',function(responseCode,body,headers){
// Your code here
})
More info:
Module page in Github & NPM;
Examples of use run-middleware module
Disclosure: I am the maintainer & first developer of this module.
I have used following way:
at userpage.js
router.createSitemap = function(req, res, callback) { code here callback(value); }
at product.js
var userPageRouter = require('userpages');
userPageRouter.createSitemap(req, res, function () {
//console.log('sitemap');
});
Also can use in same userpage.js router I can use for other routing as well. eg.
router.get('/sitemap', function (req, res, next) {
router.createSitemap(req, res, function () {
res.redirect('/sitemap.xml');
}); });
Hope this will help.