Express GET route will not work with parameters - node.js

I am new to Express and Mongoose. I am currently working on my first project, that is not a tutorial, and I has run into a problem.
I have multiple routes, they are defined in the index.js like this:
app.use('/api/client',require('./routes/client'));
app.use('/api/host',require('./routes/host'));
In the routes, there are multiple verbs that work, like PUT and POST.
Here is the problematic route (I am trying to do more that what is presented here, but what is presented here, does not work as well):
router.get('/ama/:id', function (req, res, next) {
Ama.findById(req.params.id).then(function(Ama){
res.send(Ama);
});
});
This should work, right? It should return the document in the database, with that id. And I have checked if the document excists, probably around a 100 times.
Now, if I simplify the route greatly, removing the id, and make a simple response, the route works:
router.get('/ama', function (req, res, next) {
res.send({type:"GET"});
});
It's so wierd, that as soon as i add the parameter, i get a:
<pre>Cannot GET /api/host/ama</pre>
in Postman.
Any ideas? Mongod is running, my other routes are working.

It looks like you're trying to retrieve this URL:
/api/host/ama?id=SOMEID
However, you have a route declared for URL's that look like this:
/api/host/ama/SOMEID
In other words, the id is part of the path of the URL, and not passed as a query string parameter (that's what /:id means: it's a placeholder for a part of the URL that the route should match).
So either change the request-URL by adding the id to the path (/api/host/ama/58e395a8c6aaca2560089c‌​e7), or rewrite your route handler to something like this:
router.get('/ama', function (req, res, next) {
Ama.findById(req.query.id).then(function(Ama){
res.send(Ama);
});
});
However, I would advise using the former (making the id part of the URL).

There are two problems here:
router.get('/ama/:id', function (req, res, next) {
Ama.findById(req.params.id).then(function(Ama){
res.send(Ama);
})
res.send(req.params.id)*/
});
First of all, res.send(req.params.id) will run before the res.send(Ama); and it will probably send the entire response. You are missing the .exec() method call (see the answer by Cédric De Dycker for details). The res.send() can only be reliably used once. Maybe you want res.write() instead if you want to wrte multiple things. Also you don't handle the promise rejection so you don't handle database errors. To know why you should always handle the promise rejections see this answer: Should I refrain from handling Promise rejection asynchronously?

The parameter should work fine but it seems you missed to add .exec to your query
Ama.findById(req.params.id).exec().then(function(Ama){
res.send(Ama);
})

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.

how to extract part of url server side in nodejs express

Currently working on a nodejs express server. And I think I'm doing something in an inefficient way. I have this route set up
app.get('/admin/scanTable/:table', require('./AUTH/ValidateCookie.js'), require('./AUTH/verifyURI.js'), require('./ROUTES/render.js'));
so the url here is /admin/scanTable/:table. I know I can get the whole path with req.route.path. I know I can use req.params.table to collect the table parameter. But the thing I don't know how to get is the first part of the path, in this case admin. I know I could get it by looking for / symbols and slicing the parts I need from req.route.path but I figure with all these functionalities that express has, there's probably a better way of doing this.
I know I can use
app.use('/admin', function(req, res, next){console.log('admin called'), next();});
to check if this part of the uri was called to then execute some code, but it's not really what I want. Can anyone tell me the easiest way to find this? At the moment I have attached a variable to req.string whenever app.use('/admin' is called it will attach the string admin to this variable which then makes it available to all other functions that are called. But even this feels like overkill. Any Ideas?
Both options you describe are valid and straightforward:
Using a regex on req.route.path, a la /^admin/.test(req.route.path)
Using middleware to attach a new property to the req object, a la
app.use('/admin', function(req, res, next){ req.adminRoute = true; next();});
or if you need to do this same thing for all admin routes, do it once:
var adminRouter = require("express").Router();
router.get("/scanTable/:table", require("./AUTH/ValidateCookie.js"), ...);
router.use(function (req, res, next) { req.adminRoute = true; next(); }));
app.use("/admin", adminRouter);
I don't know the context of your application, but I would consider using the last example, and putting anything else that's specific to /admin routes as middleware also.

What to do when one route "blocks" another?

I'm using nodejs (with sailsjs), and I'm having an issue with routing, here is the case:
I have one route that handles the url '/user/?variable'. It links to
a controller action that shows a profile, depending on the variable
given; if no user is found, it returns a 404 error.
I have a second route that handles '/user/find'. It is linked to a
controller action meant for an AJAX request that returns the user's
id given the variables passed to it.
However, when I call '/user/find/' with the AJAX request, then I get the 404 error; I guess this is because it still links to the "show profile" action, and the action can't find an user named "find".
Is this conflict common among frameworks? Are there ways to solve this? I've tried switching the order in which I declare the routes, but the response is the same. I guess it would probably cause conflict too if an user signs up with username 'find', in that case, how would I handle it? Or should I just use a completely different route?
I like /user/find because the name is very straightforward, though.
Thank you.
When you declare your routes in your app.js or whatever file you file order matters.
app.get("/user/find", function (request, response) {
//do something
});
app.get("/user/:variable", function (request, response) {
//do something
});
In the above example /user/find takes precedence over /user/:variable because it is declared first. If you need to do this I would suggest playing with the order of the declarations. If you switch it to the following it should work.
app.get("/user/:variable", function (request, response) {
//do something
});
app.get("/user/find", function (request, response) {
//do something
});

Express route parsing

I'm trying to create a route for the following URL:
http://localhost:5000/api/querystring?parameter1=value1&parameter2=value2
My route looks like this:
app.get('/api/:querystring/:parameter1?/:parameter2?', function(req, res) {
// do stuff
})
How can I create a route that matches the given URL?
You can't include query string parts in the route ... you will have to leave them off.
app.get('/api/querystring' ...
Then in the callback you can look at req.query to see the parameters. If you were to compare to the query, the order of the query string parameters would matter. It shouldn't.
If you want /api/querystring?parameter1=foo and /api/querystring?parameter2=bar to use different routes, you will have to handle this by calling separate functions within the app.get route callback above.

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