node api not receiving json data - angularjs

I am using angular to call into a node get api. "undefined" is being received by node for req.query.reqdata Am I supposed to parse the JSON on the server side? Any help will be greatly appreciated.
Client:
function playOrError(instrument, octave, scaletype, basenote) {
var reqdata = {
"instrument" : instrument,
"octave" : octave,
"scaletype" : scaletype,
"basenote": basenote
};
$http.get("/api/getfile", reqdata)
.then(
function(response) {
console.log("File request: " + response.data);
},
function(error) {
console.log("File request failed: " + error);
});
}
Server:
app.use(bodyParser.json())
app.use(bodyParser.urlencoded({
extended: true
}));
...
app.get('/api/getfile', function(req, res, next) {
console.log(req.reqdata)
var instument = req.query.instrument
console.log(instrument)
})

reqdata is only the variable name you are using on the client side, and is never seen by express. Rather, console.log(req.query); should log an object (which is the reqdata object you pass into it); This object should have the values you added to that reqdata object, like so:
{
"instrument" : instrument,
"octave" : octave,
"scaletype" : scaletype,
"basenote": basenote
}
Then you can get the instrument for example by doing req.query.instrument
This is similar to when you pass a variable into a function. Just because the variable is named something when you pass it as an argument doesn't mean the function will use the same name! In this case, reqdata is passed in as the req.query

I figured this one out. Bennett was close, but it needs the first value to be params. This way you can send a whole bunch of query parameters via object notation.
$http.get("/api/getfile", {params : reqdata})
I also ended up converting te GET into POST eventually.

Related

res.json converts object into array nodejs

I'm responding with a JSON in my routing with the following
app.get('/loginerr', function(req, res, next){
var message = req.flash('signupMessage');
res.json({'error' : message});
});
The message is a simple String type but the JSON object is sent inside an array like this:
{
"error": [
"The email is already taken"
]
}
As you can see there is a pair of brackets for an array in the response. How I get rid of them?
you can use this :
var message = req.flash('signupMessage')[0];
res.json({'error' : message});
I was not aware that the req.flash object is an array.
I just had to take the only and first element of the array:
res.json({'error' : message[0]});

mapping the response to corresponding request

