When utilizing the registerAsync method in a Nest module, the framework may encounter difficulties in resolving dependencies

When attempting to import a Module using registerAsync and configuring it with a provider from my module, I encounter an error stating that the provider cannot be found. Can anyone help identify what I am missing?

Here is my code snippet:

import { CacheModule, Module } from '@nestjs/common';

@Module({
  imports:     [
    CacheModule.registerAsync({
      useFactory: async (options) => ({
        ttl: options.ttl,
      }),
      inject: ['MY_OPTIONS'],
    }),
  ],
  providers:   [
    {
      provide:  'MY_OPTIONS',
      useValue: {
        ttl: 60,
      },
    },
  ],
})
export class AppModule {
}

Error message received:

Error: Nest can't resolve dependencies of the CACHE_MODULE_OPTIONS (?). Please make sure that the argument MY_OPTIONS at index [0] is available in the CacheModule context.

The provided example simplifies my actual code, but the core issue remains: I have a provider within the AppModule that needs to be accessed in the CacheModule.registerAsync() function.

If anyone would like to assist in troubleshooting this problem, I have created a simple repository here: https://github.com/MickL/nestjs-inject-existing-provider

Answer №1

This may seem unusual, but even with the same @Module, it's necessary to explicitly inform the dependency manager about imports and exports as shown below:

import { CacheModule, Module } from '@nestjs/common';

@Module({
  imports:     [
    CacheModule.registerAsync({
      imports: [AppModule], // <-- ADDED
      useFactory: async (options) => {
        console.log('MY_OPTIONS', options) // <-- LOGS FINE upon NestFactory.create(AppModule)
        return {
          ttl: options.ttl,
        }
      },
      inject: ['MY_OPTIONS'],
    }),
  ],
  providers:   [
    {
      provide:  'MY_OPTIONS',
      useValue: {
        ttl: 60,
      },
    },
  ],
  exports: ['MY_OPTIONS'] // <-- ADDED
})
export class AppModule {
}

REVISITED

After examining your repository, particularly the file src/my-lib.module.ts, the following appears to be functioning (though not completely resolving the underlying issue):

export class MyLibModule {
  // changed to async version by returning Promise
  static register(options: ModuleOptions): Promise<DynamicModule> {
    // retains reference to newly created module
    const OptionsModule = MyLibOptionsModule.register(options)
    // prints 'true', yet importing MyLibOptionsModule still doesn't work
    console.log('who-am-i', OptionsModule.module === MyLibOptionsModule)
    return Promise.resolve({
      module: MyLibModule,
      imports: [
        // OptionsModule, // seems unnecessary
        HttpModule.registerAsync({
          useFactory: ((options: ModuleOptions) => {
            console.log("Works:", options);
            return {
              url: options.externalApiUrl,
              timeout: options.timeout
            };
          }),
          // successfully imports using the newly created reference
          imports: [OptionsModule],
          inject: [MODULE_OPTIONS]
        })
      ]
    });
  }
}

Answer №2

The issue arises from the discrepancy in level between "CacheModule.registerAsync" and "AppModule", resulting in a provider defined in "AppModule" not being accessible to "CacheModule.registerAsync".

If we were to transfer the "MY_OPTIONS" to a separate module called "CacheConfigModule", the code could be structured like this:

CacheConfigModule.ts

import { Module } from '@nestjs/common';

@Module({
  providers: [
    {
      provide: 'MY_OPTIONS',
      useValue: {
        ttl: 60
      }
    }
  ],
  exports: ['MY_OPTIONS']
})
export class CacheConfigModule {}

AppModule.ts

import { CacheModule, Module } from '@nestjs/common';
import { CacheConfigModule } from './CacheConfigModule';

@Module({
  imports: [
    CacheConfigModule,
    CacheModule.registerAsync({
      imports: [CacheConfigModule],
      useFactory: async (options) => ({
        ttl: options.ttl
      }),
      inject: ['MY_OPTIONS']
    })
  ]
})
export class AppModule {}

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

Ways to Prompt a User to Select the "Remember Me" Option

How can I implement the functionality of 'Remember Me' on a login page? I want users who click on 'Remember Me' to be able to reopen the page without logging in again, even after closing their browser. But how do I differentiate between ...

Exploring the new possibilities of Angular 5: Enhanced REST API service with paginated data and object mapping capabilities

