Where are get, post methods defined in ExpressJS? - node.js

I'm unable to find the code of get or post methods. I haven't found them in expressjs lib folder, so it's probably that they are present in one of the js files the Router requires.
var express = require('express');
var router = express.Router();
var Blah = require('../modules/Blah');
router.post('/', function(req, res, next) {
Blah.foo(req, res);
});
I need it to find out where the next parameter is passed to that callback function above, because it has to be done by ExpressJS framework under the hood.

Express uses the methods module to dynamically attach http verbs to the router :
lib/router/index.js :
// create Router#VERB functions
methods.concat('all').forEach(function(method){
  proto[method] = function(path){
    var route = this.route(path)
    route[method].apply(route, slice.call(arguments, 1));
    return this;
  };
});

See the answer by KeatsPeeks for more details. Here are some links to specific parts of the source code that might be helpful:
get and post methods are defined in the methods module here:
https://github.com/jshttp/methods/blob/master/index.js#L14-L15
Here in lib/applciation.js the .METHOD calls for them are delegated to router.METHOD:
https://github.com/strongloop/express/blob/master/lib/application.js#L471-L484
The rest is in lib/router/index.js:
https://github.com/strongloop/express/blob/master/lib/router/index.js#L506-L513
And in lib/router/route.js - search for "methods" in:
https://github.com/strongloop/express/blob/master/lib/router/route.js

Related

TypeError: register.route(...).use is not a function

I'm using express.Router() whenever i try use method it gives the following error
TypeError: register.route(...).use is not a function
Code
/server/routes
const express = require('express');
const register = express.Router();
const account = require("../controller/AccountController");
const Middleware = require("../utils/middlewares");
register.route('/')
.post(Middleware.checkUser)
.post(account.user_register)
register.route('/verify/:token')
.get(Middleware.verifyEmail)
register.route('/resend/:email')
.use(Middleware.sendVerification)
module.exports = register;
Server.js
server.use('/register', register);
When i use a method like get there is no error. But i don't want to use any method since the middleware just sends an email
As stated in documentation, route all method is intended for route-specific middleware, it could be:
register.route('/resend/:email')
.all(Middleware.sendVerification)
If the route is expected to be requested with GET only and may not make sense for other verbs, it should be narrowed down to supported verbs:
register.route('/resend/:email')
.get(Middleware.sendVerification)
In this case sendVerification seems to be route handler and not a middleware. It's suitable to specify it only for get if /resend/ is expected to be requested with GET.

Express.js unique var per request outside routing

In my express application I have a module called helpers thats is required in almost all my routes and modules. This module has a logger method that logs to fluentd (but that's unimportant). While building the data to log I'd like to add a unique identifier of the request, so that all the logs written for the same request have the same unique ID. Using a global var in the app entry point app.use doesn't work because this var would be overwritten every time a new request hits, so the global uuid will change would obviously change in case of high load or long running tasks. The res.locals is not available outside routing, so I can't use it for this matter. Is there a way to create a var that would be unique per request and available in every module or maybe a way to access the res.locals data outside routing? Thank you
EDIT
Maybe an example will help understand better the question.
Suppose I have a module called helpers.js like this:
let helpers = {};
helpers.log = (logData, logName) => {
fluentLogger.emit('', {
name: logName,
//uuid: the needed uuid,
message: logData
});
}
module.exports = helpers;
Now obviously I can do this in my app.js entry point:
app.use(function (req, res, next) {
res.locals.uuid = uuid.v4();
next();
});
and then in every loaded middleware module that requires helpers(adding a new param to the helpers.log method):
const helpers = require('helpers');
router.post('/', (req, res, next) => {
helpers.log('my log message', 'myLogName', res.locals.uuid);
next();
});
and this will normally work. But suppose a big or middle size project where there are hundreds of custom modules and models (not middlewares) and a module may require other modules that require other modules that require finally the helpers module. In this case I should pass the res.locals.uuid as a parameter to every method of every method so that I have it available in the logger method. Not a very good idea. Suppose I have a new module called dbmodel.js that is required in a middleware function:
const helpers = require('helpers');
let dbmodel = {};
dbmodel.getSomeData = (someParam) => {
//some logic
helpers.log('my log message', 'myLogName');
}
module.exports = dbmodel;
The dbmodel has no idea about the res.locals data if I don't pass it from the middleware, so the helpers.log method will also have no idea about this.
In PHP one would normally write a GLOBAL var in the application's entry point so a hypothetical logger function would have access to this global on every method request from whichever class of the application.
Hope this explanation will help :) Thank you
EDIT 2
The solution for this kind of problems is CLS. Thanks to #robertklep for the hint. A good slideshare explaining exactly the same problem (logger with unique ID) and explaining the CLS solutions can be found here: https://www.slideshare.net/isharabash/cls-and-asynclistener
I answered a very similar question here which will solve this problem.
I used to solve the problem the libraries node-uuid and continuation-local-storage. Take a look to the answer of this question and see if it helps:
NodeJS Express - Global Unique Request Id
And you want a bigger explanation, take a look here:
Express.js: Logging info with global unique request ID – Node.js
Yes you can do so by one method .
Every request comes to his routes pass that request inside the middleware.
Suppose you have
app.get('/', function(req, res) {
res.sendFile(path.join(public + "index.html"));
});
a request.
Place Middleware in it .and edit req field coming , in this way you will get the unique variable values for each request
check out this .
https://expressjs.com/en/guide/writing-middleware.html
Like this
var requestTime = function (req, res, next) {
req.requestTime = Date.now()
next()
}
app.use(requestTime)
app.get('/', function (req, res) {
var responseText = 'Hello World!<br>'
responseText += '<small>Requested at: ' + req.requestTime + '</small>'
res.send(responseText)
})
Here req.requestTime is unique for each request.

