Express router for accepting a URL as route parameter - node.js

Imagine you want to build a webpage health checker. I want users to send GET requests to https://localhost/check/{valid_url_here} and I send a request to that URL. I couldn't find proper way of writing the correct router for this in Express.
This is the closest answer but it trims the url after ? adding it to req.query
router.get('/check/:url*', (req, res) => {})
so when URL is https://example.com/?print=1 the variable req.params.url misses the ?print part... I want to capture anything that comes after /check/

router.use("/check", function(req, res) {
var url = req.url.substring(1);
});
Then https://localhost/check/https://example.com/?print=1 leads to url = "https://example.com/?print=1".

Related

How do I access URL parameter after i've routed my express app to another file?

My main express server is called app.js in Node.js.
app.use("/login", require(./routes/login));
app.use("/:id", require("./routes/users"));
When I try to access the URL parameter, it returns undefined.
I tried logging req.params:
const express = require('express');
const router = express.Router();
router.get('/dashboard', (req, res) => {
res.send(`Current Ornament Status and Data for ${req.params}`);
});
module.exports = router;
It gives me an empty array.
I suppose that it the parameter is inaccessible in another file after routing. Could you suggest a workaround?
I think you're missing some fundamental bits about express.js routing for this to make sense.
The requires line means it is loading another piece of code. So you need to show us that too.
The :id thing requires a longer explanation.
Let's say I want the server to process the URL /finduser/23
Where 23 can vary, could be just about any number. I am NOT going to write 99 different versions of router.get, right?
router.get("/finduser/1",...
router.get("/finduser/2",...
router.get("/finduser/3",...
No, what we do is turn that into a parameter
router.get("/finduser/:id",...
Then whatever number we pass turns into req.params.id, assume router passes req,res
EX: If we pass URL /finderuser/15, then req.params.id = 15
If you just pass /finduser then req.params.id gets NOTHING.
Full details are available here
http://expressjs.com/en/guide/routing.html#route-parameters
Your example:
router.get('/dashboard', (req, res)
Doesn't have ANY parameters. so req.params.id has nothing.

Node express api routes for multilingual directory like url

Does any one knows an example or could explain here how node.js and express would have to route for a multilanguage site? I'm using i18n-node for translation and folder like routing ( /es/, /de/ , etc ) for different languages. This all are static routes but I also have routes like apiRoutes.route('/user/profile') using 'app' at the begining ( app.get('/app/user/profile') so please consider this in your answer so is NOT necesary route to : app.get('/es/app/user/profile') .
having 15 routes like this now:
app.get('/terms', function(req, res) {
res.render('terms',{
...
});
});
how it have to be set for routes like:
app.get('/es/terms', function(req, res) {
res.render('terms',{
...
});
});
Should I duplicate this routes and add for example a locale for
each like:
app.get('/es/terms', function(req, res) {
res.render('terms',{
...
});
});
Or Should do something like:
if cookie['lang'] && cookie['lang'] is in locales
// then redirect to /:lang/terms
else
// show default language in /terms
if req.headers["accept-language"] && req.headers["accept-language"]
// then redirect to /:lang/terms
else
//show default language in /terms
Or there is another way I should approach this that follows good practices or is better respecting standards?
Miro's Answer in :
How can I get the browser language in node.js (express.js)? says I should use app.all('*', ...
Is this all I need?, ..still, it might have a syntax error or i'm not understanding well this two parts
var rxLocal = /^\/(de|en)/i;
...
app.get(/\/(de|en)\/login/i, routes.login);
thanks in advance
You need to consider 2 things :
1. How get the local :
Accept-Language
The HTTP protocole define the Accept-Language header to manage the local. This is a normalized method. You can access it with the req.acceptsLanguages method of express.
+Normalized
+Natively support by brower
-Not easy to by passe by the end user
Path / Cookies
You can get the local from the path. In express it can be do with a parameter patter like /:local/rest/of/path and retrieve in the request object with the req.param method.
You can also get the information from the cookies with the req.cookies properties (don't forgot to set it).
Both
To increase the user experience you can mix the both method. For exemple get the default language from the HTTP header send by the browser but permite to the user to override this in you application and store this parameter in the cookies.
2. Use the local:
Each methods to get the local can be used from different way. I will
use random of them in exemple but they are all compatible.
Top level configuration.
In case of you use a template Engine and you controller can be local agnostic. You can use a middleware to get the local information and configure the render engine.
app.use('/:local' (req, res, next) => {
let localKey = req.param('local');
res.locals = // Some ingenious method to get the locales from localKey
next();
}
Check res.locals and your engine documentation.
Use it in controller.
If the local is part of the contoller process. You can get directly is value in controller.
In case of you use a complexe method to determine the final value of the local, you can also use a middleware to determine this value and enrich the request with it.
app.use((req, res, next) => {
let local = req.cookies.local;
if(!local) local = req.acceptsLanguages();
if(!local) local = 'en-US';
req.local = local;
}
Both
You can use both method too. It depend of what you need. Find the best way to get a maintainable code and avoid replication for your use case.
When you use middle where witch impact the controllers, be sure you declare them before your routes.
You can use a route parameter to get the locale from the URL, like this:
app.get('/:lang/terms', function (req, res) {
if (req.params === 'es') {
res.send('¡Hola!');
else {
res.send('Hi!');
}
});
The colon character tells Express to put whatever is between the first to slashes of the path in req.params.lang.
See express routing documentation for details.

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.

How to Redirect to Single Page Web App in Express for Node

I am writing a website with a single page web app (the rest of the website is just static files which are served). I am trying to write a piece of middleware for express to redirect all requests that follow the pattern 'example.com/app' to 'example.com/app' so that requests such as 'example.com/app/my/specific/page/' will all result in the same page being sent. The key issue with this is that the url in the address bar of the browser must not change so that the javascript app itself can interpret it and display the correct thing.
I could have done something like this:
app.use( '/app', function ( req, res ) {
res.redirect('/app');
});
However, this causes the url of the page to change and a separate HTTP request is assumedly made.
The most obvious alternative solution is to do something like this:
app.use( '/app', function ( req, res ) {
res.sendfile(__dirname + '/public/app/index.html');
});
The issue here is that resources from the page after requests like 'example.com/app/my/specific/page/' will look in the wrong location. For example, if I have an image on the page such as then it will look for example.com/app/my/specific/page/image.jpg. Since no image is returned, it will not display on the page. This happens for all external scripts or stylesheets.
I also tried something like this:
app.use( '/app', function ( req, res ) {
res.sendfile(__dirname + '/public/beta' + url.parse(req.url).pathname);
});
but that was very stupid of me for obvious reasons.
In the end I used this middleware to serve the app's page when appropriate
// all unmatched requests to this path, with no file extension, redirect to the dash page
app.use('/dash', function ( req, res, next ) {
// uri has a forward slash followed any number of any characters except full stops (up until the end of the string)
if (/\/[^.]*$/.test(req.url)) {
res.sendfile(__dirname + '/public/dash/index.html');
} else {
next();
}
});
I then set used a base HTML element with the href attribute pointed to the root.
If you're still trying to accomplish this I may have found a starting point. Alexander Beletsky has a Backbone.js + Express SPA boilerplate repo Located Here.
For a brief article on how it came about you can read his article on Dzone.

Is it possible to apply basic authentication / middleware in on routes with a whitelist in Express?

I'm implementing a RESTful API with Express in Node, and I'm new to both. I'd like to use basic authentication to control access.
I would like to apply it using something like a whitelist but I'm not sure how to do that.
Blacklisting is easy, I can just pepper my #VERB calls with the second argument:
app.get('/', asyncAuth, requestHandler);
I can take that even further and blacklist everything with:
app.all('*', asyncAuth, requestHandler);
But I want to apply my basicAuth to every single route, except for POST /users. Is there an elegant way to do that? Can I use the 'blacklist' approach then selectively remove it from the routes I'd like? I couldn't figure out how.
Define your route for POST /users before the blacklisted routes:
app.post('/users', function(req, res) {
...
});
app.all('*', asyncAuth, requestHandler);
You could maintain a list of regexps that are whitelisted, and match the url against each url in the list, if it matches any then proceed, else require auth
app.all('*', asyncAuth);
function asyncAuth(req, res, next) {
var done = false;
whitelist.forEach(function(regexp) {
if (req.url.match(regexp)) {
done = true;
next();
}
});
if (!done) requireAuth(next);
}
Something along those lines

Resources