NestJS inject service in guard - dependency-injection

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!

Related

Nest js: class created by injection is shared across 2 services

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,
}

Dynamically inject repository in generic services with nestjs

I am building an authorization service for my nestjs app.
For every protected resource on my app (Media, Game, ...), I have a *RoleEntity associated (MediaRoleEntity, GameRoleEntity, ...) that defines what a user can do with a specific resource. Each one of this *RoleEntity implements RoleEntityInterface:
export interface RoleEntityInterface<T extends ResourceEntity> {
resource: T;
user: UserEntity;
role: string;
}
Each protected entity (MediaEntity, GameEntity, ...) extends ResourceEntity.
Now I want to build a generic provider RoleService, responsible for database interaction:
#Injectable()
export class RoleService<T extends ResourceEntity> {
readonly roleRepository: Repository<RoleEntityInterface<T>>;
async read(roleDto: Partial<RoleDto<T>>): Promise<RoleEntityInterface<T>> {
return this.roleRepository.findOne({
where: { ...roleDto },
});
}
async create(roleDto: RoleDto<T> | RoleDto<T>[]): Promise<void> {
await this.roleRepository.insert(roleDto);
}
}
And I want inject this service in guards, interceptors...
Problem, I don't know how to do that, more precisely:
How can I dynamically inject the roleRepository ? (I imagine some kind of factory has to be involved.)
REAL USE CASE
I want to be able to protect resources with a guard:
#Injectable()
export class RoleGuard<T extends ResourceEntity> implements CanActivate {
constructor(
private authService: AuthService,
private roleService: RoleService<T>,
private readonly reflector: Reflector,
) {}
...
}
Now in a controller, when I use
#Role('Admin')
#UseGuards(RoleGuard<MediaEntity>)
Get()
...
It would be perfect if the whole thing magically works :), ie correct roleService with correct roleRepository are properly injected.
I am completely new to nestjs and typescript (and never played with angular neither) so maybe the whole approach is wrong..

NestJs module depending on provider, ServiceLocator?

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.

Best practice to organise api links in Angular2

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) {}
}

Can you only inject services into services through bootstrap?

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.

Resources