How to send integers in query parameters in nodejs Express service - node.js

I have a nodejs express web server running on my box. I want to send a get request along with query parameters. Is there any way to find type of each query parameter like int,bool,string. The query parameters key value is not know to me. I interpret as a json object of key value pairs at server side.

You can't, as HTTP has no notion of types: everything is a string, including querystring parameters.
What you'll need to do is to use the req.query object and manually transform the strings into integers using parseInt():
req.query.someProperty = parseInt(req.query.someProperty);

You can also try
var someProperty = (+req.query.someProperty);
This worked for me!

As mentioned by Paul Mougel, http query and path variables are strings. However, these can be intercepted and modified before being handled. I do it like this:
var convertMembershipTypeToInt = function (req, res, next) {
req.params.membershipType = parseInt(req.params.membershipType);
next();
};
before:
router.get('/api/:membershipType(\\d+)/', api.membershipType);
after:
router.get('/api/:membershipType(\\d+)/', convertMembershipTypeToInt, api.membershipType);
In this case, req.params.membershipType is converted from a string to an integer. Note the regex to ensure that only integers are passed to the converter.

This have been answered a long ago but there's a workaround for parsing query params as strings to their proper types using 3rd party library express-query-parser
// without this parser
req.query = {a: 'null', b: 'true', c: {d: 'false', e: '3.14'}}
// with this parser
req.query = {a: null, b: true, c: {d: false, e: 3.14}}

let originalType = JSON.parse(req.query.someproperty);
In HTTP, querystring parameters are treated as string whether you have originally sent say [0,1] or 5 or "hello".
So we have to parse it using json parsing.

//You can use like that
let { page_number } : any = req.query;
page_number = +page_number;

Maybe this will be of any help to those who read this, but I like to use arrow functions to keep my code clean. Since all I do is change one variable it should only take one line of code:
module.exports = function(repo){
router.route('/:id',
(req, res, next) => { req.params.id = parseInt(req.params.id); next(); })
.get(repo.getById)
.delete(repo.deleteById)
.put(repo.updateById);
}

Related

How do I convert Express query parameters back into a string?

