Home > Software design >  Dependency injection into nestjs mixin
Dependency injection into nestjs mixin

Time:09-10

I'm trying to create a guard that takes parameters and also uses a global service (prismaService).

The dependency injection works as expected for a normal guard, but to create a guard that accepts parameters I'm using mixins.

export const UserGuard = (table: Prisma.ModelName, field: string) => {
  class RoleGuardMixin implements CanActivate {
    constructor(prismaService: PrismaService) {}

    async canActivate(context: ExecutionContext) {
      const subject = await this.prismaService[table];
      return true;
    }
  }

  const guard = mixin(RoleGuardMixin);
  return guard;
};

In this case the PrismaService isn't found (I believe because the mixin is a pure function that returns a class). Is there a way to get nestjs to inject PrismaService after the guard is called? Can services be injected into classes?

CodePudding user response:

you missed the @Injectable() annotation:

export const UserGuard = (table: Prisma.ModelName, field: string) => {
  @Injectable() // <<<<<<<
  class RoleGuardMixin implements CanActivate {
    constructor(private prismaService: PrismaService) {}
    //          ^ or 'public' or 'protected'

    async canActivate(context: ExecutionContext) {
      const subject = await this.prismaService[table];
      return true;
    }
  }

  const guard = mixin(RoleGuardMixin);
  return guard;
};

or, using @Inject()

export const UserGuard = (table: Prisma.ModelName, field: string) => {
  class RoleGuardMixin implements CanActivate {
    constructor(@Inject(PrismaService) private prismaService: PrismaService) {}

    async canActivate(context: ExecutionContext) {
      const subject = await this.prismaService[table];
      return true;
    }
  }

  const guard = mixin(RoleGuardMixin);
  return guard;
};

CodePudding user response:

Thanks to @Micael for the answer.

What is needed is to decorate the RoleGuardMixin with the @Injectable decorator.

export const UserGuard = (table: any, field: string) => {
  @Injectable()
  class RoleGuardMixin implements CanActivate {
    constructor(public prismaService: PrismaService) {}

    async canActivate(context: ExecutionContext): Promise<boolean> {
      const request = context.switchToHttp().getRequest();
      const subject = this.prismaService[table].findUnique({
        where: { id: request.params.id }
        });
      return request.user.id === subject[field];
  }

  const guard = mixin(RoleGuardMixin);
  return guard;
};
  • Related