nestjs can't inject dependency in custom decorator - node.js

In offical document about authorization, i follow this guide and use casl lib
Let's assume that if i want to validate the request man is the owner of an article, i must get the article data from the database, and compare userId between user and article.userId, so i must inject a repoistory dependency like this
#Injectable()
export class DeleteHolePolicyHandler implements IPolicyHandler {
#Inject()
private readonly treeholeDaoService: TreeholeDaoService
async handle(ability: AppAbility, req: Request) {
const hole = await this.treeholeDaoService.findById(req.body.id)
return res
}
}
but i got an error, it shows me this.treeholeDaoService is undefined.
so what should i do that can make it work?
this is reproduce link

You can't inject dependencies since it's an in-place property declared using new. As stated in the docs:
Since we must instantiate the policy handler in-place using the new keyword, ReadArticlePolicyHandler class cannot use the Dependency Injection. This can be addressed with the ModuleRef#get method (read more here). Basically, instead of registering functions and instances through the #CheckPolicies() decorator, you must allow passing a Type<IPolicyHandler>. Then, inside your guard, you could retrieve an instance using a type reference: moduleRef.get(YOUR_HANDLER_TYPE) or even dynamically instantiate it using the ModuleRef#create method.

Related

NestJS + MikroORM EntityManager Validation Error

