Sometimes I need to use some methods which implemented in nestjs code structure in separate from this classes
For example we have such architecture:
entities
-entity.entity.ts
-entity.module.ts
-entity.service.ts
-entity.providers.ts
So how Can I use method or property from entity.service in separate class? Such like this:
import EntityService from './entities.entity.service'
export class SeparateClass{
propertyFromEntityService: string
constructor() {
this.propertyFromEntityService = EntityService.propertyFromEntityService
}
}
And one more important point. I don’t want to implement this separate class in the nestjs structure, I just want to use it as a regular class. Thank you
If you are not wanting to use dependency injection via Nest, but you still want to use a property from a class in the Nest application, you'll need to manually instantiate the class, providing whatever dependencies that class has, and then pulling the property from the service. The other option, if this class will be used outside of the Nest context, but still while the Nest application is running, is you can use the Nest application to get the service via app.get(EntityService), but this does require you to have access to app after the NestFactory has created the application.
Related
Background
I'm working on a large application that needs to be upgraded. If I were starting from scratch I'd do this all differently. But right now I need to figure out a fix without touching hundreds of files.
For the same reason, I ideally need this code to work on Nest 6. This project needs to be upgraded to the latest nest, but there are some things that need to be fixed to do this. Before I can do that, I need to resolve the current issue, which is blocking us from upgrading off of node 12
Problem
I have a logger class. This class is supposed to pull in some information from the REQUEST context, if one is available (basically, some headers). If no request context is available, this can be ignored.
For simplicity in talking about this, we can say that I need a provider Logger which returns either a RequestAwareLogger or PlainLogger instance, depending on whether or not it is being resolved from a request scope. Alternately, I need the provider to return the same class, with either a request injected (via #Inject(REQUEST)), or left undefined.
Edit For posterity: If I were writing this from scratch, I'd just update the logger.log call to consume this information directly by passing in the request object, or the fields I needed tracked. But since this is a huge project already, I'd have to modify 1000 lines of code in different files, many of which don't have direct access to the request. This will be a longer term effort
Unfortunately, there is no built-in way to do this in Nest. However, it is possible to create a custom provider that would achieve the same effect.
Here is an example provider that would return either a RequestAwareLogger or PlainLogger instance, depending on whether or not it is being resolved from a request scope:
#Injectable()
export class LoggerProvider {
constructor(
#Optional() #Inject(REQUEST) private readonly request?: Request,
) {}
getLogger(): PlainLogger | RequestAwareLogger {
// If a request is available, return a RequestAwareLogger instance
if (this.request) {
return new RequestAwareLogger(this.request);
}
// Otherwise, return a PlainLogger instance
return new PlainLogger();
}
}
Then, you can use this provider in your logger service like so:
#Injectable()
export class LoggerService {
constructor(private readonly loggerProvider: LoggerProvider) {}
log(message: string) {
const logger = this.loggerProvider.getLogger();
// Use the logger instance
logger.log(message);
}
}
Note that this provider will only work if Nest's IoC container is used to resolve the logger service. If you are using a different IoC container (e.g. in a non-Nest application), you will need to create a custom provider for that container.
The docs here are as below:
When it comes to unit testing an application, we usually want to avoid
making a database connection, keeping our test suites independent and
their execution process as fast as possible. But our classes might
depend on repositories that are pulled from the connection instance.
How do we handle that? The solution is to create mock repositories. In
order to achieve that, we set up custom providers. Each registered
repository is automatically represented by a Repository
token, where EntityName is the name of your entity class.
The #nestjs/typeorm package exposes the getRepositoryToken() function
which returns a prepared token based on a given entity.
What does that even mean? Autocomplete docs just give the signature with no explanation.
getRepositoryToken() is a helper method that allows you to get the same injection token that #InjectRepository() returns. This is useful when it comes to tests so that you can define a custom provider that has a matching token for the DI resolution, and so you can provide a mock of the Repository methods without the need to actually talk to the database. So for example, if you have
#Injectable()
export class FooService {
constructor(#InjectRepository(Foo) private readonly fooRepo: Repository<Foo>) {}
}
In your test you can add the provider
{
provide: getRepositoryToken(Foo),
useValue: {
find: jest.fn(),
insert: jest.fn(),
},
}
And now you've got a mock injectable provider for the Repository.
The biggest reason that things have to be done this way is because typescript doesn't reflect generic classes, it only reflects Repository, and if Nest tries to figure out which repository you mean to inject, with just that name (Repository) it's most likely going to get it wrong and inject the wrong class. Using #InjectRepsitory() allows for setting the proper injection token.
I’m a newbie to mvc 5 dependency injection,I know that mvc 5 has a default parameterless constructor.But in dependency injection we create a constructor with a parameter, and IOC containers provide object to the parameter.my question is how does IOC containers like unity make mvc 5 understand the parametered constructor
The basic way that it works is that you ask the IoC container for a type ("resolve") and it will use reflection to look for the constructor (for Unity, the one with the most arguments if they are multiple constructors). It will then repeat the process for each of the argument types themselves, like a tree all the way down the dependency graph. Unity will be able to create instances of concrete types automatically but if the constructor uses an interface or abstract type then it needs to know which implementation to use so in these cases, you need to register the type beforehand:
Register:
e.g. container.RegisterType<IUserHelper, UserHelper>();
Resolve:
e.g. container.Resolve<IUserHelper>();
IOC containers do not work with MVC out of the box but extra libraries exist such as Unity.MVC5 which hook into the MVC pipeline so when MVC tries to create a controller, it uses the IoC container instead of newing up the controller directly (which would fail unless it is parameterless).
Here is an example:
public class MyController(IUserHelper userHelper, IRepository repository) : Controller
Then we could have:
public class MyRepository(IDbContext dbContext) : IRepository
and
public class MyDbContext () : IDbContext
If we use RegisterType to register the IUserHelper, IRepository and IDbContext then when MVC needs to create the controller, it will be able to build the controller complete with all the dependencies.
I'm relatively new to NestJs and am wondering how can I access the INestApplication application context created in my server bootstrap from an imported Module or Controller? I'm building a framework on top of NestJS and need access to lists of specific types components/services etc that have been provided by my framework as well as applications written with the framework.
For Modules, you are unable to do that since they will be invoked before the ApplicationContext will get bootstrapped. What might help, depending on your case, are Dynamic Modules.
For Controllers, you can use the ModuleRef, which allows you to dynamically import anything from the ApplicationContext.
Very important to note is the { strict: boolean }-option
onModuleInit() {
// Will search only inside the ModuleContext
this.service = this.moduleRef.get(Service);
// Will search in the whole application
this.service = this.moduleRef.get(Service, { strict: false });
}
Newbie question:
When working with NestJS and TypeORM, and one has created a custom repository (which extends the standard repository), is a seperate service class needed anymore?
At the moment, I'm working only with the custom Repository class and it works fine, but I'm not sure if this is correct and perhaps has some side effects.
Btw, in another project i have no custom repo, only a service which get's two standard repo's injected, and this works also fine.
Regards,
sagerobert
I think it's up to you how much you want to add layers between typeORM and your most "front-office" code (that would be the controllers in a typical nest application).
I explain myself:
If you want, you could typically inject directly the built-in typeORM repositories into your controllers:
import {Controller, Get} from '#nestjs/common';
import {InjectRepository} from '#nestjs/typeorm';
import {Repository} from 'typeorm';
import {User} from './entities/User.entity';
#Controller()
export class AppController {
constructor(
#InjectRepository(User)
private readonly userRepository: Repository<User>,
) {
}
#Get()
async root(): Promise<User> {
return await this.userRepository.find(1);
}
}
So this would be the less layered implementation of how to retrieve the user with ID = 1.
Now, the documentation of NEST recommends to abstract this repository and inject it into a service rather than in a controller directly. This allows you to have less binding between your controller and TypeORM. Instead, it's your service that has this binding. If you have many controllers that use this repository, and you decide that you want to change TypeORM and use the new fancy ORM, you'll have to change every controller.
Now, if you just inject the repository inside your service and use this service into all your controllers, you will just have to change the implementation of your service and all the controllers will remain the same.
Secondly, imagine that you want to test your application. You will face the same problem. How can you run your tests without an SQL connection? I suppose that your unit tests are not created to test the TypeORM behaviour, but instead written to test YOUR code behavior.
It will be much easier to mock a repository injected in a service than mock all repositories injected in your controllers.
So to conclude this answer, I think that this question should be closed because it is primarily opinion-based. But IMO, the dreamed architecture is the following:
Create a Custom Repository that extends the TypeORM Repository.
Inside the Custom Repository, add methods that use the Query Builder.
Inject this Custom Repository into your services
Inject the services into your controllers.
Don't ever use the query builder into controllers because it is hard to mock.
I hope this answers to your question: A service class is not needed. But it will help you keep your code clean.