I'm kind of new to express and node.js, and I can't figure out the difference between app.use and app.get. It seems like you can use both of them to send information. For example:
app.use('/',function(req, res,next) {
res.send('Hello');
next();
});
seems to be the same as this:
app.get('/', function (req,res) {
res.send('Hello');
});
app.use() is intended for binding middleware to your application. The path is a "mount" or "prefix" path and limits the middleware to only apply to any paths requested that begin with it. It can even be used to embed another application:
// subapp.js
var express = require('express');
var app = modules.exports = express();
// ...
// server.js
var express = require('express');
var app = express();
app.use('/subapp', require('./subapp'));
// ...
By specifying / as a "mount" path, app.use() will respond to any path that starts with /, which are all of them and regardless of HTTP verb used:
GET /
PUT /foo
POST /foo/bar
etc.
app.get(), on the other hand, is part of Express' application routing and is intended for matching and handling a specific route when requested with the GET HTTP verb:
GET /
And, the equivalent routing for your example of app.use() would actually be:
app.all(/^\/.*/, function (req, res) {
res.send('Hello');
});
(Update: Attempting to better demonstrate the differences.)
The routing methods, including app.get(), are convenience methods that help you align responses to requests more precisely. They also add in support for features like parameters and next('route').
Within each app.get() is a call to app.use(), so you can certainly do all of this with app.use() directly. But, doing so will often require (probably unnecessarily) reimplementing various amounts of boilerplate code.
Examples:
For simple, static routes:
app.get('/', function (req, res) {
// ...
});
vs.
app.use('/', function (req, res, next) {
if (req.method !== 'GET' || req.url !== '/')
return next();
// ...
});
With multiple handlers for the same route:
app.get('/', authorize('ADMIN'), function (req, res) {
// ...
});
vs.
const authorizeAdmin = authorize('ADMIN');
app.use('/', function (req, res, next) {
if (req.method !== 'GET' || req.url !== '/')
return next();
authorizeAdmin(req, res, function (err) {
if (err) return next(err);
// ...
});
});
With parameters:
app.get('/item/:id', function (req, res) {
let id = req.params.id;
// ...
});
vs.
const pathToRegExp = require('path-to-regexp');
function prepareParams(matches, pathKeys, previousParams) {
var params = previousParams || {};
// TODO: support repeating keys...
matches.slice(1).forEach(function (segment, index) {
let { name } = pathKeys[index];
params[name] = segment;
});
return params;
}
const itemIdKeys = [];
const itemIdPattern = pathToRegExp('/item/:id', itemIdKeys);
app.use('/', function (req, res, next) {
if (req.method !== 'GET') return next();
var urlMatch = itemIdPattern.exec(req.url);
if (!urlMatch) return next();
if (itemIdKeys && itemIdKeys.length)
req.params = prepareParams(urlMatch, itemIdKeys, req.params);
let id = req.params.id;
// ...
});
Note: Express' implementation of these features are contained in its Router, Layer, and Route.
Simply
app.use means “Run this on ALL requests”
app.get means “Run this on a GET request, for the given URL”
app.use is the "lower level" method from Connect, the middleware framework that Express depends on.
Here's my guideline:
Use app.get if you want to expose a GET method.
Use app.use if you want to add some middleware (a handler for the HTTP request before it arrives to the routes you've set up in Express), or if you'd like to make your routes modular (for example, expose a set of routes from an npm module that other web applications could use).
app.get is called when the HTTP method is set to GET, whereas app.use is called regardless of the HTTP method, and therefore defines a layer which is on top of all the other RESTful types which the express packages gives you access to.
Difference between app.use & app.get:
app.use → It is generally used for introducing middlewares in your application and can handle all type of HTTP requests.
app.get → It is only for handling GET HTTP requests.
Now, there is a confusion between app.use & app.all. No doubt, there is one thing common in them, that both can handle all kind of HTTP requests.
But there are some differences which recommend us to use app.use for middlewares and app.all for route handling.
app.use() → It takes only one callback.
app.all() → It can take multiple callbacks.
app.use() will only see whether url starts with specified path.
But, app.all() will match the complete path.
For example,
app.use( "/book" , middleware);
// will match /book
// will match /book/author
// will match /book/subject
app.all( "/book" , handler);
// will match /book
// won't match /book/author
// won't match /book/subject
app.all( "/book/*" , handler);
// won't match /book
// will match /book/author
// will match /book/subject
next() call inside the app.use() will call either the next middleware or any route handler, but next() call inside app.all() will invoke the next route handler (app.all(), app.get/post/put... etc.) only. If there is any middleware after, it will be skipped. So, it is advisable to put all the middlewares always above the route handlers.
In addition to the above explanations, what I experience:
app.use('/book', handler);
will match all requests beginning with '/book' as URL. so it also matches '/book/1' or '/book/2'
app.get('/book')
matches only GET request with exact match. It will not handle URLs like '/book/1' or '/book/2'
So, if you want a global handler that handles all of your routes, then app.use('/') is the option. app.get('/') will handle only the root URL.
There are 3 main differences I have found till now. The 3rd one is not so obvious and you may find it interesting. The differences are the same for the express router. That means router.use() and router.get() or other post, put, all, etc methods has also same difference.
1
app.use(path, callback) will respond to any HTTP request.
app.get(path, callback) will only respond to GET HTTP request. In the same way, post, put, etc will respond to their corresponding request. app.all() responds to any HTTP request so app.use() and app.all() are the same in this part.
2
app.use(path, callback) will match the prefix of the request path and responds if any prefix of the request path matches the path parameter. Such as if the path parameter is "/", then it will match "/", "/about", "/users/123" etc.
app.get(path, callback) Here get will match the whole path. Same for other HTTP requests and app.all(). Such as, if the path parameter is "/", then it will only match "/".
3
next('route') doesn't work on the middleware/callback functions of app.use(). It works only on app.get(), app.all() and other similar function of other HTTP requests.
According to express documentation:
next('route') will work only in middleware functions that were loaded by using the app.METHOD() or router.METHOD() functions.
METHOD is the HTTP method of the request that the middleware function
handles (such as GET, PUT, or POST) in lowercase.
From here we will use the keyword METHOD instead of get, post, all, etc.
But what is next('route')?!
Let's see.
next('route')
we see, app.use() or app.METHOD() can take several callback/middleware functions.
From the express documentation:
Middleware functions are functions that have access to the request object (req), the response object (res), and the next middleware function in the application’s request-response cycle. The next middleware function is commonly denoted by a variable named next.
If the current middleware function does not end the request-response cycle, it must call next() to pass control to the next middleware function. Otherwise, the request will be left hanging.
So we see each middleware functions have to either call the next middleware function or end the response.
And this is same for app.use() and app.METHOD().
But sometimes in some conditions, you may want to skip all the next callback functions for the current route but also don't want to end the response right now. Because maybe there are other routes which should be matched. So to skip all the callback functions of the current route without ending the response, you can run next('route'). It will skip all the callback functions of the current route and search to match the next routes.
For Example (From express documentation):
app.get('/user/:id', function (req, res, next) {
// if the user ID is 0, skip to the next route
if (req.params.id === '0') next('route')
// otherwise pass the control to the next middleware function in this stack
else next()
}, function (req, res, next) {
// send a regular response
res.send('regular')
})
// handler for the /user/:id path, which sends a special response
app.get('/user/:id', function (req, res, next) {
res.send('special')
})
See, here in a certain condition(req.params.id === '0') we want to skip the next callback function but also don't want to end the response because there is another route of the same path parameter which will be matched and that route will send a special response. (Yeah, it is valid to use the same path parameter for the same METHOD several times. In such cases, all the routes will be matched until the response ends). So in such cases, we run the next('route') and all the callback function of the current route is skipped. Here if the condition is not met then we call the next callback function.
This next('route') behavior is only possible in the app.METHOD() functions.
Recalling from express documentation:
next('route') will work only in middleware functions that were loaded by using the app.METHOD() or router.METHOD() functions.
Since skipping all callback functions of the current route is not possible in app.use(), we should be careful here. We should only use the middleware functions in app.use() which need not be skipped in any condition. Because we either have to end the response or traverse all the callback functions from beginning to end, we can not skip them at all.
You may visit here for more information
app.use gets called every time a request is sent to the server.
Only thing is we should call it before handling get, put, post etc. requests
app.use(middleware);
function middleware(req, res, next)
{
console.log("Came in middleware function without arrow");
next();
}
app.get gets called only for get requests for given path.
app.get('/myget', myget_function);
function myget_function(req, res)
{
console.log("Came in function myget");
res.send('Hello World! from myget');
}
app.post gets called only for post requests for given path.
app.post('/mypost', mypost_function);
function mypost_function(req, res)
{
console.log("Came in function mypost");
res.send('Hello World! from mypost');
}
Related
Does using app.use(express.static("public")) call the middleware for every request, even if it wasn't a request for a static resource?
It will only get called if a route hasn't dealt with the request already.
Keeping in mind that routes are tested in the order they are registered, take this example:
const express = require('express');
const app = express();
const port = 3000;
app.get('/foo', (req, res) => {
console.log('Foo!');
res.send('Foo!');
});
app.use(function (req, res, next) {
console.log('middleware triggered');
next();
});
app.get('/bar', (req, res) => {
console.log('Bar!');
res.send('Bar!');
});
app.listen(port, () => {
console.log(`Example app listening at http://localhost:${port}`);
});
If I request http://localhost:3000/foo then the server will log:
Foo!
The /foo endpoint matched the request and then called res.send().
If I request http://localhost:3000/bar then it logs:
middleware triggered
Bar!
The middleware kicks in (because it matches the route), called next() to go to the next function that matches the route, and then the /bar handler is called.
It is important to position your static middleware carefully.
If you put it before the route you want to match the request then there are two possible negative effects:
You'll call it when it isn't needed which is inefficient
A static file will match a route instead of an actual route handler
On the other hand, if you put it last then you'll solve the efficiency problem, but some bad route design might mean that something creates a URL which matches an already existing static file and masks it.
It's a good idea to specify a directory that you know will never conflict with a route (e.g. app.use('/static', express.static('public'));) to avoid that possibility. As a bonus it means that any broken links which would normally 404 won't have to go through the static middleware unless the link is pointing in the /static path in the first place.
When registering it like that it, the middleware will run on every request, yes.
Basically because that statement is actually the same as:
app.use("/", express.static("public"))
Calling express.static returns a classic middleware function that will be run on every path you specify in app.use.
If you want it only to kick in on a specific path, you could register it like this:
app.use('/static', express.static('public'));
I need strategy on organizing the urls.
Our application has around 150 urls. Some are rather simple without any Route parameters. While others have often more than 1 route parameter in them. For example it could be like this
api/School/Class
api/School/1/Class/2/Student
api/School/Class/revaluate
So in the first one it has no parameter , while second has two parameters and finally third one has 1 but last part is not a resource but an action.
I don't want to store the url just where we would consume it, since maintaining the urls would be technical nightmare. I was hoping if we could have single file api.js or multiple files like api/School.js , api/Teacher.js for storing the files.
In express, you call this a router.
const express = require('express');
const app = express();
const schoolRouter = require('./routers/school');
//...
app.use('/api/school', schoolRouter); // Forwards any requests to the schoolrouter
//...
School.js:
// The router works just like express app (which is also a router)
const schools = require('express').Router();
// we used example.com/api/schools/something to get here
// but the router only cares about what comes next
schools.get('/', function(req, res, next) {
// res.send()
});
// Get a single school (etc, you get the point)
schools.get('/:schoolId', function(req, res, next) {
let id = req.params.schoolId;
// get data from server and res.send()
});
//...
module.exports = schools;
And you can chain routers, but because you only have a partial route, parameters might get lost. So the normal thing is to store parameters to the req object.
schools.use('/:schoolId/classes', function(req, res, next) {
req.schoolId = req.params.schoolId;
next()
}, classesRouter);
This way we can access req.schoolId at any time further down the chain.
//Force HTTPS
if (app.get('env') == 'production'){
app.use('*',function(req,res,next){
if(req.headers['x-forwarded-proto']!='https') res.redirect(301, "https://" + req.host + req.url)
/* x-forwarded-proto is used because heroku */
else next()
})
}
Edit: for anyone using this example -- req.host is deprecated, be sure to use req.hostname instead.
I have a block of code that redirects any http request to the same page, but with https protocol.. it works beautifully except that making an http request always redirects to the homepage. I've traced it down to the fact that req.url is always equal to '/' no matter what the request url actually is.
i.e. If I navigate to page http://hostname.com/my/path I would expect req.urlon the server to equal "my/path/" but instead it just equals "/".
I'm thinking this has something to do with either react-router, which I'm using for the front-end, or the way that heroku internally redirects the request, but I have not been able to find a solution yet.
Mounting a function to a path with app.use() rewrites the req.url by removing the mount point part from it. You should use req.originalUrl instead or omit the path argument:
app.use(function (req, res, next) {
// req.url not changed as path is not specified
});
app.use('/foobar', function (req, res, next) {
// foobar removed from the req.url
});
app.use('*', function (req, res, next) {
// everything (*) removed from the req.url
// original URL available in req.originalUrl
});
Is app.use express or something? My guess would be that youre probably performing a redirect before you get to that snippet of code you provided. It's probably not react-router because front-end stuff happens after the backend returns a response (meaning req.url shouldnt be affected by react-router because react-router comes later)
I have recently started a new app with Express 4.0, and I really liked the new express.Router() thing.
Something that got me stuck for quite some time was the following behavior:
var app = require('express')(),
router = express.Router();
router.get('/me', function(req, res, next) {
if(someBoolean) {
return next(); //here I expect to get a 404 error from express!
}
res.json({name: 'yourName'});
});
router.get('/:user_id', function() {
//any code here!
});
app.use('/users', router);
I always used next() (in Express 3.x) to either call the next middleware or to force a 404 from the server.
Since /users/me and /users/45 are totally different routes and are not mounted in a way that one should come after another, I wonder why I get code in /users/:user_id evaluated after calling next() in /users/me.
Am I doing something wrong or things are supposed to work different in Express 4.0?
This is working as expected. In Express 4 all middleware/routes are executed in the order that they are added to your app, so the path for your second router.get() is tested and matches because :user_id could be any kind of token, numeric or otherwise (basically any character that isn't /).
You can fix this at least in a couple of different ways:
Don't call next() in your first router.get()
Use a RegExp instead of a string to ensure that user_id only matches a numeric value. For example: router.get(/^\/(\d+)$/, function() {. However then you have to access the param via regexp group index instead of by a name: var user_id = req.params[0].
I'm new to Node and Express and I'm not sure how I can access req in a middleware function in a POST route. Do I need to pass it in as a parameter? There are other middleware functions in this route that access req but it is not being passed in. Overall, I'm guess I'm confused as to how req works...
The function I'm referring to is helpers.createPermissions()
My Route
app.post('/oauth/authorize/decision', login.ensureLoggedIn('connect/signin'), helpers.createPermissions(req), oauth2.server.decision());
The Function
exports.createPermissions = function(req) {
console.log(req);
};
The Error
ReferenceError: req is not defined
Middleware will always get passed three arguments: req, res and next.
So your middleware should look like this:
exports.createPermissions = function(req, res, next) {
console.log(req);
// TODO: make sure you eventually call either `next` or send back a response...
};
And you can use it like this:
app.post('/oauth/authorize/decision', login.ensureLoggedIn('connect/signin'), helpers.createPermissions, oauth2.server.decision());
In situations where you see middleware being called as a function, it's because you're not calling the middleware itself, but a function that's returning a middleware function. For example:
var myMiddlewareWrapper = function() {
// return the actual middleware handler:
return function(req, res, next) {
...
};
};
app.get('/', myMiddlewareWrapper(), ...);
This is usually done to pass extra options to the middleware handler (like with login.ensureLoggedIn()).