How can I set the routes correctly?

Here is a sample code:
var x = require('./folder/usefile');
var Auth = passport.authenticate('jwt', { session: false });
module.exports = function(app){
console.log('inside function(app)'); //line 1 executed!
var player = express.Router();
var finalRun = express.Router();
app.use('/api/usefile',player);
player.get('/', Auth, x.login);
player.post('/post', Auth, function(req, res){
x.register});
app.use('/api',finalRun);
console.log('inside api'); //line 2 is executed!
}
In usefile my login function is present which is exported.
I am using passport here, whose functionality is present in separate file here it is used only for authentication.
When I ran http://localhost:8080/api/usefile/---> for get method, it is displaying 404. same for post method.
The console is printing line 1 and line 2(have mentioned in the comments) and the flow is line1, line2.
Can anyone help me to find what mistake I have made here?
You've created two Router instances player and finalRun. There are two main issues:
This line player.use('/usefile',player) should be app.use('/usefile',player). express.Router().use is used to add a middleware for all routes registered to the router (in this case player). For example, if you wanted to use the Auth middleware from Passport for every player route, you could declare it as player.use(Auth).
You are not declaring any route handling for the finalRun router. So in this case, your route handlers registered with player will handle host/usefile and finalRun will handle any host/api.
If you are wanting the handlers registered with player to handle /api/usefile, using a single router instance would be far simpler.
Register the /api/usefile path with the player router like:
app.use('/api/usefile', player);
Docs for app.use
Docs for router.use

Express.js: Use Routers inside Routers

I have such router:
exports.read = (req,res) ->
// do stuff with DB
res.status(200).send
data:data
Now how can I use this router inside another router, call it exports.wrapper? I wnat to avoid having to rewrite my DB requests again and again. Is this approach that I have in mind recommended?
I would not recommend attempting to wrap routers inside each other.
It's recommended in Express 4 to use Express's router object like so:
// router.js
var myRouter = express.Router();
myRouter.route('/read', myController.readMethod);
Then in your controller you would handle the request and end with the result call:
// myController.js
exports.readMethod = function(req, res) {
var data = readFromDB(req.params);
res.send('read method renders', data);
}
exports.readMethod2 = function(req, res) {
var data = readFromDB(req.params);
res.send('read method 2 renders', data);
}
function readFromDB(params) {
// make a call to the DB (maybe via a model)
// return some data
}
Hope that helps
edit
Additionally, I would recommend wrapping your DB calls in a model, to abstract them away from your router or controller logic. For a reference of a well organised Express App that uses MVC checkout this Yeoman generator - https://github.com/ngenerio/generator-express-simple
second edit
In my very brief example externalising the readFromDB method to a model makes this function moot, if all it's doing is getting data from the DB put it in a model.

Cascade-like rendering with Express JS

With an express app running on a node server, how would I go about recursively searching for a render file from the full path right back to the beginning of the supplied URL.
For example, if someone was to hit my server with www.somewebsite.com/shop/products/product, the render engine would first check that there is an index.jade file in shop/products/product/. If none is found it would then check shop/products/, and subsequently shop/.
var express = require('express');
var app = express();
app.get('/*', function(req, res){
res.render(req.path + '/index.jade', function(err, html){
// some loopback code which alters the path and recalls the render method
})
});
The problem is that the response object is not passed to the render callback, so I'm unable to recall render on the response. I'm looking to create a loop because the URL paths may be any number of directories deep, so I can't just assume I only need to cascade for a definitive number of times.
Anyone see a way round this?
You should be able to use the response object from the closure. I think (assuming express allows you to call res.render a second time) you could use code like this answer to achieve what you want:
var express = require('express');
var app = express();
app.get('/*', tryRender);
function tryRender(req, res){
res.render(req.path + '/index.jade', function(err, html){
if (err) {
req.path = 'mynewpath';
tryRender(req, res);
}
})
}
Note: You will need to add a base case or this function will recurse infinitely if it doesn't find a view that works :D
In the event that express doesn't allow a subsequent call to res.render, you'll probably need to find out if the file exists on the file system yourself.

Resources