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?
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.