Promises - catch is not working - javascript

Why is it that the following code doesn't catch the exception being thrown?
$http.get(null) // <- this throws a fit
.catch(function (e) {
console.log(e); // <- this is not being triggered
});
Error: [$http:badreq] Http request configuration url must be a string or a $sce trusted object. Received: null
https://errors.angularjs.org/1.7.2/$http/badreq?p0=null

.catch() is not a replacement for normal try catch.
It is specifically for handling exceptional circumstances that occurred during the promise resolution process.
In this case, the exception (throwing a fit) is happening outside the promise resolution process.
Your supplying invalid input to the $http.get method causing an exception before an XHR even gets created, not something going wrong with the HTTP request or any subsequent processing.
Here is an equivalent of what is happening:
try {
$http.get(throwAnException())
// .catch isn't even being evaluated!
.catch(function(e) {
console.error(e); // no chance of being called
});
} catch (e) {
// I would be evaluated
console.error(e);
}
function throwAnException() {
throw "An error before we even start";
}

You need to understand that this catch is waiting for a "rejection" from your get call.
In other words, your $http.get is triggering an error and never returning a promise...this way, you can't execute a catch straight from an error, get it?
If you have $http.get("xyz") it will then do its thing and reject, therefore, being caught by your catch.
What you are doing results in this
// step 1
$http.get(null)
.catch()
// step 2
ERROR
.catch() // will not even get here, but if it did, it wouldn't work either
While, if your get could work, but rejected, you would have:
// step 1
$http.get('someFailingURL')
.catch()
// step 2
RejectedPromise
.catch() // gonna work :)
If your url comes from a different source (and that's why you get a null value for it some times) you should probably validate it before trying and getting it, like so:
if (yourVariableURL !== null) {
$http.get(yourVariableURL)
.catch()
} else {
console.log('Invalid url');
}

This will throw Error: $http:badreq Bad Request Configuration. It has issue at request parameter level where string/url is expected but not null. Hence not going inside the block. That is the reason it is not triggering catch.
The error will be thrown by Angular is as below -
Http request configuration url must be a string or a $sce trusted object. Received: null
This error occurs when the request configuration parameter passed to the $http service is not a valid object. $http expects a single parameter, the request configuration object, but received a parameter that was not an object or did not contain valid properties.
To resolve this error, make sure you pass a valid request configuration object to $http.
Additionally, if required to catch the issue with this block of code itself, wrap it in try-catch block.

Related

NestJS blocking new requests after throwing error

I've got a small testing application (a test lab) with an AppControler and an AppService, AppController has a GET endpoint and send requests payload to AppService, which has two async methods.
AppService
async requestTesting (payload): Promise<void> { // This is what's being called from the controller
if(payload) {
await this.validateErrorHandling(payload)
}
console.log('TESTING', payload)
// DO STUFF
}
async validateErrorHandling(payload): Promise<void> {
console.log('DO STUFF')
if(payload && payload.number > 2) { // This is true
throw new Error()
}
}
When requestTesting calls validateErrorHandling, the second method is going to check that condition (if truthy) and shall throw an Error.
I'm used to do this with an exception filter on real use cases, but in this very specific case, whenever I call my Controller's endpoint and that error is thrown on my AppService, the following is shown:
UnhandledPromiseRejection: This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). The promise rejected with the reason "........".
And I'm unable to make any other request through postman until I restart the app.
Postman shows:
Error: connect ECONNREFUSED 127.0.0.1:3000
Now, I'm aware that a try/catch should fix this, but I'm trying to understand why this is stopping my whole application instead of stopping the function execution only, as it never happened to me before, and if I try to throw it anywhere else, it just works.
Now, both methods have a Promise<void> return type, but if validateErrorHandling throws an error, everything should stop and that console.log('TESTING', payload) should not be executed (as if it were business logic).
I'm afraid it's not just me being silly, but I might actually be missing something.
The reason that we throw an error is that we want to tell the front application that something went wrong. In order to achieve this, it's better to throw an HTTP error instead of simply throwing it. So here is the code:
throw new UnprocessableEntityException({
errorCode: UpdateProductErrorStatusEnum.DeviceNotReported,
message: UpdateProductErrorMsgEnum.DeviceNotReported,
});
You have two options. First throw the error in the service itself, second to throw an Error (as you did) and catch it in the controller layer. Each way has its own pros and cons. Throwing in the controller is better because the controller is designed to handle HTTP related stuff, and service is created for only logic stuff. But throwing in the controller makes the controller messy and maybe your code will not be clean.
See here for more info: https://docs.nestjs.com/exception-filters

first time getting this error Uncaught Error in Console

