Why express.js does not route binary file? - node.js

I have a file I want to access at the following URL:
http://127.0.0.1:400/db/signal/test.xlsx
And I have the following GET handler in my Express app:
app.get('/db/signal/', function (req, res) {
// handle route
});
When I browse to http://127.0.0.1:400/db/signal/, the handler is executed. But when I browse to http://127.0.0.1:400/db/signal/test.xlsx the handler fails to execute. Why?
I'm using Express version 4.
Thanks for your reply.

Express uses path-to-regexp to match paths. If you take a look at the API, you'll see that the string '/db/signal/' will only match exactly that path; it won't match any subpaths. To match that path and any subpath, just append an asterisk, like so:
app.get('/db/signal/*', (req, res) => { ... });
You can see more examples of matching patterns in the Express routing guide.

Related

Express route: some routes are not recognised [duplicate]

I'm trying to wrap my head around my implementation of express.router() not triggering of the middleware function assigned to it.
I wrote a pretty big app and trying to add a few more endpoints to my path, but for some reason the 9th route gets loaded but does not trigger the function.
app.js
server.use(cors());
server.use(function (req, res, next) {
next();
});
server.use("/", express.static("./assets"));
server.use("/api", api);
server.use("/debug", debug);
server.use("/config", config);
server.use("/control", control);
server.use("/tools", files);
And this is where I declared my routes with the respective functions.
router.get("/teams", onGetTeams);
router.get("/players", onGetPlayers);
router.get("/achievements", getTop3);
router.get("/xpression", onXprPayload);
router.get("/snapshot", onRequestSnapshot);
router.get("/round-timeline", onRequestTimelinePayload);
router.get("/:half", onRequestHalf);
router.get("/dashboard-message", onSetDashboardMessage);
router.get("/get-match-odds", getTeamOdds);
function getTeamOdds(req, res) {
console.log("Sent odds");
res.json(odds);
res.end();
}
When I make the request for the last route, the function does not get executed, and I get back a 200 response.
Is there something big I'm missing?
Thank you !
Your route definition here:
router.get("/:half", onRequestHalf);
is a wildcard route that matches ALL routes so none of the routes after it will get called unless that specific route calls next() to continue routing.
Top level wildcard routes are problematic for this reason. I would suggest avoiding them. There are temporary work-arounds like moving their definition to be the last top level route definition, but they can still be limiting for defining future routes because they are so greedy.
My recommendation would be to not make it a top level route:
router.get("/half/:half", onRequestHalf);
So, it won't conflict with the other top level routes and it essentially has it's own URL scope all to itself.

Function isn't being called in Node Js using REST API

I am writing a code in Node JS, which uses mustache for templating html and REST API as backend.
Here is my code that doesn't work.
function setupRoutes(app) {
const base = app.locals.base;
app.get(`${base}/search.html`,doSearchContent(app));
app.get(`${base}/:name`,doGetContent(app));
}
function doSearchContent(app) {
return async function(req, res) {
console.log("here");
}; };
When I run my program and go to base/search.html. It never calls the doSearchContent method.
Any idea why and how I can fix this?
EDIT: The doGetContent works as expected. It's when I run the search.html it doesn't
The express paths should be started with a leading slash. Please change your routes addition to something like this:
...
app.get(`/${base}/search.html`,doSearchContent(app));
app.get(`/${base}/:name`,doGetContent(app));
...
Express matches the path of http request against the 'path' provided for all routes to decide which routes must be called. Since the http paths always start with a slash, your routes also must specify those to match.
These lines
app.get(`${base}/search.html`,doSearchContent(app));
app.get(`${base}/:name`,doGetContent(app));
are not working as you expect. In Express routes we don't invoke functions directly. Instead, we either pass a name of a callback fucntion to invoke, that receives req and res params, or an anonymous callback. In your case it could be something like this:
app.get(`${base}/search.html`,(req, res) => {
console.log("It's alive!");
doSearchContent(app);
});
app.get(`${base}/:name`, (req, res) => {
doGetContent(app)
});
The express paths should be started with a leading slash.
This is not true
Have you added search.html file or used a template to build the HTML?
Make sure the template is being called and not the html file.
Other than that your code looks fine and it should work

ExpressJS sendFile() cannot send URL GET parameters

