nestjs exception filter is not invoked - javascript

I am trying to use an exception filter in my NestJS app. I followed the instructions found here to setup my global ExceptionFilter, which looks like this:
#Catch()
export class DemoExceptionFilter implements ExceptionFilter
{
private readonly logger: Logger;
constructor()
{
this.logger = new Logger(DemoExceptionFilter .name);
}
public catch(exception: unknown, host: ArgumentsHost): void
{
this.logger.log(exception);
}
}
In my AppModule I have registered the DemoExceptionFilter this way:
#Module({
...
providers: [
...
{
provide: APP_FILTER,
useClass: DemoExceptionFilter
}
...
]
})
When I throw an exception somewhere in my code that exception gets logged by NestJS in the console but my DemoExceptionFilter is not invoked.
I also tried
app.useGlobalFilters(new DemoExceptionFilter());
in main.ts, which also does not work.
What am I missing?

In the documentation, it says where global exception filters will be applied:
Global-scoped filters are used across the whole application, for every controller and every route handler.
They are not used for the application startup. So if you want to test your exception filter, throw an error in the route handler method of a controller and call the route.

Related

NestJS CQRS: (Repository's) Dependency Injection not working in handler

I am new to nodejs and am trying to implement NestJS's CQRS 'recipe'. I have a service with Request scope with QueryBus injection:
#Injectable({scope: Scope.REQUEST})
export class CustomerService {
constructor(
#Inject(REQUEST) private readonly req: Request,
private readonly queryBus: QueryBus,
) {}
I have defined a handler class CustomerHandler to handle CustomerQuery:
#QueryHandler(CustomerQuery)
export class CustomerHandler implements IQueryHandler<CustomerQuery> {
constructor(
private readonly repository: CustomerRepository,
) {}
async execute(query: CustomerQuery) {
const {response, id, name} = query;
this.repository.getCustomer(response, id, name);
}
But upon execution I got an error message:
UnhandledPromiseRejectionWarning: TypeError: Cannot read property 'getCustomer' of undefined at CustomerHandler.execute
which means, if I am not wrong, repository injection failed. (which caused code to fail for statement this.repository.getCustomer(response, id, name);)
I have added my repository class CustomerRepository in providers array of my module CustomerModule:
#Module({
imports: [Logger, CqrsModule],
providers: [CustomerService, ...QueryHandlers, CustomerRepository],
exports: [CustomerService],
})
export class CustomerModule {}
Here's my repository class, for reference:
#Injectable()
export class CustomerRepository {
constructor(
#Inject(REQUEST) private readonly req: Request,
) {}
Am I missing something here? Why is my repository class not being instantiated, if thats not the case, why is the repository injection failing in handler. Any input would be appreciated :)
Documentaion I am following: https://docs.nestjs.com/recipes/cqrs
Github example I referred: https://github.com/kamilmysliwiec/nest-cqrs-example
EDIT:
Handler (CustomerHandler) is not able to perform any sort of injection. I tried injecting logger (PinoLogger), which led to similar issue. So, it looks like, the problem is not with CustomerRepository, but with CustomerHandler.
UPDATE:
So basically, the problem is that every CqrsModule provider is
statically scoped which mean that they cannot depend on request-scoped
providers. Once you define your command handler as a request-scoped
provider, either CommandBus or QueryBus won't be able to reference it.
This is not an issue, but rather a design decision that sits behind
the entire module.
Source: https://github.com/nestjs/cqrs/issues/60#issuecomment-483288297
i.e. #QueryHandler() cannot be request scoped (source: comment on question - NestJS undefined dependencies and answer to the same https://stackoverflow.com/a/61916353/10011503).
And, this is also an open issue.
Reading nestjs doc, i saw that all handlers for command and query handlers are resolve en default scope, so, all dependencies with request or trasient scope are not provide in handlers. Solution is inject factory objects that resolve dependencies when are necesary

Angular: manually instantiate class with dependency injection

I am using Angular 10.0 and I have a problem with --prod compiling.
I need to instantiate classes manually and need to support dependency injection.
The following code works fine during development to instantiate my classes:
public instantiateWithDi(parentInjector: Injector, myClass: any): any {
const reflector = ReflectiveInjector.resolveAndCreate([], parentInjector);
const newInstance = reflector.resolveAndInstantiate(myClass);
return newInstance;
}
When I build my project with --prod (or --optimization=true), then I get the following error at runtime:
ERROR Error: Cannot resolve all parameters for 'e'(?). Make sure that all the parameters are decorated with Inject or have valid type annotations and that 'e' is decorated with Injectable.
Decorating the constructor parameters of the classes with #Inject did not work either. Using injection tokens does not help as well.
The classes are already decorated with #Injectable() and in the "providers" array of their respective angular module.
I know, the ReflectiveInjector is deprecated, but simply using the get method of the injector does not work either, because it seems to cache the classes once created and does not re-instantiate them each time I call my "instantiateWithDi" method.
Example usage
I've created a small demo at stackbliz for this: https://stackblitz.com/edit/angular-plugin-mechanism?file=src/app/plugin-execution.service.ts
Basically the magic happens here (plugin-execution.service.ts):
#Injectable({
providedIn: 'root'
})
export class PluginExecutionService {
public static readonly eventListeners = [];
constructor(private injector: Injector){}
private instantiateWithDi(parentInjector: Injector, myClass: any): any {
const reflector = ReflectiveInjector.resolveAndCreate([], parentInjector);
const newInstance = reflector.resolveAndInstantiate(myClass);
return newInstance;
}
public onApplicationEvent(event: ApplicationEvent){
const injector = Injector.create({
parent: this.injector,
providers: [{
provide: ApplicationEvent,
useValue: event
}]
});
PluginExecutionService
.eventListeners
.forEach(cls => this.instantiateWithDi(injector, cls));
}
}
This allows developers to create a class and push their class into a eventListener array. It gets executed every time, an application event occurs.
See the example "plugin" some.plugin.ts in the stackblitz example.
The real usecase is of course much more complex and involves custom decorators and stuff, but that would be quite an overkill for a demo.
You see the result in the console. The "plugins" work fine as intended. But when i build it using --prod, the app does not work any longer...
Any help is very much appreciated!
Thanks,
Manuel