I started migrating a project from typeorm to MikroORM and I've been facing an issue when calling the same ( or different ) repository more than once. The error is as follows:
ValidationError: Using global EntityManager instance methods for context specific actions is disallowed. If you need to work with the global instance's identity map, use 'allowGlobalContext' configuration option or 'fork()' instead.
A more detailed explanation is:
I am using NestJS
DB is postgreSQL
GRPC communication for this specific service ( not sure if that matters )
Wrapping repository calls in rxjs observables: e.g. from(this.userRepository.findOne({id: user.id})
Now, I've read through the documentation and other issues here and on github mainly regarding the EntityManager and the RequestContext. I've added the #UseRequestContext() annotation on my controller ( and injected the private readonly orm: MikroORM, instance in the constructor ):
#GrpcMethod('UsersService', 'Login')
#UseRequestContext()
login(user: UserLogin): Observable<UserResponse> {
return this.userService.login(user);
}
The service itself calls userRepository.find... and via debug I can see the executed query and the result is fetched, however I have another call to the roleRepository later on down the line. This call fails with the error above. I've played around with it and it seems like even if I try to call the same userRepoistory.find... for a second time it will fail again: e.g.:
loginUser(user: UserLogin) {
return this.getUserById(user.id).pipe(
switchMap(() => this.getUserById(user.id)),
);
}
If I do the following inside the getUserById method however, it works like a charm:
getUserById(id: string): Observable < User > {
const emFork = this.em.fork();
return from(emFork.findOne(User, {
userId: id
}));
Basically what I am trying to understand is:
It says in the documentation that the function marked with #UseRequestContext() should not return anything, however when placing it on the Grpc method it works ( at least for the first repository call ). If I remove it I get the same error before calling any repositories. Am I using it correctly?
If the forking of the EntityManager is the correct approach, wouldn't that make creating Repository classes and injecting them obsolete? Also isn't forking it each time going create a lot of instances?
It's obvious I am lacking understanding on how this context works, so an explanation would be greatly appreciated!
Also, any other hints/tips are welcome!
Thank you for your time :)

FakeItEasy in C# on a servicereference

I have a servicereference with a method I need to use in a test.
The servicereference class is defined as:
public class MyServiceReference : Clientbase<IMyServiceReference>, IMyServiceReference
{
public MyServiceReference()
{
}
..... methods is then defined
}
From my testmethod I have tried both
private MyServiceReference myServiceReferenceFake = A.Fake<MyServiceReference>();
// And
private MyServiceReference myServiceReference = new MyServiceReference();
For both of these is crashes in the constructor with the message:
System.InvalidOperationException: Could not find default endpoint element that references contract.
All I need is to have a callto definition from a method in that class.
How can this be solved?
I've no experience with Clientbase, which I assume to be a System.ServiceModel.ClientBase<TChannel>,but I can make some general comments.
Since you tried first to fake a MyServiceReference, I'll assume that you're not testing that class, and you want to use it as a collaborator for the system under test. In that case, your best bet is to try faking IMyServiceReference. interfaces are very easy to fake, since they don't bring along any behaviour or baggage like faking a class does.
If you feel you really need to fake a MyServiceReference, then we have to contend with the fact that FakeItEasy will eventually call MyServiceReference(), which will call ClientBase<IMyServiceReference>(), whose documentation says
Initializes a new instance of the ClientBase<TChannel> class using the default target endpoint from the application configuration file.
Based on the error you reported, I assume that the application configuration file is not found or does not include the configuration required to create a MyServiceReference. The fact that you get the same error when you just try to instantiate a MyServiceReference directly strengthens my belief.
So I think your paths forward are either to try faking IMyServiceReference or to provide the configuration that ClientBase<IMyServiceReference> needs.

Best way to add custom validation method in a CodeIgniter 4 module

Here is the problem.
I've got a module called Contact. It lives in a directory called modules/Contact. I registered a namespace Contact for the module in app/Config/Autoload.php. Everything seems to load fine. Now I want to use a custom validation method to validate input coming from a form field. My question is about the best way to do it. My approach is as follows: According to CI4 documentation, Validation class loads App/Config/Validation.php when used for validation. In the file there is public property called $ruleSets, which points to an array, it contains names of classes with validation rules. I want to add my own class with validation methods to this array. According to CI4 documentation on validation, configuration classes, and their public properties in App/Config/ can be updated using registrars. So, I crated one such registrar, a class, in my Contact module. It lives in Contact\Config\Registrar.php . The class has public static method Validation, which returns an array with an updated $ruleSet. The new value is an array and contains all the standard validation class names + my validation class name. The trouble is public static method Validation I added in my registrar seems not to change the value of $ruleSet defined in App/Config/. Contact/Config/Registrar.php is loaded, but Validation method it contains is not called. So, what's the best method to add custom validation rules without having to updated files which live beyond my module? There is very little on registrars in CI4 documentation. Have I misunderstood how they work and how they are supposed to be used?
I had the same problem and my solution was to extend the validation class (better solutions are always welcome).
For example I wanted to write my own Auth module and use my own set of rules. My custom validation class lives under acme/Auth/Config/AuthValidation.php
<?php
namespace Acme\Auth\Config;
use Config\Validation;
class AuthValidation extends Validation
{
public $login = [
'username' => 'required',
'password' => 'required',
];
}
This way all validation rules in your main app are inherited.
And you would use this code in your controller to validate:
<?php
namespace Acme\Auth\Controllers;
use CodeIgniter\Controller;
use Acme\Auth\Config\AuthValidation as AuthValidation;
class Auth extends Controller
{
public function login()
{
//Instantiate the new AuthValidation class
$authValidationConfig = new AuthValidation();
//Since the validation class is a config for the validation service we set it for the validation service
$authValidation = \Config\Services::validation($authValidationConfig);
//Set the login rule from our AuthValidation class
$authValidation->setRuleGroup('login');
//Validate the request against our login rule
if($authValidation->withRequest($this->request)->run())
{
return 'Success';
}
else
{
return 'Failure';
}
}
}
It may be not the best solution because I'm pretty new to CodeIgniter but this is how I found my way around it.
Sidenote: The main problem seems to be that the class passed to the validation service constructor has to be an instance of "Config\Validation" so I had to extend it. But there might be other ways around it.
Feel free to correct me :)

posibilty to get service whithout moduleRef.get

