I am building an app using node.js and knex for the ORM. I want my insert command to send either a success or error response, but it is not working for some reason:
knex('reports').insert({
reportid: reportId,
created_at: currentDate
}).then().catch(function(error) {
if(error) {
console.log("error!!!: " + error)
res.send(400, error);
} else {
console.log('no error');
res.send(200);
}
});
The code as is does NOT console.log out the error nor lack of error.
Note - the res.send(200) should go back to my client side to alert the client the request was successful.
Can someone help? Thanks in advance!!
Promises will either trigger your then function or the catch function. Not both. Handling the success case happens in the then function, handling the error case happens in the catch function.
To demonstrate with your code:
knex('reports').insert({
reportid: reportId,
created_at: currentDate
}).then(function(data) {
console.log('no error');
res.send(200);
}).catch(function(error) {
console.log("error!!!: " + error)
res.send(400, error);
});
You should handle the positive flow within the .then part:
then()
{
console.log('no error');
res.send(200);
}
Also it's not consider a good practice to mix DB code with HTTP related logic as they probably should reside in different layers/components, see best practice number 4 here:
http://goldbergyoni.com/checklist-best-practices-of-node-js-error-handling/
Related
I'm currently building a single page application based on Laravel and VueJS.
Is there any better way then mine to handle errors with axios?
This is how I currently do it when a user clicks on login button:
VueTemplae:
methods : {
authenticateUser() {
axios.post('/api/login', this.form).then(() => {
this.$router.push({name : 'home'});
}).catch((error) => {
this.error = error.response.data.message;
});
}
}
Api route:
public function login() {
try {
// do validation
} catch(Exception) {
// validation failed
throw new Exception('login.failed');
}
// manually authentication
if(Auth::attempt(request()->only('email', 'password'))) {
return response()->json(Auth::user(), 200);
}
// something else went wrong
throw new Exception('login.failed');
}
Unfortunately, throwing an exception always prints an internal server error into the console.
If I return something else than an exception, axios always executes then().
Is there any way to prevent this or a better way to handle axios responses?
Thank you!
Your API needs to return a response with a 4XX status code in order for the catch block to fire in your Vue component.
Example:
After you catch the error on the API side, send a response with status code 400 Bad Request. It will be formatted similarly to your successful login response, but with an error message and 400 status code instead of 200.
I can not catch the error response with axios. How to do that?
I use something like:
axios
.post(...)
.then(response => {
console.log('Success: ', response)
}).catch(error => {
console.log('Error: ', error)
})
I see that the result of ajax request has 400 status code and the response body looks like {someField:["This field may not be blank"]} (Django backend). That's ok, I'm ready to process these errors in the catch handler.
But they go to the success handler instead. Why so? I see the following output in the console:
Success: Error: Request failed with status code 400
at createError (createError.js:16)
at settle (settle.js:18)
at XMLHttpRequest.handleLoad (xhr.js:77)
The success handler receives axios error object as the result. Why that may be and what to do next? This error object does not contain any usefull information.
UPD. Actually, the error object does contain the useful information, it contains the response object inside. So we can use:
axios
.post(...)
.then(response => {
if (response && response.response) {
console.log('This is also an error', response.response.status)
} else {
console.log('Success: ', response)
}
}).catch(error => {
console.log('Error: ', error)
})
But that looks super ugly.
The axios version is axios#0.16.2.
That's the big project, but I can not find any axios customizations.
Use Axios interceptors for the response. Check which status you want to force to fail as error so they go through the catch path whenever you receive said status code.
axios.interceptors.response.use(function (response) {
if (response.status === 400) {
return Promise.reject(response);
}
return response;
}, function (error) {
// Do something with response error
return Promise.reject(error);
});
If you are not receiving the expected status code, you might change the way you check the response in the interceptor. You can check any of the elements that Axios response is structured.
axios.interceptors.response.use(function (response) {
if (response.statusText !== 'OK') {
return Promise.reject(response);
}
return response;
}, function (error) {
// Do something with response error
return Promise.reject(error);
});
I have been trying to alert this so that it prints two responses
when there is an error or a duplicate entry and
when the response is ok and prints successfully
var response;
try {
response = JSON.parse(xmlhttp.responseText);
} catch (e) {
console.error(this.responseText);
alert(this.responseText);
}
if (response) {
console.log(response);
}
I want it to alert a response both when there is a failure and when the response is successful, but I haven't figured it out yet.
figured it out
at this stage
console.error(this.responseText);
alert(this.responseText);
i needed to insert my error message here like this
var responseText = this.responseText;
alert('Registration failure because ' + responseText );
and below
console.log(response);
alert ('Registration Successful');
At this stage it prints the required outcome.
I'm starting to convert my callback code to promises in Sails.js, but I don't understand how I can raise custom errors and handle them in the promise chain. Sails.js uses Q as its promise library.
User.findOne({email: req.param('professorEmail'), role: 'professor'})
.then(function (user) {
if (user) {
return Course.create({
user_id: user.id,
section: req.param('section'),
session: req.param('session'),
course_code: req.param('course_code')
});
} else {
// At this point `user` is undefined which means that no professor was found so I want to throw an error.
// Right now the following statement does throw the error, but it crashes the server.
throw new Error('That professor does not exist.');
// I want to be able to handle the error in the .fail() or something similar in the promise chain.
}
}).then(function (createSuccess) {
console.log(createSuccess);
}).fail(function (err) {
console.log(err);
});
Right now the .fail() is never called because the thrown error crashes the server.
Use .catch() instead of .fail().
Waterline's claim complete Q promise object after the first then seems untrue by your test. I've verified it myself as well and found a workaround.
You can do this :
var Q = require('q');
[...]
Q(User.findOne({email: req.param('professorEmail'), role: 'professor'}))
.then(function (user) {
if (user) {
return Course.create({
user_id: user.id,
section: req.param('section'),
session: req.param('session'),
course_code: req.param('course_code')
});
} else {
// At this point `user` is undefined which means that no professor was found so I want to throw an error.
// Right now the following statement does throw the error, but it crashes the server.
throw new Error('That professor does not exist.');
// I want to be able to handle the error in the .fail() or something similar in the promise chain.
}
}).then(function (createSuccess) {
console.log(createSuccess);
}).fail(function (err) {
console.log(err);
});
This will return a true Q promise.
I need to invoke some common methods before an AJAX call is made and after the AJAX call (before the actual handler method is called) is success. I'm using dojo.aspect to achieve this.
This is my code sample
function makeAjaxCall(){
dojo.xhrGet({
url:"sample_url",
content:{
test:"value"
},
load:function(response){
//Do some logic here
},
error:function(response){
//handle error
}
});
}
Below is the dojo.aspect which I'm using to get a hook to the XHR calls.
define(["dojo/aspect"], function(aspect){
aspect.after(dojo, "xhr", function(deferred){
console.log("AJAX AFTER");
deferred.then(function(response){
//CALLED AFTER 'load' METHOD IS CALLED.
console.log("Testing");
});
});
aspect.before(dojo, "xhr", function(method, args){
console.log("AJAX BEFORE");
});
});
Now the problem is deferred.then inside aspect.after is called after the "load" function is called. Is it possible to have a method which is called before the actual load method is invoked?
The short answer is yes.
First, there are two ways to make ajax calls in Dojo.
dojo/xhr - this is what you have above and this is deprecated
in favor of
dojo/request/xhr
The first implementation will call into the second implementation. So I would recommend using aop on dojo/request/xhr.
aspect.around(require.modules['dojo/request/xhr'], 'result', function(originalXhr){
return function(url, options, returnDeferred){
var dfd = new Deferred();
// Logic before making the xhr call
originalXhr(url, options, returnDeferred)
.then(function(response) {
// Logic handling the response but before resolving the deferred.
dfd.resolve(vm);
// Logic after resolving the deferred.
}, function(err){
// error handling?
dfd.reject(msgs);
}, function(update) {
dfd.progress(update);
});
return dfd;
};
});
You can find the complete implementation at
https://github.com/cswing/evinceframework/blob/master/evf-web-js/src/dojo/evf/serviceRegistry.js (~ line 111)
USAGE:
require('dojo/xhr/request', function(xhr){
xhr({...}).then(
function(response) {
//handle response
},
function(error) {
//handle error
}
);
});
The dojo/xhr code will translate itself to the usage above, so the code you posted should work.
If you switch to the new API - dojo/request
Then you could use dojo/request/xhr and dojo/request/notify
In Dojo 1.10 there is new API to globally catch state of requests.
notify("error", function(error){
console.error(error);
//SyntaxError: Unexpected token < in JSON at position 0(…)
});
But in my case I get errors in html eg. so in error I get "error SyntaxError: Unexpected token < in JSON at position 0(…)"
In previous version there was an access to response object:
topic.subscribe("/dojo/io/error", function(/*dojo.Deferred*/ dfd, /*Object*/ response){
if (response.status === 401) {
window.location.reload();
}
});
So I figured out that json handler can be customized:
require(["dojo/request/handlers"], function(handlers){
handlers.register("json", function(response){
if (response.status === 401) {
window.location.reload();
return;
}
return JSON.parse(response.text || null);
});
});
This way you are able to detect response.errors before JSON.parse throws exception.