I'm new to Node.js and Express.js and its routing. It's all set up correctly and it all works except for the following code.
I tried the following code:
app.get("/game/*", function(req, res) {
res.sendFile(__dirname + "/public/game.html?gameId=" + /\/([^\/]+$)/.exec(req.url)[1]);
});
The goal was to send all requests with /game/{gameId} (where gameId is some number) to /public/game.html?gameId={gameId}.
It correctly gets the requests with /game/, gets the gameId parameter from the URL, and attempts to sendFile() it. However, the sendFile() does not work, saying:
web.1 | Error: ENOENT, stat '/opt/lampp/htdocs/papei/public/game/32'
I've searched this error, and I guess it has to do with a file not being found. The problem is, /public/game.html exists. If I remove the ?gameId... part in the sendFile(), then it works. But I guess the sendFile() is looking for an exact URL, and is not finding it.
Is there any way to send URL GET parameters using ExpressJS?
I think the problem is that sendFile tries to find an exact match (which your query parameters break) as you thought.
You could use express-static to serve the html page, and then redirect to it as needed like so:
app.get("/game/:gameid", function(req, res) {
// Not ideal, as it uses two requests
res.redirect('/game.html?gameId=' + req.params.gameid)
});
Or you could put the html inside a template and render it for the response e.g:
app.get("/game/:gameid", function(req, res) {
// Render the 'game' template and pass in the gameid to the template
res.render('game', {gameid: req.params.gameid})
});
Either way, you don't need to use a catch all route and regex to get query parameters, see req.params or req.query in the express documentation.
Hope this helps.

Express 4 route handling with named parameters and router.param()

Is there a clean way to handle key/value query params in Express 4 routes?
router.route('/some/route?category=:myCategory')
I want to detect the presence of 'myCategory' in this route and use router.param([name], callback) to handle the associated logic.
router.param('myCategory', function(req, res, next, id) {
/* some logic here... */
});
The above 'router.param()' works fine if I have a route like /some/route/:myCategory but fails if I use
router.route('/some/route?category=:myCategory')
Am I doing something wrong here, or is this not supported in the Express 4 router out of the box?
Express treats properties after a ? as query params. So for:
/some/route?mycategory=mine
you would have to use:
req.query.mycategory or req.query['mycategory']
See this for more examples.

Express Framework app.post and app.get

I am fairly new to the express framework. I couldn't find the documentation for application.post() method in the express API reference. Can someone provide a few examples of all the possible parameters I can put in the function? I've read a couple sites with the following example, what does the first parameter mean?
I know the second parameter is the callback function, but what exactly do we put in the first parameter?
app.post('/', function(req, res){
Also, let's say we want the users to post(send data to our server) ID numbers with a certain format([{id:134123, url:www.qwer.com},{id:131211,url:www.asdf.com}]). We then want to extract the ID's and retrieves the data with those ID's from somewhere in our server. How would we write the app.post method that allows us to manipulate the input of an array of objects, so that we only use those object's ID(key) to retrieve the necessary info regardless of other keys in the objects. Given the description of the task, do we have to use app.get() method? If so, how would we write the app.get() function?
Thanks a lot for your inputs.
1. app.get('/', function(req, res){
This is telling express to listen for requests to / and run the function when it sees one.
The first argument is a pattern to match. Sometimes a literal URL fragment like '/' or '/privacy', you can also do substitutions as shown below. You can also match regexes if necessary as described here.
All the internal parts of Express follow the function(req, res, next) pattern. An incoming request starts at the top of the middleware chain (e.g. bodyParser) and gets passed along until something sends a response, or express gets to the end of the chain and 404's.
You usually put your app.router at the bottom of the chain. Once Express gets there it starts matching the request against all the app.get('path'..., app.post('path'... etc, in the order which they were set up.
Variable substitution:
// this would match:
// /questions/18087696/express-framework-app-post-and-app-get
app.get('/questions/:id/:slug', function(req, res, next){
db.fetch(req.params.id, function(err, question){
console.log('Fetched question: '+req.params.slug');
res.locals.question = question;
res.render('question-view');
});
});
next():
If you defined your handling functions as function(req, res, next){} you can call next() to yield, passing the request back into the middleware chain. You might do this for e.g. a catchall route:
app.all('*', function(req, res, next){
if(req.secure !== true) {
res.redirect('https://'+req.host+req.originalUrl);
} else {
next();
};
});
Again, order matters, you'll have to put this above the other routing functions if you want it to run before those.
I haven't POSTed json before but #PeterLyon's solution looks fine to me for that.
TJ annoyingly documents this as app.VERB(path, [callback...], callback in the express docs, so search the express docs for that. I'm not going to copy/paste them here. It's his unfriendly way of saying that app.get, app.post, app.put, etc all have the same function signature, and there are one of these methods for each supported method from HTTP.
To get your posted JSON data, use the bodyParser middleware:
app.post('/yourPath', express.bodyParser(), function (req, res) {
//req.body is your array of objects now:
// [{id:134123, url:'www.qwer.com'},{id:131211,url:'www.asdf.com'}]
});

Resources