typescriptaxiosnestjs

How to create multiple Axios instances in NestJS


I am converting an existing Express application to NestJS, currently I have a config file where I create multiple axios instances for each microservice:

export const writeModelApi = axios.create({
  baseURL: getWriteModelApiUrl(),
});

export const readModelApi = axios.create({
  baseURL: getReadModelApiUrl(),
});

export const configApi = axios.create({
  baseURL: getConfigApiUrl(),
});

function addCamelizeInterceptors(api: any) {
  api.interceptors.request.use(
    (config: AxiosRequestConfig): AxiosRequestConfig => {
      config.data = decamelizeKeys(config.data);

      return config;
    },
    (error: any) => {
      return Promise.reject(error);
    }
  );
  
  api.interceptors.response.use(
    (response: AxiosResponse): AxiosResponse => {
      response.data = camelizeKeys(response.data);

      return response;
    },
    (error: any) => {
      if (error.response != null) { 
        error.response.data = camelizeKeys(error.response.data);
      }

      return Promise.reject(error);
    }
  );
}

addCamelizeInterceptors(taskingApi);
addCamelizeInterceptors(readModelApi);
addCamelizeInterceptors(configApi);

I thought of replicating this using shared modules in nestjs, currently I have this:

@Module({
  imports: [
    HttpModule.register({
      baseURL: getReadModelApiUrl(),
    }),
  ],
  providers: [ReadModelService],
  exports: [ReadModelService],
})
export class ReadModelModule implements OnModuleInit {
  constructor(@Inject() private httpService: ReadModelService) {}

  public onModuleInit() {
    addCamelizeInterceptors(this.httpService.axiosRef);
  }
}

@Injectable()
export class ReadModelService extends HttpService {}

but nest is giving me an error saying:

[ExceptionHandler] Nest can't resolve dependencies of the ReadModelModule (?). Please make sure that the argument dependency at index [0] is available in the ReadModelModule context.

Potential solutions:
- If dependency is a provider, is it part of the current ReadModelModule?
- If dependency is exported from a separate @Module, is that module imported within ReadModelModule?
  @Module({
    imports: [ /* the Module containing dependency */ ]
  })

I am really not sure how to do this. Can someone help?


Solution

  • For future reference I ended up doing a bit of a hack. I went through NestJs code and noticed there's currently no way of extending the HttpService because the provider constant needed for its constructor is not exposed (AXIOS_INSTANCE_TOKEN).

    So I created my own version of the HttpModule and provided the needed constant so my service could extend HttpService.

    Here's my code:

    MyHttpModule:

    export const AXIOS_INSTANCE_TOKEN = "AXIOS_INSTANCE_TOKEN";
    
    @Module({
      providers: [
        ReadModelService,
        {
          provide: AXIOS_INSTANCE_TOKEN,
          useValue: Axios,
        },
      ],
      exports: [ReadModelService],
    })
    export class MyHttpModule {}
    

    ReadModelService:

    @Injectable()
    export class ReadModelService extends HttpService {
      constructor() {
        const instance = Axios.create({
          baseURL: getReadModelApiUrl(),
        });
        addCamelizeInterceptors(instance);
    
        super(instance);
      }
    }
    

    This allows me to use the ReadModelService like I would use HttpService, but with a baseURL and axios interceptors. I also created a similar service for WriteModelService and others. I am not sure this is the best solution possible, but it works as intended and there's not much code needed.