I Can take instance of service using this example:
export class GetEntityDomainService {
constructor(private readonly moduleRef: ModuleRef) { }
getEntity(): void {
const myObject = this.moduleRef.get(MyClassName);
}
}
but how could I invoke a service instance outside of a class object
where I don't have a handle to moduleRef:
here is example from angular:
const injector = ReflectiveInjector.resolveAndCreate(providers);
const widgets: WidgetService = injector.get(WidgetService);
https://kevinphelps.me/blog/2017-01-17-using-angular-dependency-injection-in-node
whether is it possible to download an instance of the service without needing a moduleRef?
Thanks
Piotr
There are several reasons
sometimes I need to inject a service in a function, then I have to pass moduleRef to this function to make it possible
The second example is Command and Events -
for example I create such an action, then I pass parameters to send to handler,:
this.dispach(new Command (parameters ...))
Currently my actions know from which module they are triggered and in which module their handler is - so I won't send actions between wrong areas of the system (layers, dependencies). I check all this when executing
this.dispach (new Command ())
now I have to write such a dispatch as follows:
this.dispach (new Command (this.moduleRef, ... other parameters))
could I create a moduleRef from the code?, it would facilitate the process of creating an action and eliminate the need to pass moduleRef
but I don't know if it will help me
as I analyzed DI nest, it works differently from angular
The service knows where it was declared and when it injects something in it, it uses the tokens declared in this module
I suppose I will only be able to inject general scope

Abstracting class using mongoose

I'm developing an application in which I need to have some abstraction.
I mean there, that I would like to "simulate" an interface behaviour like creating a contract inside of my concrete classes.
Actually, dealing with Users, I'm having a UserMongoRepository class with the contract implemented :
getAll() returns the full list of users by promise
getById(id) returns the user concerned by promise
save(user) saves the user by promise
... etc
I have the same methods implemented inside of the UserMysqlRepository (allowing me to switch behaviour when a change is needed.
Problem
My problem is that I'm dealing with Mongoose that doesn't act like a datamapper, but more like an active record.
It means that my implementation of save(user) would be a bit weird like following :
save(user){
let mongooseUser = this.convert(user);
return user.save();
}
The convert method allows me to switch from a standard Model to a specific Mongoose model. It allows me, again, to have some abstraction and to don't have to rewrite my full application data access.
My real problem is when I try to unit test my full class :
import MongooseUser from '../../auth/mongooseModel/MongooseUser';
/**
* UserMongoRepositoryclass
*/
export default class UserMongoRepository{
/**
* Create an UserMongoRepository
*/
constructor(){
}
/**
* Convert a User to a MongooseUser
*/
convert(user){
return new MongooseUser({email:user.mail,password:user.password,firstname:user.firstName, lastname:user.lastName});
}
findById(id){
return MongooseUser.find({id:id});
}
save(user){
return user.save();
}
}
In a standard way, I would inject my DAO inside of my constructor, and being able to mock it.
In the case of mongoose, it's a bit disturbing, because the element that makes the job isn't an instantiated object (so that I can mock it) but a class definition imported at the top of the document.
Solutions
Should I pass the MongooseUser class definition as a parameter inside of the constructor ?
Implying that I will have this code inside of the convert method :
let user = new this.MongooseUser({})
Have you got a better idea, to abstract mongoose behaviour in data mapper way ?
I don't want to use another module, it's, in my sense, the most advanced one with NodeJS...
I'm not familiar with the import syntax (nor EMCASCRIPT-6), though you say you're using node.js, so I'd recommend using the proxquire package. The idea is that the package allows you to require an external package, while stubbing the requirements that that package would use. So in your case, you could do something like:
proxyquire('../my/class/that/uses/mongoose', {
mongoose: MyTestMongooseImplementation
})
Which would allow you to use your own mongoose implementation while still using your MongooseUser as you have defined it in your package. Alternatively, you could just override the the MongooseUser class (path relative to the the file whose requirements you are stubbing:
proxyquire('/path/to/UserMongooseRepository', {
'../../auth/mongooseModel/MongooseUser': MyTestMongooseUser
})
Documentation: https://www.npmjs.com/package/proxyquire

Resources