This is more a memo concrete example of how Promises work when it comes to error-handling. It also explains some of NestJS Controller behaviour when it comes to occuring errors.
Below code and comments are self-explanatory.
@Controller('myRoute')
export class AlarmController {
@Get()
public aNestControllerEndPoint() {
// this snippet could be in any block of code,
// but some of below comments tells about
// Nest http response in different cases.
try {
return myAsyncFunc()
.then(
onfulfilled => {
// We enter here if myAsyncFunc returns a resolved Promise
// Any exception happening in this block will be caught in the
// .catch block below.
console.log('success!', onfulfilled);
return onfulfilled;
},
onrejected => {
console.error("3 - Request fails with error", onrejected);
// We enter here if :
// - myAsyncFunc returns a rejected Promise
// - an unhandled exception occurs in myAsyncFunc
// We have to return a Promise: here, we return an auto-rejected Promise
// which will be caught in the .catch block below.
// Also in this particular path, we decide to generate an exception
// of a particular kind.
return Promise.reject( new ConflictException() );
// or simply:
// throw new ConflictException();
}
)
.catch(
(reason: any) => {
// We enter here:
// - if an exception occured in the 'onfulfilled' or 'onrejected' block above
// - if the 'onfulfilled' or 'onrejected' block above returned a rejected Promise
// - if an exception occured in myAsyncFunc and no 'onrejected' block
// like above exists
// - if myAsyncFunc returns a rejected Promise and no 'onrejected' block
// like above exists
console.error("2 - Request fails with error", reason);
throw reason;
// or:
// return Promise.reject( reason );
}
);
} catch (e) {
// Because we used 'await', we'll enter this block if:
// - an exception occurs in myAsyncFunc and is not handled
// above by 'onrejected' or .catch above
// - myAsyncFunc returns a rejected Promise which is not handled
// above by 'onrejected' or .catch above
// - an exception occurs in above blocks ('onfulfilled', 'onrejected' or .catch)
// and is not handled by subsequent blocks
// - above blocks ('onfulfilled', 'onrejected' or .catch) returns a rejected Promise
// not handled by subsequent blocks
// If we hadn't used 'await', the server would instanly replied '200',
// and meanwhile the async process would be on-going.
console.error("1 - Request fails with error: ", e);
// Letting an unhandled exception go will cause one of two things:
// - NestJS interceptor will catch it, and if it's recognised HttpException,
// it will generate an appropriate HTTP answer (with appropriate HTTP code)
// example with: throw new HttpException('error message', 400); // import { HttpException } from '@nestjs/common';
// example with: throw new ServiceUnavailableException(); // import { ServiceUnavailableException } from '@nestjs/common';
// - or an error 500 will be generate, and due to the nature of Nodejs
// regarding unhandled exceptions, we server will crash (and has to be
// braught back up by an Process Manager such as PM2, docker-composer, etc.)
// example with: throw new Error("Unrecognised exception");
throw e;
// WARNING: if we don't re-throw an exception here and returns nothing,
// NestJS will generate a 20x response with '' as body.
}
}
}
