In Nest Js, I have a module definition:
#Module({
imports: [ConfigModule.forRoot(), HelperModule],
providers: [
NEtheriumChainService,
NBinanceChainService,
NBitcoinChainService,
NChainServiceProvider,
{
provide: Web3,
useValue: new Web3(),
},
],
exports: [NChainServiceProvider],
})
export class NChainsModule {}
NEtheriumChainService and NBinanceChainService both accept a Web3 class in their constructor. I would have thought that this syntax would provide each service with its own Web3 instance, but they end up with the same instance of Web3 - effectively sharing it. How do I ensure that each service has its own dedicated Web3 instance?
With the release of nest.js 6.0, injection scopes were added. With this, you can choose one of the following three scopes for your providers:
SINGLETON: Default behavior. One instance of your provider is used for the whole application
TRANSIENT: A dedicated instance of your provider is created for every provider that injects it.
REQUEST: For each request, a new provider is created. Caution: This behavior will bubble up in your dependency chain. Example: If UsersController (Singleton) injects UsersService (Singleton) that injects OtherService (Request), then both UsersController and UsersService will automatically become request-scoped.
What you need is TRANSIENT
Usage
Either add it to the #Injectable() decorator:
#Injectable({ scope: Scope.TRANSIENT })
export class Web3 {}
Or set it for custom providers in your module definition:
{
provide: "Web3",
useClass: Web3,
scope: Scope.TRANSIENT,
}
Related
I am pretty new to developing REST APIs using the NestJS framework (started using it last week).
For Authorization purposes I want to implement a CanActivate Guard to my app. This guard simply looks for an authorization header to extract the jwt. Furthermore the user needs to be fetched via a service to get its role and check for the required permission. Additionally there is a #Permission decorator, which is used on protected routes, that takes in a permission string.
This decorator file looks like this:
export const PERMISSION_KEY = "requiredPermission"
export const Permission = (permission: string) => {
return SetMetadata(PERMISSION_KEY, permission);
}
But I am experiencing strange behaviour: Only injecting the Reflector (so I can look up the required permission from the route) is working fine. When now trying to inject a service, let's say AuthService, the constructor of the AuthenticationGuard isn't even called, so the service results in undefined. Event the reflector instance is undefined, though it worked before. Here is how it looks in my authentication.guard.ts:
#Injectable()
export class AuthenticationGuard implements CanActivate {
constructor(
private reflector: Reflector,
private authService: AuthService
) {}
canActivate(context: ExecutionContext): boolean | Promise<boolean> | Observable<boolean> {
// ... do some things to extract jwt from header ...
console.log(this.authService); // Results in undefined
// This line does not work because reflector also is undefined.
const requiredPermission = this.reflector.get<string>(PERMISSION_KEY, context.getHandler());
console.log(requiredPermission);
}
}
This guard is imported as a provider in a feature module called AuthModule:
#Module({
imports: [
JwtModule.register({
secret: "EXTREMELY_SECRET"
})
],
providers: [
AuthService,
{
provide: APP_GUARD,
useClass: AuthenticationGuard
}
],
controllers: [ AuthController ],
exports: [
AuthService
]
})
export class AuthModule {}
Now when removing the service from dependency injection and make a console.log, I can see that it gets instantiated as the first dependency of the whole app. Does this maybe cause the service to fail injecting? How would I possibly change fix that?
Or does injecting services not work for guards in general? I think this is not the problem.
Maybe someone can help me with this problem and give me some advice on to fix this issue.
Thank you very kindly in advance for your support!
Goal
I am working in a module similar to SpringActuator (I need /health, /info, /metrics, etc), I need the module to be reused across several apps, but the logic to determine if the app is healthy or to get the app info is defined at the application itself, I want this actuator module to be agnostic of the application. So I need the application to import the module passing a provider that exists already at the application context.
Implementation
I used the ModuleRef (with strict option) to create something like a ServiceLocator, so that any app dependency could be resolved during module initialization.
The actuator module is imported like this
imports: [ActuatorModule.forRoot({ actuatorToken: ApplicationActuator })]
The ApplicationActuator is the class knowing if the app is healthy or not. This provider could have another dependencies internally (nested)
The ActuatorModule uses a factory approach to provide the service locator(FactoryHelper)
providers: [
{
provide: 'ActuatorFactoryHelper',
useFactory: (moduleRef: ModuleRef) => new FactoryHelper(moduleRef, options.actuatorToken),
inject: [ModuleRef],
}
]
And finally my service uses the FactoryHelper like this
get actuator(): Actuator {
return this.factoryHelper.instance;
}
constructor(#Inject('ActuatorFactoryHelper') private readonly factoryHelper: FactoryHelper<Actuator>) {}
This is how the FactoryHelper looks like
export class FactoryHelper<T> implements OnModuleInit {
instance: T;
constructor(
private readonly moduleRef: ModuleRef,
private readonly token: Type<any> | string | symbol,
) {}
onModuleInit() {
this.instance = this.moduleRef.get(this.token, { strict: false
});
}
}
Question
I read in another threads that having a module depending on a provider is a bad practice, Is it a bad practice? what issues could I face? Is it a easier way of doing it?
Notes
I tried using custom providers (useFactory) but nested dependencies got not resolved (they are not visible to the actuator module).
Thanks in advance.
I am struggling with angular2's dependency injection. In my example I have two Services.
Service1 injects Service2 and gets data from it.
A Component injects Service1 and fetches the data from Service1
I have to provide Service2 in my Component
#Component({
providers: [Service1, Service2]
})
But why? I injected Service2 in Service1. Why do I have to provide Service2 in my Component, when there's no reference to Service2 in my Component?
I am aware, that I could provide services in my bootsrap function, but I would like to provide my Services to my Component...
bootstrap(AppComponent, [... Service1, Service2])
Here is my example code, which is not working because of the missing provider
component.ts
import {Service1} from "service1.ts";
#Component({
providers: [Service1]
})
export class Component{
constructor(private s: Service1) {
//get data from Service1
}
}
service1.ts
import {Service2} from "service2.ts";
#Injectable()
export class service1{
constructor(private s2: Service2) {
//get data from service2
//edit data
//return data
}
}
service2.ts
#Injectable()
export class service2{
constructor() {
//return data
}
}
Angular needs to know, where to find the services. That's what providers array (either in the component or in the bootstrap call) is used for. You can think of it as of a hierarchical registry. If you want the services to be injected, you need to feed them to the registry.
In Angular1 the services were registered in the registry by calling the factory function or alike. Here the logic is different.
All in all, even if the component is not directly bound to the service, it has to register it, so that Angular becomes aware it exists.
In angular2 app, we need to call a lot of 3rd party restful APIs. Any idea how to organise these APIs, so we can centralize the management of these APIs (maybe in a config file)?
For example, in angular2 tutorial
https://angular.io/docs/ts/latest/guide/server-communication.html#!#fetch-data
imagine I have 20 services, every one of them will have a few functions inside to use http get, post accessing a bunch of 3rd party restful APIs. So I want to put all these API links in a centralize place, later if there is any change from 3rd party API providers, I can change without going into my services ts files?
Updated
config-values.ts
import {OpaqueToken} from 'angular2/core';
export const API_LOGIN = new OpaqueToken('API_LOGIN');
main.ts to bootstrap
...
import {API_LOGIN} from './app/shared/services/config-values';
bootstrap(AppComponent, [
ROUTER_PROVIDERS,HTTP_PROVIDERS,
provide(API_LOGIN, {useValue: 'http:bar.com/somepath'}),
provide(PLATFORM_DIRECTIVES, {useValue: [ROUTER_DIRECTIVES], multi:true}),
provide(APP_BASE_HREF, { useValue: '<%= APP_BASE %>' })
]);
In login.service.js which calls it
...
import {API_LOGIN} from 'config-values.ts';
#Injectable()
export class LoginService {
private loggedIn = false;
constructor(#Inject(API_LOGIN) private apiUrl:string,private http:Http) {
this.loggedIn = !!localStorage.getItem('auth_token');
}
}
I would create a typescript file containing OpaqueTokenss and pass them using DI
config-values.ts
export const API_FOO_URL = CONST_EXPR(new OpaqueToken('API Foo URL'));
export const API_BAR_URL = CONST_EXPR(new OpaqueToken('API Foo URL'));
...
export const API_URLS = CONST_EXPR([
provide(API_FOO_URL, {useValue: 'http:foo.com/somepath'}),
provide(API_BAR_URL, {useValue: 'http:bar.com/somepath'}),
...
]);
main.ts
import {API_URLS} from 'config-values.ts';
bootstrap(AppComponent, [API_URLS, ...]);
foo.service.ts
import {API_FOO_URL} from 'config-values.ts';
#Injectable()
export class FooService {
constructor(#Inject(API_FOO_URL) private apiUrl:string) {}
}
I am trying to wire up a basic Angular2 app that uses the Http service. (Most of the tutorials I've seen do this by having a Component consume the Http service, which seems wrong unless the basic philosophy of thin controllers has changed – but that's a different question.)
I would like to create a service that uses Angular's Http service. But I can't figure out how to inject the Http service other than this:
boot.ts:
import {bootstrap} from 'angular2/platform/browser';
import {AppComponent} from './app.component';
import {HTTP_PROVIDERS } from 'angular2/http';
bootstrap(AppComponent, [HTTP_PROVIDERS]);
myService.ts:
import {Injectable} from 'angular2/core';
import {Http} from 'angular2/http';
#Injectable()
export class aService{
constructor(http:Http){
}
/** do some stuff *//
}
This works, but it seem very wrong to require the user of the service to know the service's dependencies and be required to inject them into the bootstrap process. It seems like there should be a way to directly hand a providers array to a service the same way you can a component, but I can't find it. Am I just missing something?
Update
This way if a parent injector provides an implementation for OtherService this one is used, otherwise OtherServiceImpl is used (default).
#Injectable()
class SomeService {
OtherService _other;
SomeService(Injector injector) {
_other = injector.getOptional(OtherService);
if (_other == null) {
_other = injector.resolveAndCreateChild([
provide(OtherService, useClass: OtherServiceImpl)
]).get(OtherService);
}
_other.doSomething();
}
}
If you provide another one like
bootstrap(AppElement, [
provide(OtherService, useClass: OtherServiceImpl2)
]);
OtherServiceImpl2 is used.
See also https://github.com/angular/angular/issues/5622
Original
You could just make the http service optional (using the #Optional() annotation) and if none is provided just create an instance inside the constructor with new Http().
This way the user doesn't need to know about the services dependencies, but is able to pass alternative implementations if necessary (for example for testing).
If creating the dependeny inside the service requires DI itself, you can inject an injector and use it to get dependencies.
See also optional dependencies in http://blog.thoughtram.io/angular/2015/05/18/dependency-injection-in-angular-2.html
What also could work (not tried myself yet) is just to create a child injector and instruct it to skip self
From the SkipSelfMetadata documentation
class Dependency {
}
#Injectable()
class NeedsDependency {
dependency;
constructor(#SkipSelf() dependency:Dependency) {
this.dependency = dependency;
}
}
var parent = Injector.resolveAndCreate([Dependency]);
var child = parent.resolveAndCreateChild([NeedsDependency]);
expect(child.get(NeedsDependency).dependency instanceof Depedency).toBe(true);
var inj = Injector.resolveAndCreate([Dependency, NeedsDependency]);
expect(() => inj.get(NeedsDependency)).toThrowError();
I don't know yet if this still resolves from "self" if parent can't provide the requested type.