I am making $http request to multiple environment and processing after I get all the responses. I am using the code below:
$q.all(Object.keys($rootScope.envs).map(request)).then(function(res){
var results = {};
for (var env in res) {
results[env] = res[env].data;
}
}, function(err){
console.error(err);
});
function request(env) {
return $http.get(callService.getDomainUrl()+'/'+$rootScope.envs[env]+ '/hosts.json');
}
The above code works fine, but the results object looks like below:
{
0: {data:{}},
1: {data:{}},
2: {data:{}},
3: {data:{}}
}
I want the corresponding response for each key and the results should be like
{
env1: {data:{//data for env1}},
env2: {data:{//data for env2}},
env3: {data:{//data for env3}},
env4: {data:{//data for env4}},
}
How to map the corresponding response to the key? Please let me know how to get this as this is asynchronous request. Should I have something from the API to know which env the API is coming from?
I think the simplest way would be to push the result handling into the request function, that way you still have the 'env' value in scope.
var results = {};
$q.all(Object.keys($rootScope.envs).map(request)).then(function(res){
// Do something with 'results' here.
}, function(err){
console.error(err);
});
function request(env) {
return $http.get(callService.getDomainUrl()+'/'+$rootScope.envs[env]+ '/hosts.json')
.then(function(res) { results[env] = res.data; return env; });
}
Another option would be to replace my return env with return [env, res.data] and then you can go back to creating the results object as in your original code.
The important thing here is to remember you can handle the $http.get promises individually as well as using the promises from the call to then in $q.all.

Trouble with $gt in mongoose

I've successfully queried what I'm trying to in the mongo CLI, with the following query.
db.catches.find({'weightTotal': {'$gte' : 150} })
However, when I try to send a query up from angular to the route as such (with a little more specificity):
Hatchery.getByLocation(
{
'x': $scope.y.x._id,
'city': place.data[0].city,
'weightTotal': {'$gte' : 150 }
})
I get the usual error when something blows up in mongoose:
TypeError: Cannot call method 'toString' of undefined
at ServerResponse.writeHead (http.js:1180:45)
at ServerResponse.writeHead (/Users/ShiftedRec/x/y/node_modules/express-session/node_modules/on-headers/index.js:53:19)
But more specifically (console logging the error)
{ message: 'Cast to number failed for value "{"$gte":150}" at path "weightTotal"',
name: 'CastError',
kind: 'number',
value: '{"$gte":150}',
path: 'weightTotal' }
I've gotten this to work by doing a .where in the route, but I'd rather fit everything in the query. It can keep my routes cleaner if I just pass what I need to into a query instead of doing conditional where statements based on permissions etc.
The route the query is passed to looks like this:
router.get('/', function (req, res, next) {
User
.find(req.query)
.populate('post')
.exec(function (err, data){
if (err) return next(err);
res.json(data);
});
});
req.query console logs into this:
{ x: '5581efdcc465c1ccd97a1f6b',
y: '5581efe2458256f5d9848ca7',
weightTotal: '{"$gt": 150}' }
I'm using Mongoose 4.0.1.
Any ideas?
GET requests queries are strings, so if you send this:
www.mysite.com/?data=1&weightTotal=5
You will get this (strings and not numbers):
{data: "1",
weightTotal: "5"}
In order to use the data you can parse it somehow, for example:
req.query.weightTotal = JSON.parse(req.query.weightTotal);
or if it's just a number, a faster parse is:
req.query.weightTotal = +req.query.weightTotal;
A smarter solution, if you are sending objects in your requests, will be to use POST and not GET.
Try converting the req.query.weightTotal string to an object first:
req.query.weightTotal = eval('(' + req.query.weightTotal + ')');
Check the demo below.
var obj = {
x: '5581efdcc465c1ccd97a1f6b',
y: '5581efe2458256f5d9848ca7',
weightTotal: '{"$gt": 150}'
}
obj.weightTotal = eval('(' + obj.weightTotal + ')');
pre.innerHTML = JSON.stringify(obj);
<pre id="pre"></pre>

Doing a GET passing a complex object with angular

I am using AngularJs and Resources module. I want to do a GET to obtain an object.. to do this GET I do not have to pass simply the ID to the server, but I should pass a complex object with different properties and values..
Here the code I am using:
$scope.getActivationStatus = function (event) {
event.preventDefault();
if ($scope.segui_attivazione_form.$valid) {
$scope.activationStatus =
new SeguiAttivazioneService
.seguiAttivazione()
.$get(
{
request: $scope.activationStatus
}, function () { });
}
};
On server side I have:
[HttpGet]
public IHttpActionResult GetActivationStatus(MyComplexObject request)
{
//I will do something here later...
return Ok();
}
The problem is that "request" arrive on server equals to NULL...
I have solved the problem passing two strings to the server... in this way:
$scope.getActivationStatus = function (event) {
event.preventDefault();
if ($scope.segui_attivazione_form.$valid) {
$scope.activationStatus =
new SeguiAttivazioneService
.seguiAttivazione()
.$get(
{
codiceFiscale: $scope.activationStatus.CodiceFiscale,
codiceRichiesta: $scope.activationStatus.CodiceRichiesta
}, function () { });
}
};
And server side:
[HttpGet]
public IHttpActionResult GetActivationStatus(string codiceFiscale, string codiceRichiesta)
{
return Ok();
}
In this way everything works... but I don't like this solution because I will have more than two input...
And this is a get, not a post (not a save, an update)...
How can I pass a complex object doing a GET?
Thank you...
It's best to use the POST method if you want to send data in the body of the request. While it's possible with Angular, some servers might ignore the body of GET requests.
This approach allows to send complex objects with arrays and sub objects:
Angular:
$http({
url: '/myApiUrl',
method: 'GET',
params: { param1: angular.toJson(myComplexObject, false) }
})
C#:
[HttpGet]
public string Get(string param1)
{
Type1 obj = new JavaScriptSerializer().Deserialize<Type1>(param1);
...
}
This is not an elegant solution but it works using HTTP GET:
$http.get(url + "?" + $.param(obj).replace(/%5b([^0-9].*?)%5d/gi, '.$1'))
It converts the complex object into a string with dot notation to define levels. Most of the server side frameworks like ASP.NET Core can bind it to complex objects.
This is an example of the string I send for a complex object:
StartDate=2021-06-11&EndDate=2021-06-11&TimeRange.TimeFrom.Time=07%3A00&TimeRange.TimeFrom.TimeFrame=AM&TimeRange.TimeTo.Time=10%3A00&TimeRange.TimeTo.TimeFrame=AM
Request body can only be sent by POST. With get you could at best URL Encode the OBJECT and then send it as query string params. But thats not the best solution to post some data to the server

How to make $resource accept array of strings (AngularJS)

I would like to make a request to a REST-service in which the query parameters contain an array of strings:
productRestService.getProductsInfo(productIdsArray,"id,name,rating").$promise.
then(function(productData) { // success: Produktdaten auslesen
updateProductList(productData);
}, function (error) {
console.log("Status: " + error.status);
});
The Resource-Service is as follows:
productRestService.getProductsInfo = function(productIds, properties) {
console.log('productRestService.getProductsInfo(): productIds' + productIds);
var productInfoResourceData;
var ProductInfoResource = $resource('/rest/products/productsInfo/:productIds/:properties',
{
productIds:'#productIds',
properties:'#properties'
}
);
productInfoResourceData = ProductInfoResource.query(
{
productIds: productIds,
properties: properties
}
);
return productInfoResourceData;
}
Calling the service results to an 404-Error, because the default behaviour of the $resource object is that it expects an array of an object when "query" is used.
How can I achieve that my $resoure-service will accept an array of strings? I tried to use "transformRequest" (see snippet below), but that did not work either.
{
query: {
method: 'GET',
isArray: true,
transformResponse: function (data, headers) {
var tranformed = [];
[].forEach.call(eval(data), function (d) {
tranformed.push({ name: d });
});
return tranformed;
}
}
}
A console.log within the function of the REST service productService.getProductsInfo shows the correct data that the service received:
["212999cc-063b-4ae8-99b5-61a0af39040d","17e42a28-b945-4d5f-bab1-719b3a897fd0","9307df3e-6e7a-4bed-9fec-a9d925ea7dc0"]
The URL is correct with the other REST-URLS and should look this way (and is being concatenated to the domain accordingly):
'/rest/products/productsInfo/:productIds/:properties'
EDIT:
The other functions within the productService responds in order, they do not use arrays but JSON objects and do not show unexpected behaviour.
(This was originally a comment, but it needed cleanly formatted code samples.)
I suspect your :productIds template parameter is getting filled into the template as "[object Object]". I've only seen your template URL, not the actual constructed URL, so I can't be sure.
If your server is expecting a URL where the :productsIds template parameter is JSON, like for example ---
rest/products/productsInfo/["id1","id2","id3"]/{"prop1":true,"prop2":false}
--- then try editing your getProductsInfo definition to something like this:
productRestService.getProductsInfo = function (productIds, properties) {
var ProductsInfo = $resource('/rest/products/productsInfo/:productIds/:properties', {
productIds: function () {
return angular.toJson(productIds);
},
properties: function () {
return angular.toJson(properties);
}
});
return ProductsInfo.query();
}
(Fair warning, I didn't test this code. It's just a quick edit of your example.)
This way, you're making sure that the parameter values are converting to the JSON that the server expects (if the server is expecting JSON in the URL, that is).

Resources