Skip to content

Commit 07063be

Browse files
committed
Enhance AxiosModule to allow registering Axios interceptors at module construction
1 parent f24c5a6 commit 07063be

File tree

2 files changed

+157
-21
lines changed

2 files changed

+157
-21
lines changed

src/axios.module.ts

Lines changed: 58 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,65 @@
1-
import { Module } from "@nestjs/common";
2-
import Axios, { AxiosRequestConfig } from "axios";
1+
import { ConfigurableModuleBuilder, Module } from "@nestjs/common";
2+
import {
3+
create,
4+
type AxiosRequestConfig,
5+
type AxiosResponse,
6+
type AxiosInterceptorOptions,
7+
type InternalAxiosRequestConfig,
8+
} from "axios";
39

410
import { AxiosService } from "./axios.service";
511
import { AXIOS_PROMISE_INSTANCE_TOKEN } from "./axios.constants";
612

13+
type AxiosModuleOptions = {
14+
config?: AxiosRequestConfig;
15+
interceptors?: {
16+
response?: {
17+
onFulfilled?: (value: AxiosResponse) => AxiosResponse | Promise<AxiosResponse>;
18+
onRejected?: (error: any) => any;
19+
options?: AxiosInterceptorOptions;
20+
};
21+
request?: {
22+
onFulfilled?: (
23+
value: InternalAxiosRequestConfig,
24+
) => InternalAxiosRequestConfig | Promise<InternalAxiosRequestConfig>;
25+
onRejected?: (error: any) => any;
26+
options?: AxiosInterceptorOptions;
27+
};
28+
};
29+
};
30+
31+
const { ConfigurableModuleClass, OPTIONS_TYPE, MODULE_OPTIONS_TOKEN } =
32+
new ConfigurableModuleBuilder<AxiosModuleOptions>().build();
33+
734
@Module({
8-
providers: [AxiosService],
35+
providers: [
36+
AxiosService,
37+
{
38+
provide: AXIOS_PROMISE_INSTANCE_TOKEN,
39+
inject: [MODULE_OPTIONS_TOKEN],
40+
useFactory: (options: typeof OPTIONS_TYPE = {}) => {
41+
const axiosInstance = create(options.config ?? {});
42+
43+
if (options.interceptors?.request) {
44+
axiosInstance.interceptors.request.use(
45+
options.interceptors.request.onFulfilled,
46+
options.interceptors.request.onRejected,
47+
options.interceptors.request.options,
48+
);
49+
}
50+
51+
if (options.interceptors?.response) {
52+
axiosInstance.interceptors.response.use(
53+
options.interceptors.response.onFulfilled,
54+
options.interceptors.response.onRejected,
55+
options.interceptors.response.options,
56+
);
57+
}
58+
59+
return axiosInstance;
60+
},
61+
},
62+
],
963
exports: [AxiosService],
1064
})
11-
export class AxiosModule {
12-
static register(config: AxiosRequestConfig = {}) {
13-
return {
14-
module: AxiosModule,
15-
providers: [
16-
{
17-
provide: AXIOS_PROMISE_INSTANCE_TOKEN,
18-
useValue: Axios.create(config),
19-
},
20-
],
21-
};
22-
}
23-
}
65+
export class AxiosModule extends ConfigurableModuleClass {}

test/axios.module.test.ts

Lines changed: 99 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,111 @@ import { Test } from "@nestjs/testing";
33
import { AxiosModule, AxiosService } from "../src";
44

55
describe(AxiosModule, () => {
6-
let axiosService: AxiosService;
7-
8-
beforeEach(async () => {
6+
it("axios module export service", async () => {
97
const moduleRef = await Test.createTestingModule({
108
imports: [AxiosModule.register({})],
119
}).compile();
1210

13-
axiosService = moduleRef.get<AxiosService>(AxiosService);
11+
const axiosService = moduleRef.get<AxiosService>(AxiosService);
12+
13+
expect(axiosService).toBeDefined();
1414
});
1515

16-
it("axios module export service", () => {
16+
it("should allow registering asynchronously", async () => {
17+
const moduleRef = await Test.createTestingModule({
18+
imports: [
19+
AxiosModule.registerAsync({
20+
useFactory: () => {
21+
return {
22+
config: {},
23+
};
24+
},
25+
}),
26+
],
27+
}).compile();
28+
29+
const axiosService = moduleRef.get<AxiosService>(AxiosService);
30+
1731
expect(axiosService).toBeDefined();
1832
});
33+
34+
it("should register interceptors", async () => {
35+
const responseOnFulfilled = jest.fn();
36+
const requestOnFulfilled = jest.fn();
37+
38+
const moduleRef = await Test.createTestingModule({
39+
imports: [
40+
AxiosModule.register({
41+
interceptors: {
42+
response: {
43+
onFulfilled: (response) => {
44+
responseOnFulfilled("response");
45+
46+
return response;
47+
},
48+
},
49+
50+
request: {
51+
onFulfilled: (requestConfig) => {
52+
requestOnFulfilled("request");
53+
54+
return requestConfig;
55+
},
56+
},
57+
},
58+
}),
59+
],
60+
}).compile();
61+
62+
const axiosService = moduleRef.get<AxiosService>(AxiosService);
63+
64+
await axiosService.get("https://github.com");
65+
66+
expect(responseOnFulfilled).toHaveBeenCalledTimes(1);
67+
expect(responseOnFulfilled).toHaveBeenCalledWith("response");
68+
69+
expect(requestOnFulfilled).toHaveBeenCalledTimes(1);
70+
expect(requestOnFulfilled).toHaveBeenCalledWith("request");
71+
});
72+
73+
it("should async register interceptors", async () => {
74+
const responseOnFulfilled = jest.fn();
75+
const requestOnFulfilled = jest.fn();
76+
77+
const moduleRef = await Test.createTestingModule({
78+
imports: [
79+
AxiosModule.registerAsync({
80+
useFactory: () => ({
81+
interceptors: {
82+
response: {
83+
onFulfilled: (response) => {
84+
responseOnFulfilled("response");
85+
86+
return response;
87+
},
88+
},
89+
90+
request: {
91+
onFulfilled: (requestConfig) => {
92+
requestOnFulfilled("request");
93+
94+
return requestConfig;
95+
},
96+
},
97+
},
98+
}),
99+
}),
100+
],
101+
}).compile();
102+
103+
const axiosService = moduleRef.get<AxiosService>(AxiosService);
104+
105+
await axiosService.get("https://github.com");
106+
107+
expect(responseOnFulfilled).toHaveBeenCalledTimes(1);
108+
expect(responseOnFulfilled).toHaveBeenCalledWith("response");
109+
110+
expect(requestOnFulfilled).toHaveBeenCalledTimes(1);
111+
expect(requestOnFulfilled).toHaveBeenCalledWith("request");
112+
});
19113
});

0 commit comments

Comments
 (0)