Express adds slash at the end of url weirdly - node.js

I'm using Node.js and Express framework for developing a website. I faced weird misbehaviour with a url. When i click to related link url, url becomes "localhost:3000/images/" - a slash is added at the end as you can see. But when i change all 'images' to 'img' or else url becomes "localhost:3000/img" no slash added. Why router behaves like that? Codes written below. (I'm using Jade template Engine)
//bar.jade
li.nav-item
a.nav-link(href='images')
i.icon-camera
| Images
//end of bar.jade
//images.js (router)
var express = require('express');
var router = express.Router();
/* GET home page. */
router.get('/', function(req, res, next) {
res.render('images', { title: 'Express'});
});
module.exports = router;
//end of router .js
//app.js
var images =require('./routes/images');
........
........
app.use('/images',images);
//end of app.js

I think I know what's going on: you're also using the express.static() middleware, and in your public directory you have a directory called images/.
This middleware will generate redirects ending with a slash when you try to request a URL that matches a public directory (even when that directory is empty or matches another route).
To disable this behaviour, set the redirect option to false.

By default in express router “/foo” and “/foo/” are treated the same by the router. You can disable this behavior with strict: true option.
Express.Router documentation
var router = express.Router({strict: true});

Related

express routing and path params

I have the following routing in app.js
app.use("/api/:phone/stuff", userRoutes);
In userRoutes, I have the following
userRoutes.get("/", userController.getStuff);
The client (Android app, retrofit) requests the following url: GET /api/+155555555/stuff, in userService I have getStuff method which is executed as expected, meaning it routes it well.
in a validation middleware, I see that req.originalUrl contains the url as expected but when viewing req.params, it is an empty object. I was expecting it to link the phone part of the url to :phone param so I will have req.params.phone.
I thought the problem was the + sign but it is urlencoded and even without it, it didn't work. What am I missing?
By default express router does not inherit parent router params
const userRoutes = express.Router({ mergeParams: true });
should do the trick
http://expressjs.com/en/4x/api.html#express.router

issue: Router.use requires a middleware function but got a obj

i have looked at all the other solutions around and I still cant seem to fix it
here is my file structure and my home.js where I have my routing which I moved from my routes.js file
i have already tried adding module.exports = router to the bottom of my .js files 1
You must register your router in app.js
More about routes
const homeRouter = require('./web/home');
app.use('/home', homeRouter );

Determining path in Express router routes

I've set up an express app and using the routing middleware to abstract some routes into a separate include.
I reference them using this style in the app.js:
app.use('/foo', my_urls);
This means "/foo/bar" in the browser is handled as if it's "/bar".
The problem though is that in the router.get("/bar"...) section in the included router file, I need to know the value of the preceding (foo) part. I've set up the route that this "foo" could be anything from an array of values.
Is there any way to know the context of the routing middleware, the preceding part of the path that the routes are acting within? In other words, can I do something like (pretend code here):
router.get('/bar', function(req, res, next) {
res.send(req.path[0]) // foo
});
Solved: Thanks for the answer. I can get the value using this:
router.get('/bar', function(req, res, next) {
res.send(req.baseUrl.splice(1)) // foo
});
express has req.path property so you can know the path but is shows path after parent Router's path (if you have one), so to get parent router path you can use req.baseUrl and req.originalUrl to get full url with queryparam.

404 when accessing new route