i am working on a ToDo list and its basically done. but i am getting this error in the console that i haven't come across yet, its preventing me to create the list (to do list)
This is the error im getting:
OPTIONS http://localhost:4000/cpds/add
net::ERR_NAME_NOT_RESOLVED
Uncaught (in promise) Error: Network Error createError.js:17
at createError (createError.js.17)
at XMLHttpRequest.handelError (xhr.js:80)
Can someone please explain what this means and how to resolve this issue.
the list prints in my console but not in my browser, then prints this error afterwards.
ERR_NAME_NOT_RESOLVED - points that system fail to resolve IP address for given hostname (http://localhost:4000/cpds/add in your case). While it is very unlikely that you are realy could not resolve address for localhost itself most probable reason is that you requesting for closed port (:4000).
In general this message say Uncaught which means that somewhere in you code when you request for "http://localhost:4000/cpds/add" form axios (it is assumtion cause you don't gave any details about your code) you have statement like
axios.get(url, { headers })
.then(data => console.log(data))
without
.catch(error => console.error(error))
so full version is
axios.get(url, { headers })
.then(data => console.log(data))
.catch(error => console.error(error))
So when request is fails due to any reason (probably error in url in you case) interpreter don't know how to overcome it (other words you should directly define function which would be called in case of error and pass it to catch method).
To ensure error is in url try to place http://localhost:4000/cpds/add to address bar of you browser, if it is realy unaccessable, browser should show you an error.
This is because one of your calls returned a rejected promise/async function, or in other words: An error that occurred calling your function.
Be careful about this. You can write yourlibrarycall.then(result => ...).catch(error => ...) But this can quickly get a pitfall. The catch clause will be called if the library call failed, but also when the .then clause failed. You'd expect the failure came from the library call, but this was fine, your code might also had a problem and the value that the variable error returns might be totally different (or undefined).
Hence i prefer having:
yourFunction = async () => {
let result;
try {
result = await yourlibrarycall // this is blocking
}
catch (error) {
// error handling only of your library call
}
// here comes your following logic
...
}
Using asnyc, your function is executed asynchronously and can now wait for the result using the keyword await. If the library call failed, it will enter the catch scope and provide you a variable with the error occurred.
This is now all the error handling and only will now only cope with the request, the following logic is then executed afterwards, getting rid of the misleading .then(...).catch(...).
If you still want to use the promise approach instead of async/await be careful to handle all the errors in the catch clause explicitly, otherwise they'll bubble up and will be catched by the catch clause, as stated above.

Should parameter assertion in Javascript throw directly when function returns Promise?

I have been writing NodeJS code for quite some time now, and seen different techniques implemented by people. My question is weather it is considered best practice having a function that as a signature returns a Promise, throw directly when parameter assertion fails.
So you think we should do this? :
Throw sync way
function asyncPromise(param) {
assert(param, 'Missing required parameter');
// Param ok
return Promise.resolve(param);
}
OR this ? :
Rejected Promise
function rejectPromise(param) {
if (typeof param === 'undefined') {
return Promise.reject(new Error('Missing required parameter'));
}
// Param valid
return Promise.resolve(value);
}
My gut is telling me to go for the first way of directly throwing since wrong parameter input should be considered as something that should not continue, however when a function has a signature of returning a Promise, the caller expects a .catch handling of an error, and will miss the error if thrown directly.
What is your opinion?
Maybe the problem is that you ask about asynchronous promises but use synchronous code example.
Correct relevant code should look something like this:
/**
* #return Promise Resolved when a value is accepted, rejected otherwise.
* #throw AssertionException When no parameter is given.
*/
function asyncPromise(param) {
assert(param, 'Missing required parameter');
var promise = new Promise(param);
something.process(promise); //start asynchronous process
return Promise;
}
//somewhere else while processing
try {
doSomething();
} catch (Exception err) {
promise.reject(err);
}
//somewhere else after processing is done
if (success) {
promise.resolve(result);
}
else {
promise.reject(error);
}
In this code there are two places where an error can happen: A) in the asyncPromise() which is synchronous error and can be safely handled by throwing an Exception and B) the processing where throwing an Exception would stop the processing but would not return any reply into the original function rendering the code frozen. In such case you must reject the promise instead of throwing an exception.
Solving the case A) by either rejecting the promise or throwing an exception should depend on what is the cause of the problem: If due to the problem you cannot create or process the promise (or something related to it) then it should return an exception. If on other hand you can safely create the promise but a problem arise while you try to start the processing, then it should reject the promise. Also good reason to reject the promise is when you realize there is no reason to start the process (e.g. when you already tried and failed).
Also note that the function clearly states that it returns a Promise but can throw an Exception if the parameter is not defined. That way everyone knows what to expect and how to use it.

Promise resolve just for success?

