How can I re-parse req.url from inside a middleware function? - javascript

I have a middleware function that takes a query string value and turns it into
I am using Express 4 and Node.js. I have a route defined for /:module/:page.aspx and am using req.params and req.query values across a number of middleware functions.
app.get('/:module/:page.aspx', catchEncodedQuery, doSomeStuff, doOtherStuff);
I have one middleware function that appears first, which catches certain requests which have a query string value that can be transformed into a new req.url that I set for use further on in the middleware chain. Basically, I want to proceed as though the un-encoded form of this query string value was the request URL the whole time.
function catchEncodedQuery(req, res, next) {
if (
// req meets some specific criteria
) {
req.url = myUnencodeFunction(req.query.url_str);
next();
} else {
next();
}
};
But I would also like req.params and req.query to reflect this new URL. I could just parse the new URL myself and reassign these values to req.params and req.query, but I'm wondering if there's a better way to do this that leverages Express's existing URL-parsing functionality.

Related

How to route through a path and perform different functionality at different URLs?

I would like to post at the path /users and then immediately post to /users/:id, but the actions need to be different at each of these URLs, so I can't use the array method for applying the same middleware to different URLs
The idea is that POST(/users/:id, ...) will never be called by the client. It only gets called immediately after POST(/users, ...)
When using express, you are providing a handler function for a specific endpoint. Actually it's an array of those functions (middlewares). That means that you can switch from :
route.post('/users/`, (req, res, next) => {
// do your magic
});
to
route.post('/users/', handleMyCall);
This way you can easily reuse those functions in multiple endpoints without your need to actually make requests:
route.post('/users/', (req, res) => {
// do something +
handleMyCall(req, res);
// either return the result of this call, or another result
});
route.post('/users/:userID', (req, res) => {
// do another operation +
handleMyCall(req, res);
});
Update:
Using GET or POST differs in the way the data is sent to the server. You can use both for your cases, and it really depends on the testing client you have.
Typically, a GET request is done to query the database and not do any actions. POST is usually used to create new entities in the database.
In your scenario, I'd guess you would have post('/users/) in order to create a user. And then have get('/users/:userID') to find that user and return it to the client.
You can easily have different endpoints with different handles for those cases.
As I understood from the comments, you'll need a POST request on /users (to persist data in some database) and GET /users/:id to retrieve these data, which is very different from POSTing the same thing on 2 different endpoints.
POST is generally used to persist and GET to retrieve data.
I'll assume you use some kind of NoSQL DB, perhaps MongoDB. MongoDB generate a unique ID for each document you persist in it.
So you'll have to have 2 routes :
const postUser = async (req, res, next) => {
try {
// persist your user here, perhaps with mongoose or native mongo driver
} catch (e) {
return next(e);
}
}
const getUserById = async (req, res, next) => {
try {
// get your user here thanks to the id, in req.params.id
} catch (e) {
return next(e);
}
}
export default (router) => {
router.route('/users').post(postUser);
router.route('/users/:id').get(getUserById);
};

Nodejs + Express: How to get an element which made an HTTP GET request?