I'm trying to add a new route (/profile) to my NodeJS Express web application. I've modified my app.js file like this:
var routes = require('./routes/index');
var profile = require('./routes/profile');
app.use('/', routes);
app.use('/profile', profile);
The '/' index path works fine, my issue is with '/profile'. Whenever I try to access it, I get a 404. This is profile.js:
var express = require('express');
var router = express.Router();
router.get('/profile', function(req, res) {
var username = req.session.username;
if(username) {
res.render('profile');
} else {
res.redirect('/login');
}
});
module.exports = router;
I don't understand what I'm doing wrong because in the example express application that is generated, '/users' works fine. I basically copied that format, but it's throwing a 404. Any ideas?
In my profile.js, I had to change my GET request path to this:
router.get('/', function(req, res) {
//code
});
Otherwise, the router would be looking for /profile/profile. When I change it to /, it's just looking for the root of `/profile', or at least that's how I understand it.
To understand what you are doing wrong you should know that Node.js uses middleware functions to route your requests. To simplify you can think about it as a chain of functions.
Middleware is like a plumbing pipe, requests start at the first middleware you define and work their way “down” the middleware stack processing for each path they match.
So with the following statement you added a middleware function to handle any request starting with the root path /profile, and it is a common pattern in Node to use the use method to define the root paths.
app.use('/profile', profile);
The use method is doing part of the routing in your scenario and the statement above will match any route starting with that path, including /profile/all or /profile/12 or even /profile/go/deeper/inside.
However, you want to narrow down that routing to something more specific, so that is why you pass a router middleware function (profile in your case) to match more specific routes instead of all routes starting with /profile.
The profile middleware function is actually the next step in the chain of functions to execute, and it will start from the root path specified in the use statement, which is the reason why you need to start again with / and not with /profile. If you wanted to match a profile by ID you would do:
router.get('/:id', ...)
Which would be concatenated with the base URL (from the /use statement) and would match a request like /profile/2 or /profile/abc.

Express-js wildcard routing to cover everything under and including a path

I'm trying to have one route cover everything under /foo including /foo itself. I've tried using /foo* which work for everything except it doesn't match /foo. Observe:
var express = require("express"),
app = express.createServer();
app.get("/foo*", function(req, res, next){
res.write("Foo*\n");
next();
});
app.get("/foo", function(req, res){
res.end("Foo\n");
});
app.get("/foo/bar", function(req, res){
res.end("Foo Bar\n");
});
app.listen(3000);
Outputs:
$ curl localhost:3000/foo
Foo
$ curl localhost:3000/foo/bar
Foo*
Foo Bar
What are my options? The best I've come up with is to route /fo* which of course isn't very optimal as it would match way too much.
I think you will have to have 2 routes. If you look at line 331 of the connect router the * in a path is replaced with .+ so will match 1 or more characters.
https://github.com/senchalabs/connect/blob/master/lib/middleware/router.js
If you have 2 routes that perform the same action you can do the following to keep it DRY.
var express = require("express"),
app = express.createServer();
function fooRoute(req, res, next) {
res.end("Foo Route\n");
}
app.get("/foo*", fooRoute);
app.get("/foo", fooRoute);
app.listen(3000);
The connect router has now been removed (https://github.com/senchalabs/connect/issues/262), the author stating that you should use a framework on top of connect (like Express) for routing.
Express currently treats app.get("/foo*") as app.get(/\/foo(.*)/), removing the need for two separate routes. This is in contrast to the previous answer (referring to the now removed connect router) which stated that "* in a path is replaced with .+".
Update: Express now uses the "path-to-regexp" module (since Express 4.0.0) which maintains the same behavior in the version currently referenced. It's unclear to me whether the latest version of that module keeps the behavior, but for now this answer stands.
It is not necessary to have two routes.
Simply add (/*)? at the end of your path string.
For example, app.get('/hello/world(/*)?' /* ... */)
Here is a fully working example, feel free to copy and paste this into a .js file to run with node, and play with it in a browser (or curl):
const app = require('express')()
// will be able to match all of the following
const test1 = 'http://localhost:3000/hello/world'
const test2 = 'http://localhost:3000/hello/world/'
const test3 = 'http://localhost:3000/hello/world/with/more/stuff'
// but fail at this one
const failTest = 'http://localhost:3000/foo/world'
app.get('/hello/world(/*)?', (req, res) => res.send(`
This will match at example endpoints: <br><br>
<pre>${test1}</pre>
<pre>${test2}</pre>
<pre>${test3}</pre>
<br><br> Will NOT match at: <pre>${failTest}</pre>
`))
app.listen(3000, () => console.log('Check this out in a browser at http://localhost:3000/hello/world!'))
In array you also can use variables passing to req.params:
app.get(["/:foo", "/:foo/:bar"], /* function */);
For those who are learning node/express (just like me): do not use wildcard routing if possible!
I also wanted to implement the routing for GET /users/:id/whatever using wildcard routing. This is how I got here.
More info: https://blog.praveen.science/wildcard-routing-is-an-anti-pattern/

Resources