I'm writing an simple REST API in JavaScript and i wonder whats the best approach when using Promises and resolving/rejecting mechanism.
At first i wanted to make promise signature like:
MyApi.getSomeData()
.then(responseSuccess => console.log(responseSuccess))
.catch(responseError => console.log(responseError)
where success means we got i.e. code 200 and have some data but error means i.e. we get 404 from server. I wanted to ensure that end user that will use the API methods will have guarantee the on error(catch) he'll get particular object.
But what if the promise throws some exception somewhere inside (some runtime error or some such)? Then the promise will be rejected with this Error instead of my responseError structure.
Whats the best approach in those cases? How to distinguish between operation success, operation failure (but intentionally, i.e. 404 code) and operation unexpected error?
Run time errors in the promise will trigger the catch block. There is no avoiding that. You can however distinguish between runtime errors and network errors by checking the body of the error. So suppose
responseError = {
type: 'NETWORK_ERROR',
status: 400,
message: 'Invalid input'
}
if (responseError.type === 'NETWORK_ERROR') {
// Network error code here
} else {
// All other types of errors
}
You can also abstract this logic in a common place so you can reuse it.

JS Promises: Allowing Propagation of Errors

Background
Let's say that I'm working with NodeJS + Express. I have certain error handlers registered with Express that will take care of all errors that might come up in my application in the appropriate way(s).
As such, I throw errors in my application whenever I need to do so. If there is an unhandled error, I let it propagate until it reaches an error handler. However, while attempting to throw errors while inside of a promise chain, I ran into a problem. Take the following example:
function find() {
// consider this to be a promise from a library such as Bluebird
return new Promise(function (resolve, reject) {
// ... logic ...
});
}
function controller (req, res) {
// ... omitted ...
find().then(function (result)) {
if (result) {
// let 'res' be the Express response object
res.send("It exists!");
} else {
// let SpecificError be a prototypical subclass of Error
throw new SpecificError("Couldn't find it.");
}
}).catch(function (error) {
// throw the error again, so that the error handler can finish
// the job
throw error;
});
}
Whereas I have been expecting the error that I am re-throwing to eventually hit at least the generic error handler, I am instead seeing the requests that I send to my application hang, and the promise library that I am using complain of a Unhandled rejection.
Question
Quite simply, I am wondering how to resolve the fact that I appear to be mishandling the rejection that I am creating by throwing an error in my promise chain.
Edit: for clarification as to what (specifically) the error handler and controller function are, see the comments below.
Assuming you have bound your function with something like
app.get('/', controller);
When Express calls controller, it has yielded 100% control to you. If an exception is thrown synchronously from controller, Express is nice and will also treat that as an error for you. As soon as you invoke any asynchronous code however, it is your responsibility to decide how to handle any errors.
In the case of Express, you have two options:
Since you were passed req and res, you can catch an error and send whatever response you want back to the user.
controller actually has a function signature of function(req, res, next) in Express. This is a very common format.
The next callback expects to be called if you have not written anything in the response yet. If you call next() with no arguments, this tells Express to look keep processing the set of URL handlers that it has, trying to find one that will handle the request, returning a 404 if none are found.
If however, you pass an argument to next like next(err), Express will skip over remaining URL handlers, instead looking for error handlers. Express allows you to register custom handlers, but if none are found, it will return a 500.
So what should you do in your example? You probably want something like
function controller (req, res, next) {
find().then(function (result)) {
if (!result) throw new SpecificError("Couldn't find it.");
res.send("It exists!");
}).catch(next);
}
That means that if any exception is thrown inside of the promise chain, the next function will be called with it, and Express will take over from there.
Promise handlers are "throw safe". That means any exception you throw in any promise handler will be caught automatically and turned into a rejected promise. That is how the specification is written for promises and how they work (except for some versions of jQuery promises, but that's just because they aren't following the spec).
So, if you are getting "Unhandled rejection" from your promise library, that's designed to be a helpful warning to tell you that you had a rejected promise that had no handler for it so the rejection was silently ignored which is usually a coding mistake.
And, in fact in your controller() function, you have exactly that:
function controller (req, res) {
// ... omitted ...
find().then(function (result)) {
if (result) {
// let 'res' be the Express response object
res.send("It exists!");
} else {
// let SpecificError be a prototypical subclass of Error
throw new SpecificError("Couldn't find it.");
}
}).catch(function (error) {
// throw the error again, so that the error handler can finish
// the job
throw error;
});
}
If you get to the line where it says throw new SpecificError, then that will turn the promise into a rejected promise. That will then cause your .catch() handler to get called. In that handler, you throw again which will keep the promise as a rejected promise. So, the original promise that started with find().then(...) will now be a rejected promise. But, there are no more reject handlers and you are not returning the promise from controller(). So, you have an unhandled rejected promise at that point. That is usually a coding mistake.
You have several choices for how to correct this coding mistake:
You can handled the error yourself in the .catch() handler by calling some sort of error handling function that you pass the error to and you pass the res argument to and then don't throw the error.
You can return the promise from your controller() function and Whatever code is calling that function can then handle the rejected promise there.

Categories