I have the following code to create a new model to a collection. The underlying datastore is a remote API:
var postCreationStatus = this.model.create(newPostModel, {
wait : true // waits for server to respond with 200 before adding newly created model to collection
}, {
success : function(resp){
console.log('success callback');
console.log(resp);
},
error : function(err) {
console.log('error callback');
console.log(err);
}
});
The new model gets created, and I can confirm this from the database, but neither the success nor the error callbacks get called.
After the creation has been completed, I want to redirect the user. Redirecting prematurely kills the AJAX request, which is why it is important I use the success callback.
The server responds with a JSON response { id : 11 } and an HTTP status of 200 OK.
Looking into the backbone code, I realized my call to the create() function was incorrect. The success and error callbacks needed to be within the object being passed in as the second argument, and not as a third argument. The changed, and working snippet is this:
var postCreationStatus = this.model.create(newPostModel, {
wait : true, // waits for server to respond with 200 before adding newly created model to collection
success : function(resp){
console.log('success callback');
console.log(resp);
that.redirectHomePage();
},
error : function(err) {
console.log('error callback');
// this error message for dev only
alert('There was an error. See console for details');
console.log(err);
}
});
Related
Technical note: As axios uses different libraries/mechanisms for Node and browser, this question touches only Node.js usage of axios#0.18.0.
I can set up the following interceptor for the axios library ( https://github.com/axios/axios#interceptors ):
// Add a request interceptor
axios.interceptors.request.use(function (config) {
// Do something before request is sent
return config;
}, function (error) {
// Do something with request error
//
// I am asking about this error handler and this error object
//
return Promise.reject(error);
});
// Add a response interceptor
axios.interceptors.response.use(function (response) {
// Do something with response data
return response;
}, function (error) {
// Do something with response error
return Promise.reject(error);
});
When the callback described in error handler for request interceptor is triggered and and what is the shape of that error object?
P.S. I see that there is this code describing work with errors in axios:
axios.get('/user/12345')
.catch(function (error) {
if (error.response) {
// The request was made and the server responded with a status code
// that falls out of the range of 2xx
console.log(error.response.data);
console.log(error.response.status);
console.log(error.response.headers);
} else if (error.request) {
//
//
// !!!! This is a request error handler !!!
//
//
// The request was made but no response was received
// `error.request` is an instance of XMLHttpRequest in the browser and an instance of
// http.ClientRequest in node.js
console.log(error.request);
} else {
// Something happened in setting up the request that triggered an Error
console.log('Error', error.message);
}
console.log(error.config);
});
What will the error inside the request error handler represent in the latter code?
I think this source code might help you:
createError.js
It looks like an instance of Error, so it has error.message, and axios adds error.config, error.code, error.request and error.response, per enhanceError.js.
When the callback described in error handler for request interceptor
is triggered and and what is the shape of that error object?
the error handler (.catch clause) will be triggered by the interceptor, when it "rejects" a promise like in this part of your code:
axios.interceptors.response.use(function (response) {
// Do something with response data
return response;
}, function (error) {
// Do something with response error
return Promise.reject(error); // <---- HERE
});
The shape of the axios error object is a JSON object as stated on the handling error section of axios docs on github
message: the error message text.
response: the response object (if received) as described in the previous section. Inside response you will have data, status, and headers objects
request: the actual XMLHttpRequest object when running on browser or an instance of http.ClientRequest in node.js.
config: the original request configuration.
What will the error inside the request error handler represent in the
latter code?
It will be the error response from the request bypassed by your axios interceptor
I have the following AJAX that will send the entered data to the node server and the controller will check whether such data exist in the database or not.
If I do enter the data correctly, then everything is working fine.
However, I tried enter anything that the database does not have and it immediately throw an error, causing the server to stop. The error said that I did not handle the event, so I tried with res.json(err) in the controller instead of throw new Error, hoping that the error will be passed back to AJAX under the error key, but it is still not working. The error still gets thrown and the node server terminate itself.
I would like the server to continue and alert to the user that the data that was entered is not in the database but I have no idea why my approach is not correct.
I was thinking of using this SO thread if I'm able to get the error message back first from server side.
jQuery Ajax error handling, show custom exception messages
To solve the server from stopping, I used the code in app.js that was referred from this link
How do I prevent node.js from crashing? try-catch doesn't work
I'm not sure whether should I use the accepted answer for my case.
function createProduct(inputval){
let inputAction = window.location.pathname;
$.ajax({
type: "POST",
url: inputAction,
data: {order: inputval.split('-')[0].trim(), lot: inputval.split('-')[1].substring(0,5)},
success: function(data) {
$('#product').val('');
//Another function to add HTML
display(data);
},
error: function(jqXHR, textStatus, errorThrown) {
console.log("XHR" + jqXHR)
console.log("Status" + textStatus)
console.log(errorThrown)
}
});
}
Controller File
exports.createProduct = function (req, res) {
db.Product.findOne({ "order": req.body.order, "lot": req.body.lot }).exec(function (err, product) {
if (!product || err){
throw new Error("The product entered returns null");
}
res.json(product);
});
};
Main File: app.js
process.on('uncaughtException', function (err) {
console.error(err);
console.log("Node NOT Exiting...");
});
You should use correct status code for your response. I suggest change your controller like below snippet
exports.createProduct = function (req, res) {
db.Product.findOne({ "order": req.body.order, "lot": req.body.lot }).exec(function (err, product) {
if (err){
res.status(500).end();//means internal server error
} else if (!product) {
res.status(404).end();//means product not found
} else {
res.json(product);
}
});
};
I finally figure it out thanks to feedback from other community, so I thought I would just share it here. It's so simple and silly me for neglecting such statement.
First, the code in app.js can just be removed.
Second, based on the answer given by #Milad Aghamohammadi. Instead of just:
res.status(500).end();
Use:
return res.status(500).json({err: "Server error"});
This way, the error is able to be handled by the AJAX error function and the node server will not be terminated from the event loop.
I am working on this code and I have a really weird issue. I am using AngularJS $http request, and trying to run a success or error afterwards. I am currently getting a 404 from the server (the client says) but the server isn't barfing up a 404 (in fact it says it sent a 200 response).
This $http post doesn't hit either the 'success' or 'error' handlers and I don't know what to do for debugging it.
All other functions using RequestService work perfectly.
var refreshBusinesses = function() {
console.log("refreshBusinesses");
RequestService.post('user/managed_businesses', {}).then(function(businesses){
console.log('got busineses ', businesses)
$scope.businesses = businesses
}, function(error){
console.log("ERROR!");
$scope.error = error.message;
console.log('business refresh error ', error)
})
}
Most probably your service RequestService does not handle promise properly. I believe it is a wrapper around angular's $http. If so, probably it does not reject promise on error, but simply returns some value.
So to solve it check your RequestService that it handles error situation properly:
$http.post('url', data).then(
function(res) {
return res;
},
function(error) {
var deferred = $q.defer();
return deferred.reject(error);
});
$q docs can be found here https://docs.angularjs.org/api/ng/service/$q
I'm using Angular to send a post request with the $http service. I am doing all of the data validation of the form in Angular prior to sending the post request. However, there is one validation I am doing in PHP of whether the user already exists in the database. How do I purposefully invoke an error (in the php file) so that the Angular error callback is triggered instead of the success callback? Should I purposefully throw an exception?
IF the intent is to throw an exception, does the exception message get passed into the data parameter for the Angular error callback function?
Based on the comments to my question, I just did the following to my code:
if (duplicateUsers($username) > 0) {
return http_response_code(400); // successfully generated an error in
// the $http AngularJS servicces
} else {
// other code
}
You can chain your promises. The first promise will check the success content and that's also where you can throw an exception. This will cause the subsequent promises to return failure.
Here's a jsbin example.
angular
.module('app', [])
.run(function($http) {
var from$http = $http
.get('www.google.com') //makes a request to www.google.com
.then(function(response) {
console.log('data was successfully retrieved from google');
throw "from success handler"; //if has error, then throw "duplicated user"
});
from$http.then(function() { // this then block is handling the previous exception
console.log('this success block is never called');
}, function() {
console.log('inside error block even tho success was returned from www.google.com');
});
});
I am wondering how to properly handle errors with Meteor when using async methods. I have tried the following, but the error is being returned in the result parameter on the client callback instead of the error parameter.
Server code:
Future = Npm.require('fibers/future');
Meteor.methods({
'myServerMethod': function(){
var future = new Future();
// URL to some remote API
var url = UrlOfTheApiIWantToCall;
HTTP.get(url, {//other params as a hash},
function (error, result) {
if (!error) {
future.return(result);
} else {
future.return(error);
}
}
);
return future.wait();
}
});
Client code:
Meteor.call('myServerMethod', function (error, result) {
if(error){
console.warn(error);
}
console.log('result', result);
});
As I was saying above, 'error' is always undefined on the client side event when the HTTP.get() on the server side returned an error. I also tried replacing future.return(error); with future.throw(error); on the server side, but this really throws an error on the server side. The client side error parameter then gets a 500 Server Error, although the error thrown on the server was a 401 Unauthorized error.
So, is it possible to use Fiber's Future properly so that the client callback receives the same error parameter as the server callback?
According to the Meteor.Error docs at http://docs.meteor.com/#/full/meteor_error
Methods can throw any kind of exception. But Meteor.Error is the only kind of error that a server will send to the client. If a method function throws a different exception, then it will be mapped to a sanitized version on the wire. Specifically, if the sanitizedError field on the thrown error is set to a Meteor.Error, then that error will be sent to the client. Otherwise, if no sanitized version is available, the client gets Meteor.Error(500, 'Internal server error').
Which is why you are receiving the 500 Server Error on the client. If you want to preserve the error message and have it be sent to the client, you can do something like this:
Future = Npm.require('fibers/future');
Meteor.methods({
'myServerMethod': function(){
var future = new Future();
// URL to some remote API
var url = UrlOfTheApiIWantToCall;
HTTP.get(url, {//other params as a hash},
function (error, result) {
if (!error) {
future.return(result);
} else {
future.throw(error);
}
}
);
try {
return future.wait();
}
catch(err) {
// Replace this with whatever you want sent to the client.
throw new Meteor.Error("http-error", err);
}
}
});