AngularJS HTTP error codes with $q.all()? - javascript

I have a bunch of http requests like this:
$q.all([$http({
method: 'POST',
url: urlOne,
headers: {Authorization: "Token " + jqToken}
}), $http({
method: 'POST',
url: urlTwo,
headers: {Authorization: "Token " + jqToken}
})])
.then(function (results) {
//do stuff
});
However urlOne and urlTwo (and a bunch of others) may under some conditions return 403. In this case everything just freezes and then() function is never executed. How can I handle 403 responses?
Thanks.

It sounds like you need to handle errors.
$q.all([...])
.then(
function (results) {
// Handle success
}, function (err) {
// Handle errors
});

Related

Nested API requests in a route node/express

I'm very new to coding and this is my first post here. My learning project is a website that uses an external CRM to store client data from web forms.
I have the storage part working fine, but can't figure out how to retrieve the data and pass it to a rendered page.
I need a route to do 3 operations, each operation works properly on it's own, I just can't figure out how to nest them so they happen in order.
Get details of a deal from the CRM
var options = { method: 'GET',
url: 'https://crm.com/dev/api/opportunity/' + req.params.id,
headers:
{ 'cache-control': 'no-cache',
'content-type': 'application/json',
accept: 'application/json',
authorization: 'Basic xxx' },
json: true };
request(options, function (error, response, body) {
if (error) throw new Error(error);
return body.contact_ids;
});
this will return an array of client numbers associated with the deal.
Iterate through the client numbers to look up data from each client, and put to array. I have defined an empty array called data, outside the function scope to catch the results.
resultFromAboveRequest.forEach(function(id) {
var options = { method: 'GET',
url: 'https://crm.com/dev/api/contacts/' + Number(id),
headers:
{ 'cache-control': 'no-cache',
'content-type': 'application/json',
accept: 'application/json',
authorization: 'Basicxxx' },
json: true };
request(options, function (error, response, body) {
if (error) throw new Error(error);
data.push(body);
});
});
render the resultant data array on a page
res.render("./applicants/resume", {data: data});
I'm pretty sure this is a job for promises, however i just can't seem to get my head around the syntax. Any help would be appreciated and I apologise if the format of this question is amateurish or in some way inappropriate.
I would suggest using the request-promise library (which is a promise interface to the request library) and then using promises to manage the sequencing and error handling in a series of asynchronous operations. You can do that like this:
const rp = require('request-promise');
const options = {
method: 'GET',
url: 'https://crm.com/dev/api/opportunity/' + req.params.id,
headers: {
'cache-control': 'no-cache',
'content-type': 'application/json',
accept: 'application/json',
authorization: 'Basic xxx'
},
json: true
};
rp(options).then(body => {
return Promise.all(body.contact_ids.map(id => {
const options = {
method: 'GET',
url: 'https://crm.com/dev/api/contacts/' + Number(id),
headers: {
'cache-control': 'no-cache',
'content-type': 'application/json',
accept: 'application/json',
authorization: 'Basicxxx'
},
json: true
};
return rp(options);
}));
}).then(data => {
res.render("./applicants/resume", {data: data})
}).catch(err => {
console.log(err);
res.status(500).send("internal server error");
});
Here's a general description of the steps:
Load the request-promise library. Rather than taking a completion callback, it returns a promise that is resolved with the response body or rejected if there is an error.
Make the first request.
Use a .then() handler on the returned promise to get the result.
Process that result with .map().
In the .map() callback, return another promise from a call to request-promise for each data item. That means that .map() will return an array of promises.
Use Promise.all() on that array of promises to know when they are all done.
Return the promise from Promise.all() so that it is chained to the previous .then() handler for sequencing.
Then, in another .then() handler (which won't get called until both the previous operations are completely done), you will get the data from the .map() operation in proper order which you can use to call res.render().
Finally, add a .catch() to catch any errors in the promise chain (all errors there will propagate to this .catch() where you can send an error response).

AngularJS: How to detect if there is not a response in $http

I have this code in AngularJS:
$http({
url: my_url,
method: "GET",
data: null,
headers: {
"Content-Type": "application/json",
"my-token": "mytoken",
}
}).then(function(response, err) {
console.log(response)
console.log(err)
});
When the URL is correct and the status is 200, the response is displayed with status 200. But I want now to test with a wrong Url, then nothing is displayed, neither response nor error, so how to detect if there is no response?
By reading the $http documentation you can handle errors inside your error callback function. Also take a look at this HTTP Status Code list. Any 4xx status code e.g. 404 - not found will end inside the errorCallback function. You are also be able to handle the HTTP status by accessing response.status inside your callback functions.
Please note that there is always a response / HTTP Status code while performing an HTTP-Request.
$http({
method: 'GET',
url: '/someUrl'
}).then(function successCallback(response) {
// this callback will be called asynchronously
// when the response is available
}, function errorCallback(response) {
// called asynchronously if an error occurs
// or server returns response with an error status.
});
>> Demo fiddle
then takes two functions as parameters. First is called for success and Second is called for error. This is called promise.
Use following code to catch error:
.then(function(response) {
// Success
}, function(error) {
// Error
})
$http({
url: my_url,
method: "GET",
headers: {
"Content-Type": "application/json",
"my-token": "mytoken",
}
}).then(function(response) {
console.log(response)
}, function(error) {
console.log(error);
console.log(error.data);
});
Add a function as second parameter to .then() will track error cases for http calls.
The problem was with this line, it should be removed
"my-token": "mytoken",
Thank you !

res.json() is undefined when mocking post request with fetch-mock and isomrphic-fetch

I'm using fetch-mock to test my client action creators in cases where there is an async call being made to the BE.
While all get requests are working well I'm having hard time doing the same to post and put requests.
Attached here a code example that if works I believe that my actual code will work as well.
I'm using import fetchMock from 'fetch-mock' for mocking the response and require('isomorphic-fetch') directly to replace the default fetch
I added some comments but I do get a response with status 200 (if I change the mocked response status to 400 I get it as well. The problem is that res.json() resulted with undefined instead of the mocked result body.
Using JSON.stringify is something that I used after not being able to make it work without it.
const responseBody = {response: 'data from the server'};
fetchMock.once('http://test.url', {
status: 200,
body: JSON.stringify(responseBody),
statusText: 'OK',
headers: {'Content-Type': 'application/json'},
sendAsJson: false
}, {method: 'POST'});
fetch('http://test.url',
{
method: 'post',
body: JSON.stringify({data: 'Sent payload'}),
headers : {
'Accept': 'application/json',
'Content-Type': 'application/json',
}
})
.then(function (res) {
expect(res.status).toEqual(200); // Pass
res.json();
})
.then(function (json) {
console.log(json); // print undefine
expect(json).toEqual(responseBody); // Fail expected value to equal: {"response": "data from the server"} Received: undefined
done();
})
Mocking GET requests is working just fine
I also tried using it with fetchMock.post but had no luck
Would also appreciate if someone knows how I can test the post request sent payload as well (can't see any reference for that in the documentation)
In your first then, you don't have an explicit return, with the keyword return
If you don't do a return, the next then doesn't know the value. That's why your json is undefined.
For example:
var myInit = { method: 'GET', mode: 'cors', cache: 'default' };
fetch('https://randomuser.me/api/',myInit)
.then(function(res) {
return res.json()
})
.then(function(r) {
console.log(r)
})
So, for you:
const responseBody = {response: 'data from the server'};
fetchMock.once('http://test.url', {
status: 200,
body: JSON.stringify(responseBody),
statusText: 'OK',
headers: {'Content-Type': 'application/json'},
sendAsJson: false
}, {method: 'POST'});
fetch('http://test.url',
{
method: 'post',
body: JSON.stringify({data: 'Sent payload'}),
headers : {
'Accept': 'application/json',
'Content-Type': 'application/json',
}
})
.then(function (res) {
expect(res.status).toEqual(200); // Pass
return res.json(); // return here
})
.then(function (json) {
console.log(json); // print undefine
expect(json).toEqual(responseBody); // Fail expected value to equal: {"response": "data from the server"} Received: undefined
done();
})

Node.JS Request Module Callback Not Firing

I'm running this code using the request module for node.js
var hsKey = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
var hsForm = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
var hsHost = "https://docs.google.com/"
var url = hsHost + "forms/d/" + hsForm + "/formResponse"
var form = {
"entry.129401737": pointsAvg,
"entry.2000749128": hiddenNeurons,
"submit": "Submit",
"formkey": hsKey
};
request.post({
url: url,
form: form
}, function (err, res, body) {
console.log("Sent data");
});
I have tried running the above code just using standard Node.JS libraries, to no avail. The callback function is never fired and the request doesn't go through. I don't know why.
I believe I've found the answer to my own problem. The issue seems to be that I'm not allocating any time in the Node.js event loop to allow the request to be executed.
Have a look at this question:
your code should look something like
var hsKey = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
var hsForm = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
var hsHost = "https://docs.google.com/"
var url = hsHost + "forms/d/" + hsForm + "/formResponse"
var form = {
"entry.129401737": pointsAvg,
"entry.2000749128": hiddenNeurons,
"submit": "Submit",
"formkey": hsKey
};
request.post({
url: url,
form: form
}, function (response) {
response.setEncoding('utf8');
response.on('data', function(chunk){
//do something with chunk
});
});
The data event should get fired on receiving a response.
So if you read the docs for the request module at npm
request
.get('http://google.com/img.png')
.on('response', function(response) {
console.log(response.statusCode) // 200
console.log(response.headers['content-type']) // 'image/png'
});
There is a response event that should get fired.
I ran into this as well. I ended up creating a separate js file containing only the request, without the describe and it methods, and running it with 'mocha mynewbarebonesreq.js'. suddenly I could see that there was an exception being thrown and swallowed by mocha (with the standard reporter, spec).
I finally installed and enabled mocha_reporter which shows the exceptions
now it looks like this:
describe('CMSLogin', function () {
it('should log in as user ' + JSON.stringify(USER_PASS), function (done) {
request({
url: "http://cms.lund.multiq.com:3000/api/CMSUsers/login",
method: "POST",
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
},
json: false,
body: JSON.stringify(USER_PASS)
}, (err, res, body) => {
var parsedBody = JSON.parse(body);
this.token = parsedBody.id;
console.log(this.token)
assert.equal(USER_PASS.userId, parsedBody.userId);
assert.doesNotThrow(() => Date.parse(parsedBody.created));
if (err) { done.fail(err); }
done();
});
});
}

Error handling in AngularJS http get then construct

How can I handle an HTTP error, e.g. 500, when using the AngularJS "http get then" construct (promises)?
$http.get(url).then(
function(response) {
console.log('get',response)
}
)
Problem is, for any non 200 HTTP response, the inner function is not called.
You need to add an additional parameter:
$http.get(url).then(
function(response) {
console.log('get',response)
},
function(data) {
// Handle error here
})
You can make this bit more cleaner by using:
$http.get(url)
.then(function (response) {
console.log('get',response)
})
.catch(function (data) {
// Handle error here
});
Similar to #this.lau_ answer, different approach.
https://docs.angularjs.org/api/ng/service/$http
$http.get(url).success(successCallback).error(errorCallback);
Replace successCallback and errorCallback with your functions.
Edit: Laurent's answer is more correct considering he is using then. Yet I'm leaving this here as an alternative for the folks who will visit this question.
If you want to handle server errors globally, you may want to register an interceptor service for $httpProvider:
$httpProvider.interceptors.push(function ($q) {
return {
'responseError': function (rejection) {
// do something on error
if (canRecover(rejection)) {
return responseOrNewPromise
}
return $q.reject(rejection);
}
};
});
Docs: http://docs.angularjs.org/api/ng.$http
Try this
function sendRequest(method, url, payload, done){
var datatype = (method === "JSONP")? "jsonp" : "json";
$http({
method: method,
url: url,
dataType: datatype,
data: payload || {},
cache: true,
timeout: 1000 * 60 * 10
}).then(
function(res){
done(null, res.data); // server response
},
function(res){
responseHandler(res, done);
}
);
}
function responseHandler(res, done){
switch(res.status){
default: done(res.status + ": " + res.statusText);
}
}
I could not really work with the above. So this might help someone.
$http.get(url)
.then(
function(response) {
console.log('get',response)
}
).catch(
function(response) {
console.log('return code: ' + response.status);
}
)
See also the $http response parameter.

Categories

Resources