NestJS blocking new requests after throwing error - javascript

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

Related

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.

Promises - catch is not working

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.

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.

Handling thrown exceptions from WebApi with BreezeJs executeQuery (Unhandled rejection reasons)

I am using Breeze.js and Q.js within my MVC app.
I currently have an action on my webApi
public IQueryable<Myobject> doMyAction()
This can do 2 things:
Return a collection of objects (if the user is allowed)
Throw a HTTP Exception (if the user is not allowed) (It may not be an "unauthorised" , this is just an example)
throw new HttpResponseException(Request.CreateResponse(HttpStatusCode.Unauthorized, "Not Allowed"));
This action gets called from javascript with breeze with:
var query = EntityQuery.from('doMyAction');
// execute the query
dcCore.manager.executeQuery(query)
.then(querySucceeded)
.fail(dcCore.queryFailed);
If the user is authorised and the logic is true, then I connect to my DB and return a nice list of Myobject() and everything is fine.
However, if I do a throw exception to say they are unauthorised, then in the console I get my 401 (Unauthorised) and the message:
[Q] Unhandled rejection reasons (should be empty):
This happens before it hits the .fail() function.
I also tried putting a try/catch around the whole execute bit, hoping that I would catch an error, but had no luck.
I can see why this is happening in theory, as I am not returning something that executeQuery is expecting (In fact, im not returning at all, i'm throwing!), however,
-actual question
how should I handle returning errors from the webApi with breeze, without doing something like extending the model?
The only thing I am yet to try is to make my web API return a type of dynamic, or generic object, but this doesn't feel like the best solution.
You have two approaches for this, the first is to simply throw an simple exception directly in your query method, i.e. something like this:
[HttpGet]
public IQueryable<Customer> CustomersStartingWith(string companyName) {
if (companyName == "null") {
throw new Exception("nulls should not be passed as 'null'");
}
...
}
Or, if you want slightly more control over the HTTPResponse you can do the following:
[HttpGet]
public IQueryable<Customer> CustomersWithHttpError() {
var responseMsg = new HttpResponseMessage(HttpStatusCode.NotFound);
responseMsg.Content = new StringContent("Custom error message");
responseMsg.ReasonPhrase = "Custom Reason";
throw new HttpResponseException(responseMsg);
}
Note that for a Save operation as opposed to the Query operations described above, the best approach is to throw an EntityErrorsException. (see documentation), although throwing a simple exception will still work.
Hope this helps.

Categories