Express is great with req.query and creating an object of the query parameters. In this case, I just want those query parameters as a string. This is how I did it:
router.get('/*', (req, res) => {
const { originalUrl } = req;
console.log(originalUrl.slice(originalUrl.indexOf('?')));
But, I was wondering if there was a more direct or declarative way to do this. Surely this is not too uncommon of a task?
new URL("s://" + req.url).search gives you the query parameters, including the leading ?.

Node Express - How to support encoded url query string

Using node v6.2.0, express 4.14.0.
When entering site url as: 'http://site.name/?key=value', I'm able to get the query value by:
app.get('/', function (req, res) {
// req.query.key equals 'value'
});
But when entering encoded url: 'http://site.name/?key%3Dvalue', the req.query object looks like this:
{ 'key%3Dvalue' : '' }
Is there a way to make node req.query to parse the url correctly?
If no, what is the preferred method to extract this query value?
As understood from the comments, the parsing is correct and it shouldn't decode %3D to key delimiter.
In this case there was already clients in the wild that tried to reach the address in encoded url (because of client bug).
so I've added a temporary handler on the server to parse the '%3D' as '='.
const value = req.query.key ||
url.parse(req.url.replace('%3D', '='), true).query.key;
When the clients will rollout a new version with a fix, I could remove this handler from the server and use only req.query.key as it should be.

Single express route to capture all possible params combinations

I want my API to support filtering on the different properties of my mongodb model. The brute force way of which I would use:
app.get('/api/thing/:id', thing.getThingById);
app.get('/api/thing/:name, thing.getThingByName);
app.get('/api/thing/:name/:color', thing.getThingByNameAndColor);
etc. This approach is obviously terrible. How can I add a single route to capture multiple params so that I can return things using something like
exports.getThingByParams = function (req, res, next) {
var query = thingModel.find (req.params);
query.exec (function (err, things) {
if (err) return next (err);
res.send ({
status: "200",
responseType: "array",
response: things
});
});
};
Use the URL query string. It's a set of name/value pairs invented for precisely this use case. It still works great after all these years despite current trends the everything must be in the path portion of the URL instead of the query string because ???. Look at your route - it even says "API" in it. It doesn't need to abuse the path to be "pretty" according to hipsters.
app.get('/api/thing', thing.search);
exports.search = function (req, res, next) {
//Remember any ID values need to be converted from strings to ObjectIDs,
//and there's probably additional sanitization/normalization to do here
var query = thingModel.find (req.query);
query.exec (function (err, things) {
if (err) return next (err);
res.send ({
status: "200",
responseType: "array",
response: things
});
});
};
Then the url to find a red thing named candy would look like
/api/thing?color=red&name=candy
Yup, you can. Just use the most explicit route example:
app.get('/api/thing/:name/:color', thing.getThingByProperty);
and inside getThingByProperty simply test for req.params.YourParam (name or color) and decide what to do. If color is requested but not name, you send in the url as follows:
/api/thing/-/red.
Very common sighting to have null params in routes expressed as dash.
OR, different approach, better pattern more API like (RESTFul) is:
/api/thing/:id that's by id and to offer pattern support
and for different property search use:
/api/things/search?property1=value&property2=value
That way you respect the collection pattern in your API (/api/things) and put the search in the query to keep it flexible. Test inside the search callback for req.query.property1 or property and act accordingly

Modify Node.js req object parameters

So as usual, I tried to find this question on SO but still no luck.
I am aware that the answer is "Yes, you CAN modify the req object" but nothing is said about the req object parameters.
For example the following code will throw an error:
app.get('/search', function(req, res) {
req.param('q') = "something";
});
Error:
ReferenceError: Invalid left-hand side in assignment
I imagine this has something to do with the property not having a 'SET' method or something along those lines.
There are a few scenarios where this could come in handy.
A service that turns quick-links into full blown requests and proxies those out.
Simply modifying the parameters before sending it off to another function that you have no desire to modify.
Onto the question, Is there a way to modify the req object parameters?
Rather than:
req.param('q') = "something";
You'll need to use:
req.params.q = "something";
The first one is trying to set a value on the return value of the param function, not the parameter itself.
It's worth noting the req.param() method retrieves values from req.body, req.params and req.query all at once and in that order, but to set a value you need to specify which of those three it goes in:
req.body.q = "something";
// now: req.param('q') === "something"
req.query.r = "something else";
// now: req.param('r') === "something else"
That said unless you're permanently modifying something submitted from the client it might be better to put it somewhere else so it doesn't get mistaken for input from the client by any third party modules you're using.
Alternative approaches to set params in request (use any):
req.params.model = 'Model';
Or
req.params['model'] = 'Model';
Or
req.body.name = 'Name';
Or
req.body['name'] = 'Name';
Or
req.query.ids = ['id'];
Or
req.query['ids'] = ['id'];
Now get params as following:
var model = req.param('model');
var name = req.param('name');
var ids = req.param('ids');
One can also imagine that the left-hand side is not a variable or property, so it makes no sense to try to assign a value to it. If you want to change a query param you have to modify the property in the req.query object.
req.query.q = 'something';
The same goes for req.body and req.params.

Backbone.js/express.js parameters for model.save()

I'm using Backbone.js on the client and node.js on the backend, and I'm having a bit of trouble doing a 'limited' model save, as explained here : http://backbonejs.org/#Model-save
As in the example, if I do
book.save({author: "Teddy"});
how do I access the parameters of the save using express.js, i.e. the fact that I only want to save to the 'author' field? I've tried the following
req.body -> gives ALL parameters of the model being saved, I want only the 'author' field
req.query -> empty
Any help much appreciated!
As stated in Model.save documentation:
save model.save([attributes], [options])
[...] The attributes hash (as in set) should contain the attributes you'd like to change —
keys that aren't mentioned won't be altered — but, a complete
representation of the resource will be sent to the server.
You can however override the save method and provide a data attribute via the options which will be sent to the server instead of the full model representation. For example, this will only save the attributes passed to the method :
var M = Backbone.Model.extend({
save: function (attrs, options) {
options || (options = {});
options.contentType = 'application/json';
options.data = JSON.stringify(attrs);
Backbone.Model.prototype.save.call(this, attrs, options);
}
});
And a Fiddle http://jsfiddle.net/dLFgD/
As #mikebridge noted in the comments, this behavior can now be obtained by passing an attrs option. So either use
book.save(null, {
attrs: {author: "Teddy"}
});
or keep the override
var M = Backbone.Model.extend({
url: '/echo/json/',
save: function(attrs, options) {
options || (options = {});
options.attrs = attrs;
Backbone.Model.prototype.save.call(this, attrs, options);
}
});
http://jsfiddle.net/nikoshr/dLFgD/7/
You could also send a PATCH request if you're using a Backbone version that supports it (>=0.9.9) and your server understands that verb, as explained in #pkyeck's answer
with the current version of Backbone (1.1.0) you could also do a PATCH which only sends the changed attributes to the server.
If instead, you'd only like the changed attributes to be sent to the server, call model.save(attrs, {patch: true}). You'll get an HTTP PATCH request to the server with just the passed-in attributes.
taken from here: http://backbonejs.org/#Model-save
in your case this would be:
book.save("author", "Teddy", {patch: true});
The best way I have found to access POST parameters is to use the bodyParser middleware. This is referenced at this question: How to retrieve POST query parameters?
/* On startup, register the bodyParser middleware */
app.use(express.bodyParser());
/* Then, during route execution, each parameter can be accessed with req.param */
app.post('/author/:id', function(req, res) {
var author = req.param('author', null); // Second parameter is default.
...
});

Resources