Nest.js - nest cli is not picking up the latest file changes - nestjs

I wrote a very basic controller like
#Controller('tasks')
export class TasksController {
constructor(private tasksService: TasksService) {}
#Get(':id')
getById(#Param('id') id: string): TaskDto {
console.log('Get Called>>>', id);
const task = this.tasksService.getById(id);
const dto = TaskMapper.toDto(task);
return dto;
}
#Delete(':id')
remove(#Param('id') id: string): void {
console.log('Delete Called>>>', id);
this.tasksService.remove(id);
}
}
I'm using the following URI to call each endpoint via Postman (also tried with the Powershell) with their respective METHOD GET, DELETE.
http://localhost:3000/tasks/83b213a0-8cbf-46e0-a484-e3df7f216e2f
Now, the strangest thing is that CLI is somehow got stuck at one version of the Controller file. Now even if I delete the whole controller, the cli is still mapping the different methods of the Controller.
I've tried different methods of starting the application via various yarn, npm and directly nest commands but nothing seems to pick up the latest file changes.
I've gone through the whole code a zillion times but unable to pinpoint the issue!

Finally got it working, solution was to delete the "dist" folder.
But I still don't understand why this problem occurred in the first place!!

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 :)

NestJs: How can I import one repository into another?

I apologize for what is likely a very amateur question. Coming from Laravel, this is still quite confusing to me and I just don't understand what is needed.
I have a user.repository.ts file and a location.repository.ts file. Each have their own modules, controllers and services. I have successfully created CRUD operations for each entity but now am trying to work towards a Many to Many relationship.
In my user.repository.ts file, I am trying to save a related (many to many) repository:
// user.repository.ts
user.locations = await this.locationRepository.findByIds(locations);
...
await user.save();
I am not sure how to inject or import the location.repository.ts file. I have tried numerous variations of importing the service into each module. Or importing each module into the other module. I have tried different versions of this:
#EntityRepository(User)
#EntityRepository(Location)
Or importing the LocationService into the UserService.
In Laravel, this would be as "simple" as $model->sync($relationship);
How can I import/inject the locationRepository into my userRepository? Thank you for any suggestions!
I assume this question is related to your last question, the simplest way to implement it, Add Locationentity to your UserModule
#Module({
imports:[TypeOrmModule.forFeature([UserRepository,LocationRepository])], // or just Location entity [UserRepository,Location] if you didn't setup a custom LocationRepository
After that, inject it in your as what you did for userRepo... service
constructor(
#InjectRepository(LocationRepository)
private locationRepository: LocationRepository,
// or just private locationRepository: Repository<Location>,
) {}
In the create method service get your locations:
async createUser(createUserDto: CreateUserDto) { // usersSrvice
let locations = await this.locationRepository.findByIds(createUserDto.locations);
await this.userRepository.createMethodeName(createUserDto,locations) // add secand
params for your locations
don't hesitate to ask if you have any other questions

how to extend Request type in Express with custom property

I am trying to set up a custom middleware function in Node.js with typescript, where I want to store a decoded json web token into a custom request property 'user' like this
function auth(req: Request, res: Response, next: NextFunction) {
const decodedToken = jwt.verify(token, config.get("secret"));
req.user = decodedToken.user;
next();
}
but I keep getting a compiler error in the terminal
error TS2339: Property 'user' does not exist on type 'Request<ParamsDictionary, any, any, ParsedQs>'.
I found several answers on here that suggested creating a custom.d.ts file and extend the Request type which I did like this:
namespace Express {
interface Request {
user?: string;
}
}
now, the VS Code is happy, I get no linting, I get the correct intellisense and autocompletion and it does not let me assign a number, because it understands it needs to be a string. So it obviously works. However, when I run the code the terminal keeps giving me the same error and insists that property 'user' does not exist.
I tried restarting the TS server but that did not help.
I can make it work by creating a custom interface which extends the Request type and then using that, but I really want to know how to do it with the original Request type.
There's no way to do it on the original object with typescript - that's coming from Express and you're importing it from Express. The best you can do there is extend it like you have, or ignore the errors.
You definitely can do it in theory - you can add whatever you want to the req object in a middleware because it's just that - a javascript object. The warning you're getting is from typescript, not Express.
In practice, what you'd normally do is use res.locals for something like this. In typescript, it's defined as locals: Record<string, any>. So you could set res.locals.user in your middleware and then access it later wherever you want.
I'm not sure if I'm understanding this quite right, but, I think that the best solution is to create a custom Request class, adding this property.
export class CRequest extends Request {
user?: string
//add stuff to constructor etc
}
Now, you want to make it an interface, just replace class with interface
I also do not reccomend you use the same name as Express & Request
I managed to make it work after a lot of googling and playing with folder structure and tsconfig.json file. I put the custom.d.ts file in ./#types/express (the sub-folder has to be there) and set the typeRoots in tsconfig.json like this:
compilerOptions: {
"typeRoots": ["./#types"],
}
I also had to declare the namespace in custom.d.ts
declare namespace Express {
interface Request {
user: any;
}
}
Now it compiles without error

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

Can't pass GET parameter while unit testing Zend Framework 2

I'm having hard time trying to unit test (phpUnit) one of my modules in ZF2. What I'm trying to do is determine whether a classname is present on one of the elements on page when a GET parameter is passed to the controller.
It all works from the browser, however I can't get the GET parameter to be recognized at all when trying to unit test.
This is my code for unit testing:
<?php
namespace ComponentManager\Controller;
use Zend\Test\PHPUnit\Controller\AbstractHttpControllerTestCase;
class ComponentManagerControllerTest extends AbstractHttpControllerTestCase
{
public function setUp()
{
$this->setApplicationConfig(
include 'config/application.config.php'
);
parent::setUp();
}
public function testAdminComponentCodeCanBeAccessed()
{
$this->dispatch('/ComponentManager/requestComponent/product/details-1/details-1', 'GET', array('admin' => 1));
// I also tried: $this->dispatch('/ComponentManager/requestComponent/product/details-1/details-1?admin=1');
$this->assertResponseStatusCode(200);
$this->assertMatchedRouteName('ComponentManager/path');
$this->assertControllerName('ComponentManager\Controller\ComponentManager');
$this->assertControllerClass('ComponentManagerController');
$this->assertActionName('requestComponent');
$this->assertModuleName('ComponentManager');
// test will fail here
$this->assertQuery('div.config-active-wrapper');
}
}
The "div.config-active-wrapper" selector works fine when I remove the check for admin parameter presence in GET but when I re-add it, the GET parameter doesn't get recognised at all. Any ideas?
The problem here was that unit testing is a CLI operation and no superglobals are being populated while in CLI. Simple and stupid :P
A solution is to not use superglobals like $_GET here but to pass this "admin" parameter via some ACL and a controller instead.

Resources