Circular dependencies may arise when utilizing @UseGuards in a controller and encountering undefined dependencies

Recently, while working on my app with NestJS, I came across an issue related to the use of guards using @UseGuards(). In order to protect my controller, I created two guards as follows:

JwtAuthGuard:

import { AuthGuard } from '@nestjs/passport';

export class JwtAuthGuard extends AuthGuard('jwt') {}

ApiKeyGuard:

@Injectable()
export class ApiKeyGuard implements CanActivate {
  constructor(private configService: ConfigService) {}

  canActivate (context: ExecutionContext) {
    const request = context.switchToHttp().getRequest();
    const { apikey } = request.headers;

    if (apikey === env.get('API_KEY')) return true;
    else throw new UnauthorizedException();
  }
}

This is how my Controller is set up:

@Get('/:users')
  @UseGuards(ApiKeyGuard)
  getUser(): {
    return this.userService.getUser();
  }

The services associated with the Controller are defined like this:

@Injectable()
export class UserService {
  constructor(private dummyService:DummyService) {}

  getUser() {
    return this.dummyService.getUser();
  }

Additionally, here is the content of the module.ts file:

@Module({
  imports: [...],
  controllers: [userController],
  providers: [....],
  exports: [UserService],
})
export class CouponModule {}

I also have another module named CouponModule which includes a CouponController utilizing @UseGuard(), along with its respective services. The CouponService shows circular dependencies with the UserService and also relies on the DummyService.

Challenge: Upon implementing the @UseGuards(ApiKeyGuard) in the controller, I began encountering errors whenever the app processed requests:

TypeError: Cannot read property 'getUser' of undefined

Strangely enough, when switching to @UseGuards(JwtAuthGuard), the app worked fine without any errors. Even after removing the @UseGuards() decorator, the error persisted.

In an attempt to resolve this issue, I added the DummyServices to the providers section of both modules' module.ts files, but unfortunately, the problem remained unsolved.

Despite conducting extensive research and investigation, I have yet to identify the root cause or find a suitable solution for this dilemma.

Answer №1

Perhaps the issue stems from a circular dependency that requires time to load all essential dependencies such as providers and services.

Your JwtAuthGuard implementation takes time to retrieve and validate the token, allowing for the loading of necessary dependencies which is why your app functions correctly with it.

In contrast, the apiKeyGuards operates differently by simply validating based on text comparison, allowing requests to pass through before all dependencies are fully loaded resulting in undefined behavior.

The solution is straightforward - slightly delay the api key validation using the sleep() function provided below:

//api-key.strategy.ts
@Injectable()
export class ApiKeyStrategy extends PassportStrategy(Strategy, 'apiKey') {
  constructor(private readonly authService: AuthService) {
    super();
  }

  async validate(request: string): Promise<void> {
    await sleep(0);
    const isValid = await this.authService.validateApiKey(request);
    if (!isValid) {
      throw new UnauthorizedException('Invalid API Key');
    }
    return user;
  }