I am making a front using Express. I have a table where each row has a link that makes a GET request, so that the back-end (done with node.js) returns a file corresponding to that row.
All links make the url GET request like "/documents/table/file".
What I intend to do is for my express server to be able to know which link of what row makes the GET request with the req field of it in order to be able to return the corresponding requested file.
The request is being handled in my express server as follows:
router.get('/documents/table/file', async (req, res) =>{
//Get which element made the get petition
});
As I said before, I intend to know what link from which row of the table performs a request using the req field.
You need to pass the information about the row/item that makes the GET request, that is a must.
Now with Express there are a couple of ways to do this: Express routing.
1. Defining route params: req.params
GET Request: /documents/table/file/345 (345 is the row identifier name or id etc)
At nodejs express end:
router.get("/documents/table/file/:id", (req, res) => {
/*request parameter with this kind of route sits in req.params*/
console.log(req.params);
const requestedId = req.params.id;
});
2. Sending as query string parameters: req.query
GET Request: /documents/table/file?id=345
At nodejs express end:
router.get("/documents/table/file/", (req, res) => {
/*request parameter with this kind of route sits in req.query*/
console.log(req.query);
const requestedId = req.query.id;
});
The short version is: you can't know this.
The way this is normally handled that if a request is needed for a specific item (or row in a table), you need to add some relevant information to the url that can identify it yourself.
So if it's a GET request for /foo/get-file, and every 'file' has some kind of unique id, you might want to change your url to /foo/get-file/123 or /foo/get-file?id=123
Do you want to access specific file using get command? If so, here's an answer - Express router - :id?.
More precisely, you write something like router.get('/documents/table/file/:id), and this :id is available in req.params object.

Node Express app.get(*) req.url is always /favion.ico

I have an Express server, where my app is served from the app.get('*') route.
I'd like to have users with promo codes visit the site from a campaign URL like so: www.mysite.com/?code=123.
The problem is every browser request is routed to the favicon request, thus my req.url and req.query variables cannot be used to get the promo codes. Req.url is always /favicon.ico and req.query is always empty.
I did find the original URL is the request object's header, but this seems like a roundabout way of achieving my objective. The request object's original URL field also points to favicon.ico.
app.get('*', (req, res) => {
console.log(req.url);
console.log(req.query);
}
I'd like to keep my promo code solution as quick and dirty as possible for the time being, so I'm fine with URL parameters. Is there a simple solution to extract the original URL query parameters without diving into the headers?
EDIT: I'm now sharing my root request handler below. The favicon request is handled by the express-favicon middleware earlier in the code.
app.get('*', (req, res) => {
console.log("In get *");
console.log("Req.url: ",req.url);
console.log("Promo code: ",req.query.promo);
const context = {};
const app = ReactDOMServer.renderToString(
<StaticRouter location={req.url} context={context}>
<App />
</StaticRouter>
);
const indexFile = path.resolve('./public/index.html');
fs.readFile(indexFile, 'utf8', (err, data) => {
if (err) {
console.error('Something went wrong:', err);
return res.status(500).send('Oops, better luck next time!');
}
return res.send(
data.replace('<div id="root"></div>', `<div id="root">${app}</div>`)
);
});
})
The problem is that I'm using React Router, which doesn't support query parameters:
https://reacttraining.com/react-router/web/example/query-parameters
To get aroud this, I'm using window.location.search on the client to get the promo code, then passing to the backend with an explicit promo handler.
You can accept dynamic value as part of the URL in express
api call ==> www.mysite.com/dynamic_promo_code
app.get('/:promo_code',(req,res)=>{
// req.params will be and object holding your dynamic promo_code
const promo = req.params.promo_code; // this will be your dynamic promo code
});
if you wish your promo code is opitional and don't want to be part of URL
api call ==> www.mysite.com?promocode=dynamic_promo_code
app.get('/',(req,res)=>{
//req.query is an object holding your optional parameter
const code = req.query.promocode; // this will be yor dynamic promo code
})

Is it possible to reassign req.params in express?

I'll start with some context:
I have a RESTful API Server that includes routes for managing users; e.g.
PUT .../users/:id/profile
As part of our authentication flow we verify the user's identity and compare the id in the url with the id retrieved from our IDP.
What I'm trying to do is implement a 'me' replacement approach; where a user, instead of providing their id in the url, can simply provide 'me' instead, and the id is reassigned with id retrieved from the IDP based on their authentication. I've seen Google do this for some of their APIs. E.g.
.../users/me/profile
So far I've been attempting a simple replacement with the assumption that a modified req.params will propagate forward:
req.params.id = req.params.id === 'me'
? session.id
: req.params.id
This wasn't working so I did a bit of reading up on it and apparently req.params gets built with each middleware function (when .use() is called), so reassigning req.params.id doesn't propagate throughout the app as I had hoped.
Currently all our business logic pulls the id from req.params so I was wondering if there's a way to get the above behaviour to work to avoid refactoring all my business logic?
I understand that req.params is built from parsing the url; so would modifying the url be an option?; to replace 'me' with the id; so that req.params is populated as intended? If so, how could this be achieved?
Or, if you have a nicer alternative to getting the above 'me' replacement behaviour to work then I'm all ears!
Global middleware (that you add using app.use() or router.use()) is typically not even aware of any route handlers that declare parameters, so req.params usually isn't even populated.
A solution would be to "inline" the modifying middleware:
app.put('/users/:id/profile', middleware, ...)
But that would require rewriting all your route handlers.
As you already point out correctly, you can modify the URL:
app.use(function(req, res, next) {
if (req.url === '/users/me/profile') {
req.url = '/users/1234/profile';
}
next();
});
app.put('/users/:id/profile', ...)
Instead of having to match each URL specifically, you can perform substring matches, or use a list of all URL's that may contain an :id parameter (and therefore, may contain the me identifier).
I just realized that this should work (using req.param()):
router.param('id', function(req, res, next, id) {
if (id === 'me') {
req.params.id = '1234';
}
next();
});
This should be added to routers that declare parameters, either in route handlers directly, or in mountpoints.
A convoluted example:
let childRouter = express.Router({ mergeParams : true });
childRouter.put('/profile', ...);
let parentRouter = express.Router({ mergeParams : true });
parentRouter.use('/:id', childRouter);
parentRouter.param('id', function(req, res, next, id) {
if (id === 'me') {
req.params.id = '1234';
}
next();
});
app.use('/users', parentRouter);
Because parentRouter declares a mountpoint /:id, it should get the resolving function.

What javascript library sets the _parsedUrl property on a request object

I am working with node/express/passport/ looking at code that attempts to use a request like:
req._parsedUrl.pathname;
I cannot figure out where this variable is coming from. Is this a canonical variable name that is set in a common .js library? It doesn't seem exposed in any headers.
req._parsedUrl is created by the parseurl library which is used by Express' Router when handling an incoming request.
The Router doesn't actually intend to create req._parsedUrl. Instead parseurl creates the variable as a form of optimization through caching.
If you want to use req._parsedUrl.pathname do the following instead in order to ensure that your server doesn't crash if req._parsedUrl is missing:
var parseUrl = require('parseurl');
function yourMiddleware(req, res, next) {
var pathname = parseUrl(req).pathname;
// Do your thing with pathname
}
parseurl will return req._parsedUrl if it already exists or if not it does the parsing for the first time. Now you get the pathname in a save way while still not parsing the url more than once.
You can write a middleware to handle then set properties for req.
var myMiddleWare = function () {
return function (req, res, next) {
req._parsedUrl = 'SOME_THING';
next()
}
};
app.get('/', myMiddleWare, function (req, res) {
console.log(req._parsedUrl); // SOME_THING
res.end();
})
Express middleware document in here

Categories