REST method GET for searching by criteria as json fro mongodb - node.js

I have an nodejs server with express and mongoose and I'd like to use method GET for search accoring to criteria which I'd like to provide as JSON object does anyone can help me how to implement it?
Or maybe should I use POST or PUT to make it?

http://hostname/modelname?criteria1=1&criteria2=2
router.route('/modelname')
.get(function (req, res, next) {
req.query.criteria1 === 1 // true
req.query.criteria2 === 2 // true
});

If you are unsure of what HTTP VERB you'd want to use,
POST - is primarily used for creating resources on the server
PUT - is used to update an existing resource
GET- to retrieve a resource
I would use GET in this case
GET http://myhost.com?q=word1+word2+word3+word4
app.get('*', function(req, res) {
// do something with the req.query.q array
});

You've got two options - using HTTP GET params or encoding whole criteria as JSON string and passing that string.
First option, by using params:
?crit[foo.bar][$eq]=abc&crit[foo.baz][$ne]=def
You can read it in nodejs/express via req.query.crit. But this is bad idea because there's no way of retaining data types. For example number 1 becomes string "1". Don't use it - MongoDB is data type sensitive so query {"foo.bar":{$eq:1}} is completely different from {"foo.bar":{$eq:"1"}}
Second option is to urlencode JSON criteria:
?critJSON=%7B%22foo.bar%22%3A%7B%22%24eq%22%3A%20%22abc%22%7D%2C%22foo.baz%22%3A%7B%22%24ne%22%3A%20%22def%22%7D%7D
And parse it on nodejs/express side:
var crit = JSON.parse(req.query.critJSON)
This way your data types are retained and it will work as expected.

Related

Express: req.params vs req.body (JSON)

Which is more correct, and why? Does it depend on the scenario? Is there a standard?
router.post("/user", function(req, res) {
let thisUserId = req.body.userId;
});
router.post("/user/:userId", function(req, res) {
let thisUserId = req.params.userId;
}
Thanks!
This question is more about RESTful API conventions than node or express. Based on generally accepted REST conventions, this is basic CRUD operation:
/* fetch all users */
GET /users
/* fetch specific user */
GET /users/:userId
/* create new user */
POST /users
/* edit specific user */
PUT /users/:userId
/* delete specific user */
DELETE /users/:userId
So in your case I would say req.body is more appropriate, considering you want to create a user.
EDIT: another useful resource that supports this case: 10 best practices for better RESTful API.
req.body is used to access actual form data that you 'posted'.
req.params is used for route parameters, in your case userId which is passed in the parameters:
router.post("/user/:userId", function(req, res) {
let thisUserId = req.params.userId;
}
The official docs:
req.body
Contains key-value pairs of data submitted in the request
body. By default, it is undefined, and is populated when you use
body-parsing middleware such as body-parser and multer.
Link to req.body docs
req.params
This property is an object containing properties mapped to
the named route “parameters”. For example, if you have the route
/user/:name, then the “name” property is available as req.params.name.
This object defaults to {}.
Link to req.params docs
If you want to implement guards or any other logic in your route that relies on that id (of an existing user), you pass the userID in the params.
Let's say you are submitting a form where a new user registers.. You don't want to send the credentials in the parameters since it's confidential data and easily accessible this way. Here it makes sense to put those values in the request-body and use therefore req.body..
As Haris Bouchlis already mentioned in his answer it depends on your CRUD-ops that you like to perform.
In this case I advice to use req.params.userId.
Normal API entries have this standard. To get all the users the path will be '/users'.
To retrieve or update a specific user, the path will be '/users/1'.
API example
Yes there are completely different and used for the different purpose
1.req.params comes from path segments of the URL that match a parameter in the route definition such a /song/:songid. So, with a route using that designation and a URL such as /song/48586, then req.params.songid === "48586".
2.req.body properties come from a form post where the form data (which is submitted in the body contents) has been parsed into properties of the body tag.

how to fetch req.params whatever it was

I'm working on a url shortener api. The problem i'm facing is that if I pass a parameter like https://www.youtube.com/watch?v=8aGhZQkoFbQ then req.params.url will only be equal to https://www.youtube.com/watch. I've looked a lot on stackoverflow and all the answers are similar but not what I'm looking for.
I want to parse the url parameter and get the characters it contains.
This is the URI i'm using right now
router.route('/add/:url(*)')
You can try something like this:
app.get(/[/]add[/].*/, function (req, res) {
var uri = req.originalUrl.replace(/^[/][^/]*[/]*/, '');
console.log(uri);
res.end();
});
Maybe you're wanting the query part of the URL? Take a look at req.query docs (and other parts of the request) and read about the parts of the URI or more formal definitions on wikipedia. Having the correct names will help you understand the Express.js docs.
From express.js docs:
// GET /search?q=tobi+ferret
req.query.q
// => "tobi ferret"
From wikipedia:
scheme:[//[user:password#]host[:port]][/]path[?query][#fragment]

Handle diff content type in node application

I am developing a api in nodejs which will consume by different application. different application will make call with different content type. I have use the body-parser to parsing req data.
I like to have some middleware to handle the content type and convert data in consistent format so that my controller will work properly.
If if got the call with the 'text/plain;charset=UTF-8' then before calling my controller i have to parse data to json format.
also i have to add some encoding before sending data. in same function i will decode the my data also
please help me to fix this issue.
add this function to server.ts to handle the different response type
app.use(function(req, res, next) {
if (req.headers['content-type'] == "text/plain;charset=UTF-8") {
req.body = JSON.parse(req.body)
}
return next();
});

Overloading functions for an api in node - Best practice?

I'm currently building a small express powered node app to power a RESTful API exposing data from a node module I wrote. One of the functions in the module takes three arguments, but I want to allow the usage of the API by specifying just one, two, the other two or all three arguments.
So even starting to write the routes like this already feels ridiculous.
app.get('/api/monitor/:stop/:numresults', apiController.monitorNum);
app.get('/api/monitor/:stop/:timeoffset', apiController.monitorOff);
app.get('/api/monitor/:stop', apiController.monitor);
Especially since I don't know how to specify the difference between the first two, as numresults and timeoffset are both just integers.
What would a best practice in this situation look like?
The first problem you face is that you have identical routes, which are not possible if you're using express (I'm assuming that's what you're using). Instead you probably want one route and utilise the query object instead:
app.get('/api/monitor/:stop/', function (req, res, next) {
var stop = req.params.stop,
numResults = req.query.numResults,
timeOffset = req.query.timeOffset;
yourFunc(stop, numResults, timeOffset);
});
That way you can call the api with the following url: http://example.com/api/monitor/somethingAboutStop/?numResults=1&timeOffset=2. It looks like the stop parameter can also be moved to the query object but it's up to you.
You can use a catchall route then parse it yourself.
Example:
app.get('/api/monitor/*', apiController.monitor);
Then in apiController.monitor you can parse the url further:
exports.monitor = function(req, res) {
var parts = req.url.split('/');
console.log(parts); // [ '', 'api', 'monitor', '32', 'time' ]
console.log(parts.length); // 5
res.end();
};
So, hit the /api/monitor/32/time, and you get that array above. Hit it with /api/monitor/something/very/long/which/you/can/parse and you can see where each of your params go.
Or you can help yourself, like /api/monitor/page/32/offset/24/maxresults/14/limit/11/filter/by-user
Though, as Deif has told you already, you usually do pagination with query parameters, maxResults & page being your usual params.

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