  override async authenticate(request: Request): Promise<void> {
    if (!apiKey) {
      this.fail('API Key is missing');
      return;
    }

    try {
      const user = await this.validate(apiKey);
      this.success(user);
    } catch (error) {
      this.fail(error);
    }
  }
}

//sleep.ts
export function sleep(ms: number, fn?: () => void) {
  return new Promise((res) => {
    setTimeout(() => {
      fn?.();
      res('process is sleeping!');
    }, ms);
  });
}

Answer №2

It seems like the issue lies with configService being injected into ApiKeyGuard. To troubleshoot, try removing the injection from the constructor. If everything runs smoothly after that, verify if configService is a global variable or not.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Looking to personalize the MUI - datatable's toolbar and place the pagination at the top?

I successfully managed to hide the toolbar icon, but I am struggling with positioning pagination from bottom to top. Additionally, I am attempting to add two buttons (reset and apply) in the view-Column toolbar without any success in customizing the class. ...

Step-by-step guide on developing an AngularJs provider using TypeScript

As I've developed a Directive that incorporates various Css classes, it would greatly enhance its flexibility if the Css classes could be configured at Application start within the config section. I believe utilizing a provider is the appropriate appr ...

I'm curious as to why my form data is being transmitted as application/json during my POST request, and what is causing it to generate a Bad Request error?

When adding a hotel to the database using react-hook-form, I include images as part of the form input. After submitting the form, the data is converted into FormData and then sent to the API for processing. The conversion and submission of the form take p ...

Angular 8: Bridging the gap between two players with a shared singleton service

I've been working on creating a multiplayer Battleships game, and although the basic functionality is there, I'm struggling to connect two players to the same game. Any assistance would be greatly appreciated! My goal is to create a service that ...

The error message "Undefined error in Angular 8 when waiting for API call to finish" appears when

if(this.datashare.selectedtableId!=null) { console.log( "inside if condition"); let resp= this.http.get(this.global.apiUrl+"columns/"+this.datashare.selectedtableId); resp.subscribe((data)=>this.users=data); conso ...

What causes the lack of impact on lambda rendering speed despite integrating webpack?

Hey there, I've been working on implementing webpack for a project that involves microservices, Node.js, TypeScript, AWS, and AWS SAM. My main objectives are: Reduce the cold start time of lambda functions. Minimize security vulnerabilities by e ...

The functionality of the String prototype is operational in web browsers, but it encounters issues

Version: 8.1.0 The prototype I am working with is as follows: String.prototype.toSlug = function () { return (<string>this) .trim() .toLowerCase() .replace(/\s+/g, '-') .replace(/[^\w\-]+/g, '') ...

A programming element that is capable of accessing a data member, but mandates the use of a setter method for modifications

I am unsure whether I need a class or an interface, but my goal is to create an object with a member variable that can be easily accessed like a regular variable. For example: interface LineRange { begin: number; end: number; } However, I want th ...

Using `delay` in rxjs causes Protractor end-to-end tests to exceed the time limit

After running ng e2e on my application, I encountered the following error: Failed: Timed out waiting for asynchronous Angular tasks to finish after 11 seconds. Inspecting the app.component.ts, it is evident that 'app' is published 15 seconds ...

To close the Muix DateTimePicker, simply hit the Escape key or click anywhere outside of the picker

I'd like the DateTimePicker to only close when the user presses the action buttons, not when they click outside or press Escape. Unfortunately, I haven't found any props to control this behavior yet. <DesktopDatePicker closeOnSelect={false} s ...

Is there a way to effectively utilize getServerSideProps within components?

Is there a way to utilize getServerSideProps in components the same way it's used in pages? I'm unsure how to pass sanity data into components. Edit: Issue resolved - turns out I was missing the props! :) ...

Incorporate the teachings of removing the nullable object key when its value is anything but 'true'

When working with Angular, I have encountered a scenario where my interface includes a nullable boolean property. However, as a developer and maintainer of the system, I know that this property only serves a purpose when it is set to 'true'. Henc ...

"Utilize the handle property of a component when interacting with the window.onclick

In my component, I have a property called enableButtons which is set to true when I click on an ion-menu label. However, I want this property to revert to false if I click anywhere else. Here's the code I tried: export class ProfilePage implements OnI ...

An informative step-by-step approach to constructing Angular applications utilizing npm and TypeScript

When I first encountered Angular2, I was introduced to TypeScript, npm, and more for the very first time. I was amazed by their power, but I know I've only scratched the surface. While I can navigate through the "development mode," my ultimate goal i ...

How can a checkbox be implemented in Angular without using ngModel? What alternative should be used instead

I am currently looking to enhance a checkbox that used to handle backend calls, but now only needs to function as a simple checkbox that turns off other checkboxes when selected: <label class="custom-control custom-checkbox" style="di ...

Struggling to make even the most basic example work with TypeScript and npm modules

After stumbling upon this repository that made using npm modules within a Typescript program look easy, I decided to give it a try by forking it and making some changes. My goal was to add another package to get a better understanding of the process. So, I ...

Issue: MUI Autocomplete and react-hook-form failing to show the chosen option when using retrieved information

The MUI Autocomplete within a form built using react hook form is causing an issue. While filling out the form, everything works as expected. However, when trying to display the form with pre-fetched data, the Autocomplete only shows the selected option af ...

Tips for Automatically Populating Content in The Quill Js Editor Within Angular

Seeking some assistance. In my Angular application, I have received data from an API. I am trying to prefill the Quill Editor input box with the obtained data, but unfortunately, it doesn't accept the value attribute. This approach didn't work: ...

Utilizing Object.fromEntries in Typescript

I am attempting to define a type called ObjectFromEntries that functions similarly to the return type of the Object.fromEntries function. Here is what I have so far: type ObjectFromEntries<Entries extends [keyof any, any][]> = { [key in Entries[numb ...

Automate your builds with Github actions for both tags and branches!

In my typescript project repository, our release policy states that we publish packages from the master branch to the next npm tag. Additionally, we have a dedicated branch called release for publishing to the latest npm tag. My goal is to optimize the sol ...