Inject a provider in another provider, same module #1250

I have a service/provider, let's say it's call ServiceA1, in a module A marked as #Injectable().
In the same module I have another service/provider, let's say it's call ServiceA2, marked as #Injectable().
I want to inject ServiceA1 in ServiceA2 I try with:
This code throw an error: serviceA1 undefined.
My module.ts
Do I have to make another module to use serviceA2 in serviceA1?
If you're injecting a service directly by the class, you do not need the #Inject():
#Injectable()
export class ServiceA2 {
constructor(private serviceA1: ServiceA1) {
}
This is the same as:
#Injectable()
export class ServiceA2 {
constructor(#Inject(ServiceA1) private serviceA1: ServiceA1) {
}
Note that you injected #Inject('ServiceA1') instead of #Inject(ServiceA1). This is matching by a string token instead of a class and can therefore not be resolved.
If you wanted to inject the class by a string token, you would need to declare the provider in your module like this:
providers: [
ServiceA2,
{provide: 'ServiceA1', useClass: ServiceA1},
]
This also works within the same module.
Anyone running into this: make sure you remember to annotate the injected service with #Injectible.

Angular - How to implement Exception Handling on component level

While working inside Angular (Angular 4, 5), if a component raises Error (TypeError or null or undefined error or so), whole application breaks onward.
How can we deal with this, to catch errors on component level and possibly show a fallback UI, like React16 does using Error Boundaries.
I would approach it by handling the error at Component level and have a service that listens to any errors happening at Component or Service level.
Ex:
Throw the error from the service
catch the error in component
Handle the error, process it and send the Error event with details to ErrorService.
You can have a app level component "errorBannerComponent" which takes input from ErrorService and paint your UI.
As soon as the error is received in ErrorService, The errorBannerComponent should display the error on screen.
Hope it helps.
Also By default, Angular comes with its own ErrorHandler that
intercepts all the Errors that happen in our app and logs them to the
console, preventing the app from crashing. We can modify this default behavior by creating a new class that implements the ErrorHandler:
You can find more details and example here:
As the proposed solutions are rather dull. I tried to recreate it myself. The easiest solution would be to provide a module scoped custom ErrorHandler class.
Thanks to this, you could even create a multiple different ErrorBoundaries.
My proposed solution can be seen here: https://stackblitz.com/edit/angular-ivy-brb143?file=src/app/widget/widget.module.ts
What is really important for this solution to work (atleast it didn't work otherwise for me). Was to provide the custom error handler as a part of a module rather than a component directly.
The important bits from the solutions:
module:
/**
* This is really imporant as this allows us to provide a module scoped ErrorHandler
*/
#NgModule({
imports: [CommonModule],
declarations: [WidgetComponent],
providers: [{ provide: ErrorHandler, useClass: WidgetErrorHandler }],
exports: [WidgetComponent],
})
export class WidgetModule {}
component where we can throw, and catch error
#Component({
selector: 'app-widget',
templateUrl: './widget.component.html',
styleUrls: ['./widget.component.css'],
})
export class WidgetComponent implements OnInit {
constructor(#Inject(ErrorHandler) public widgetError: WidgetErrorHandler) {}
ngOnInit() {
this.widgetError.isError$.subscribe((error) =>
console.log('component can act on error: ', error)
);
}
public handleThrowErrorClick(): void {
throw Error('Button clicked');
}
}
and the handler iself
#Injectable()
export class WidgetErrorHandler implements ErrorHandler {
public isError$: Subject<Error | any> = new Subject();
handleError(error) {
console.log('Intercepted error', error);
this.isError$.next(error);
}
}

Dependency injection in Angular 2 when a constructor has arguments

I have a typescript class representing a model and I would like instances to communicate with an API via angular's Http service.
But the constructor of the model needs arguments when creating instances. For example something super simple:
class SomeModel{
constructor(public id:number, public name:string, ){
}
I would like to inject the Http service so it is available to my instances, but it seems like the canonical way to do this commandeers the constructor with:
constructor(http:Http)
I've been digging through the Injector docs, but it's a little sparse and I haven't found anything that works. Is there a way to get a reference to a service like Http from the DI system without using the constructor pattern?
I managed to solve the same problem using angular 4. First you create new injector that uses component injector. It knows about your SomeModel class and passes modelParams as instance of SomeModelParameters class. Then you use this newly created injector to create class instance.
#Injectable()
class SomeModel {
constructor(http: Http, someModelParamters: SomeModelParameters) { }
}
export class MyComponent {
constructor(injector: Injector) {
const modelParams = new SomeModelParameters();
const injectorWithModelParams = ReflectiveInjector.resolveAndCreate(
[
SomeModel,
{ provide: SomeModelParameters, useValue: modelParams }
],
injector);
this.someModel = injectorWithModelParams.resolveAndInstantiate([SomeModel]);
}
}
update
HTTP_PROVIDERS is long gone.
HttpClientModule is the current replacement.
original
If you inject a class that has constructor parameters the #Injectable annotation needs to be added.
#Injectable()
class SomeModel{
// constructor(public id:number, public name:string, ){
// }
constructor(http:Http) {}
}
For this to work HTTP_PROVIDERS needs to be added to bootstrap(AppComponent, [HTTP_PROVIDERS]);
See also Angular2 beta - bootstrapping HTTP_PROVIDERS - "Unexpected Token <"
If you need to pass other arguments from your component, youcoud pass them using a function instead.
Another way is to create the instance manually and request Http from the injector.
export class MyComponent {
constructor(injector: Injector) {
this.someModel = new SomeModel(Injector.resolveAndCreate(Http), 1, 2);
}
}

Categories