After implementing pagination in my REST API backend, I now need to update my Angular services to accommodate the changes. Instead of simply returning an array of objects, the API will now return JSON responses structured like this: { "count": 0, ...

Implementing numeric user id with next-auth is a straightforward process that involves setting up

Recently, I came across create-t3-app and decided to try it out for my NextJS projects. It handles a lot of the initial setup work for TypeScript, trpc, prisma, and next-auth, which would save me a significant amount of time. While this is beneficial, it d ...

Exporting items with a label in TypeScript/JavaScript

Is it possible to rename the functions that are exported using the following syntax in Typescript/Javascript? export const { selectIds, selectEntities, selectAll, selectTotal } = adapter.getSelectors(selectState); I would like to import selectAll as sele ...

Developing mongoose models using TypeScript for subdocuments

Exploring the integration of mongoose models with typescript, following a guide available at: https://github.com/Appsilon/styleguide/wiki/mongoose-typescript-models. Unsure how arrays of subdocuments align with this setup. For instance, consider the model ...

"An error occurred in Angular2 where the first index of the array

When I try to push the Google coordinates into an array, I am encountering some issues. Even though I have added the data, when I print console.log(this.markersData) it shows up as an empty array with objects-->[] However, on the second click, I am abl ...

Retrieve the ultimate information from the Angular service

Within my angular 6 project, I am dealing with a product_id array, product_id: any = ["123", "456"]; ngOnInit : ngOnInit() { this.product_id.forEach(element => { this.httpClient.get('https://api.myjson.com/bins/hiolc').subscribe ...

Tips for verifying the response and status code in Angular 8 while uploading a file to an S3 Presigned URL and receiving a statusCode of 200

Looking to Upload a File: // Using the pre-signed URL to upload the file const httpOptions = { headers: new HttpHeaders({ 'Content-Disposition': 'attachment;filename=' + file.name + '', observe: 'response' }) }; ...

Images in the Ionic app are failing to display certain asset files

Currently, I am working on an Ionic 4 app for both Android and iOS platforms. The issue I am facing is that only SVG format images are displaying in the slide menu, even though I have images in both SVG and PNG formats. public appPages = [ { ...

Having trouble with Jasmine timeout due to asynchronous testing in Angular?

After upgrading a project to Angular 6, some previously successful tests are now failing. Below is an example of one such test: beforeEach( async(() => { TestBed.configureTestingModule({ declarations: [CampaignsDetailScheduleCompone ...

Nextjs and Typescript are giving me an error that says, "The property 'nextUrl' is not found on type 'IncomingMessage'." What could be causing this

I'm currently utilizing the Next.js API route and attempting to retrieve the request parameters: export const GET = async (req: IncomingMessage) => { const matchString: String = req.nextUrl.searchParams.get("data") } I assume the typ ...

Can you explain the purpose of the "letter:" included in the code and how it is utilized?

g: function testFunction() { return true; } h: function anotherTestFunction() { } i: console.log('test') I'm intrigued by the mystery of this code snippet. As is written, I am executing it in NodeJS version 16 or higher and trying to un ...

(TypeScript) Generate a type based on the input parameter type

Below is the code snippet I am working with: const Settings = { setting1: 10, setting2: true, }; type S = typeof Settings; function Process<M extends keyof S>(input: { option: M; value: S[M] }) { } If I try to call Process with an incorr ...

Firebase console does not show any console.log output for TypeScript cloud functions

I encountered an issue while using Typescript to write some Firebase cloud functions. Here is a snippet of my code: index.ts export * from "./Module1"; Module1.ts import * as functions from "firebase-functions"; export const test = functions.https.onR ...

Comparison between instanceof and constructor.name

Background information: Currently, our application retrieves images from a GET API Accept: 'application/octet-stream', responseType: 'blob' and we utilize the following method to display the image on the user interface. let imageUrl ...

Testing the selection of dropdown values in Angular2 using unit tests

I have a dropdown menu for selecting countries. It defaults to a pre-selected value, and when the user changes it, they are redirected to the corresponding country page. However, I am facing an issue while trying to unit test the default value in the sele ...

What could be causing the issue with my React Native app's release version not opening on a physical Android device?

I encountered an issue while trying to install the Release version of my application. In order to test both the debug and release versions on my physical and virtual devices, I utilized the following commands: ./gradlew assembleDebug, ./gradlew assembleRel ...

How do I retype an interface from a dependency?

It's difficult to put into words, so I have created a repository for reference: https://github.com/galenyuan/how-to-retyping My goal is to achieve the following: import Vue from 'vue' declare module 'vuex/types/vue' { interfac ...

The Angular (click) event requires two clicks in order to trigger the associated Typescript function

I'm facing an issue with a Typescript function that I've linked to (click) in my HTML. Oddly, I have to click the button twice for the function to be executed. Interestingly, if I don't provide any parameters, the function works as expected ...

What could be the reason for the esm loader not recognizing my import?

Running a small express server and encountering an issue in my bin/www.ts where I import my app.ts file like so: import app from '../app'; After building the project into JavaScript using: tsc --project ./ and running it with nodemon ./build/bin ...