Skip to content

Commit dd54ba9

Browse files
committed
refactor: stop extending Axios in HttpService, expect an instance instead
closes #1424
1 parent 37acfee commit dd54ba9

File tree

33 files changed

+166
-209
lines changed

33 files changed

+166
-209
lines changed

apps/api/src/chain/services/block-http/block-http.service.spec.ts

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,23 +2,26 @@ import "@test/mocks/logger-service.mock";
22

33
import { BlockHttpService as BlockHttpServiceCommon } from "@akashnetwork/http-sdk";
44
import { faker } from "@faker-js/faker";
5+
import axios from "axios";
56

67
import { BlockHttpService } from "./block-http.service";
78

89
describe(BlockHttpService.name, () => {
9-
let service: BlockHttpService;
10-
let blockHttpService: BlockHttpServiceCommon;
10+
it("should get current height", async () => {
11+
const { height, blockHttpService } = setup();
12+
13+
const result = await blockHttpService.getCurrentHeight();
1114

12-
beforeEach(() => {
13-
blockHttpService = new BlockHttpServiceCommon();
14-
service = new BlockHttpService(blockHttpService);
15+
expect(result).toBe(height);
1516
});
1617

17-
it("should get current height", async () => {
18+
const setup = () => {
19+
const blockHttpServiceCommon = new BlockHttpServiceCommon(axios.create());
20+
const blockHttpService = new BlockHttpService(blockHttpServiceCommon);
21+
1822
const height = faker.number.int({ min: 1000000, max: 10000000 });
19-
jest.spyOn(blockHttpService, "getCurrentHeight").mockResolvedValue(height);
20-
const result = await service.getCurrentHeight();
23+
jest.spyOn(blockHttpServiceCommon, "getCurrentHeight").mockResolvedValue(height);
2124

22-
expect(result).toBe(height);
23-
});
25+
return { height, blockHttpServiceCommon, blockHttpService };
26+
};
2427
});

apps/api/src/core/providers/http-sdk.provider.ts

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import {
1111
NodeHttpService,
1212
ProviderHttpService
1313
} from "@akashnetwork/http-sdk";
14+
import axios from "axios";
1415
import { container } from "tsyringe";
1516

1617
import { apiNodeUrl, nodeApiBasePath } from "@src/utils/constants";
@@ -26,8 +27,8 @@ const SERVICES = [
2627
CosmosHttpService
2728
];
2829

29-
SERVICES.forEach(Service => container.register(Service, { useValue: new Service({ baseURL: apiNodeUrl }) }));
30+
SERVICES.forEach(Service => container.register(Service, { useValue: new Service(axios.create({ baseURL: apiNodeUrl })) }));
3031

31-
container.register(GitHubHttpService, { useValue: new GitHubHttpService({ baseURL: "https://raw.githubusercontent.com" }) });
32-
container.register(CoinGeckoHttpService, { useValue: new CoinGeckoHttpService({ baseURL: "https://api.coingecko.com" }) });
33-
container.register(NodeHttpService, { useValue: new NodeHttpService({ baseURL: nodeApiBasePath }) });
32+
container.register(GitHubHttpService, { useValue: new GitHubHttpService(axios.create({ baseURL: "https://raw.githubusercontent.com" })) });
33+
container.register(CoinGeckoHttpService, { useValue: new CoinGeckoHttpService(axios.create({ baseURL: "https://api.coingecko.com" })) });
34+
container.register(NodeHttpService, { useValue: new NodeHttpService(axios.create({ baseURL: nodeApiBasePath })) });

apps/api/test/services/test-wallet.service.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { BalanceHttpService } from "@akashnetwork/http-sdk";
22
import type { EncodeObject } from "@cosmjs/proto-signing";
33
import { coins } from "@cosmjs/proto-signing";
44
import { calculateFee, GasPrice, SigningStargateClient } from "@cosmjs/stargate";
5+
import axios from "axios";
56
import dotenv from "dotenv";
67
import dotenvExpand from "dotenv-expand";
78
import * as fs from "fs";
@@ -19,9 +20,11 @@ const MIN_AMOUNTS: Record<string, number> = {
1920
};
2021

2122
export class TestWalletService {
22-
private readonly balanceHttpService = new BalanceHttpService({
23-
baseURL: config!.API_NODE_ENDPOINT
24-
});
23+
private readonly balanceHttpService = new BalanceHttpService(
24+
axios.create({
25+
baseURL: config!.API_NODE_ENDPOINT
26+
})
27+
);
2528

2629
private mnemonics: Record<string, string> = {};
2730

apps/deploy-web/src/components/turnstile/Turnstile.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,10 @@ let originalFetch: typeof fetch | undefined;
2727

2828
const addResponseInterceptor = (intercept: (service: Axios, value: AxiosError) => AxiosResponse | Promise<AxiosResponse>) => {
2929
const removes = HTTP_SERVICES.map(service => {
30-
const interceptorId = service.interceptors.response.use(null, error => intercept(service, error));
30+
const interceptorId = service.axios.interceptors.response.use(null, error => intercept(service.axios, error));
3131

3232
return () => {
33-
service.interceptors.response.eject(interceptorId);
33+
service.axios.interceptors.response.eject(interceptorId);
3434
};
3535
});
3636

apps/deploy-web/src/context/ServicesProvider/ServicesProvider.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ export function useServices() {
3131

3232
function createAppContainer<T extends Factories>(settings: Settings, services: T) {
3333
const di = createChildContainer(rootContainer, {
34-
authzHttpService: () => new AuthzHttpService({ baseURL: settings?.apiEndpoint }),
34+
authzHttpService: () => new AuthzHttpService(rootContainer.createAxios({ baseURL: settings?.apiEndpoint })),
3535
walletBalancesService: () => new WalletBalancesService(di.authzHttpService, di.chainApiHttpClient, browserEnvConfig.NEXT_PUBLIC_MASTER_WALLET_ADDRESS),
3636
certificatesService: () => new CertificatesService(di.chainApiHttpClient),
3737
chainApiHttpClient: () => rootContainer.createAxios({ baseURL: settings?.apiEndpoint }),

apps/deploy-web/src/queries/useBalancesQuery.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ export function useBalances(address?: string, options?: Omit<UseQueryOptions<Bal
1010
return useQuery({
1111
queryKey: QueryKeys.getBalancesKey(address) as QueryKey,
1212
queryFn: () => (address ? di.walletBalancesService.getBalances(address) : null),
13-
enabled: !!address && !!di.authzHttpService.getUri(),
13+
enabled: !!address && !!di.authzHttpService.axios.getUri(),
1414
...options
1515
});
1616
}

apps/deploy-web/src/queries/useGrantsQuery.spec.tsx

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,9 @@ describe("useGrantsQuery", () => {
2828
};
2929

3030
const authzHttpService = mock<AuthzHttpService>({
31-
defaults: { baseURL: "https://api.akash.network" },
31+
axios: {
32+
defaults: { baseURL: "https://api.akash.network" }
33+
} as AxiosInstance,
3234
getPaginatedDepositDeploymentGrants: jest.fn().mockResolvedValue(mockData)
3335
});
3436
const { result } = setupQuery(() => useGranterGrants("test-address", 0, 1000), {
@@ -46,7 +48,9 @@ describe("useGrantsQuery", () => {
4648

4749
it("does not fetch when address is not provided", () => {
4850
const authzHttpService = mock<AuthzHttpService>({
49-
defaults: { baseURL: "https://api.akash.network" },
51+
axios: {
52+
defaults: { baseURL: "https://api.akash.network" }
53+
} as AxiosInstance,
5054
getPaginatedDepositDeploymentGrants: jest.fn().mockResolvedValue([])
5155
});
5256
setupQuery(() => useGranterGrants("", 0, 1000), {
@@ -69,7 +73,9 @@ describe("useGrantsQuery", () => {
6973
}
7074
];
7175
const authzHttpService = mock<AuthzHttpService>({
72-
defaults: { baseURL: "https://api.akash.network" },
76+
axios: {
77+
defaults: { baseURL: "https://api.akash.network" }
78+
} as AxiosInstance,
7379
getAllDepositDeploymentGrants: jest.fn().mockResolvedValue(mockData)
7480
});
7581

@@ -88,7 +94,9 @@ describe("useGrantsQuery", () => {
8894

8995
it("does not fetch when address is not provided", () => {
9096
const authzHttpService = mock<AuthzHttpService>({
91-
defaults: { baseURL: "https://api.akash.network" },
97+
axios: {
98+
defaults: { baseURL: "https://api.akash.network" }
99+
} as AxiosInstance,
92100
getAllDepositDeploymentGrants: jest.fn().mockResolvedValue([])
93101
});
94102
setupQuery(() => useGranteeGrants(""), {
@@ -108,7 +116,9 @@ describe("useGrantsQuery", () => {
108116
pagination: { total: 1 }
109117
};
110118
const authzHttpService = mock<AuthzHttpService>({
111-
defaults: { baseURL: "https://api.akash.network" },
119+
axios: {
120+
defaults: { baseURL: "https://api.akash.network" }
121+
} as AxiosInstance,
112122
getPaginatedFeeAllowancesForGranter: jest.fn().mockResolvedValue(mockData)
113123
});
114124

@@ -127,7 +137,9 @@ describe("useGrantsQuery", () => {
127137

128138
it("does not fetch when address is not provided", () => {
129139
const authzHttpService = mock<AuthzHttpService>({
130-
defaults: { baseURL: "https://api.akash.network" },
140+
axios: {
141+
defaults: { baseURL: "https://api.akash.network" }
142+
} as AxiosInstance,
131143
getPaginatedFeeAllowancesForGranter: jest.fn().mockResolvedValue([])
132144
});
133145
setupQuery(() => useAllowancesIssued("", 0, 1000), {

apps/deploy-web/src/queries/useGrantsQuery.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ export function useGranterGrants(
1717
const { authzHttpService } = useServices();
1818
const offset = page * limit;
1919

20-
options.enabled = options.enabled !== false && !!address && !!authzHttpService.defaults.baseURL;
20+
options.enabled = options.enabled !== false && !!address && !!authzHttpService.axios.defaults.baseURL;
2121

2222
return useQuery({
2323
queryKey: QueryKeys.getGranterGrants(address, page, offset),
@@ -29,7 +29,7 @@ export function useGranterGrants(
2929
export function useGranteeGrants(address: string, options: Omit<UseQueryOptions<DepositDeploymentGrant[]>, "queryKey" | "queryFn"> = {}) {
3030
const { authzHttpService } = useServices();
3131

32-
options.enabled = options.enabled !== false && !!address && !!authzHttpService.defaults.baseURL;
32+
options.enabled = options.enabled !== false && !!address && !!authzHttpService.axios.defaults.baseURL;
3333

3434
return useQuery({
3535
queryKey: QueryKeys.getGranteeGrants(address || "UNDEFINED"),
@@ -47,7 +47,7 @@ export function useAllowancesIssued(
4747
const { authzHttpService } = useServices();
4848
const offset = page * limit;
4949

50-
options.enabled = options.enabled !== false && !!address && !!authzHttpService.defaults.baseURL;
50+
options.enabled = options.enabled !== false && !!address && !!authzHttpService.axios.defaults.baseURL;
5151

5252
return useQuery({
5353
queryKey: QueryKeys.getAllowancesIssued(address, page, offset),

apps/deploy-web/src/services/app-di-container/app-di-container.ts

Lines changed: 49 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import { StripeService } from "@akashnetwork/http-sdk/src/stripe/stripe.service"
1313
import { LoggerService } from "@akashnetwork/logging";
1414
import { getTraceData } from "@sentry/nextjs";
1515
import { MutationCache, QueryCache, QueryClient } from "@tanstack/react-query";
16-
import type { Axios, AxiosInstance, AxiosResponse, CreateAxiosDefaults, InternalAxiosRequestConfig } from "axios";
16+
import type { Axios, AxiosInstance, AxiosRequestConfig, AxiosResponse, CreateAxiosDefaults, InternalAxiosRequestConfig } from "axios";
1717
import axios from "axios";
1818

1919
import { analyticsService } from "@src/services/analytics/analytics.service";
@@ -27,7 +27,30 @@ import { ProviderProxyService } from "../provider-proxy/provider-proxy.service";
2727

2828
export const createAppRootContainer = (config: ServicesConfig) => {
2929
const apiConfig = { baseURL: config.BASE_API_MAINNET_URL };
30+
3031
const container = createContainer({
32+
getAxiosInstance: () => (config?: AxiosRequestConfig) => {
33+
const { headers, ...defaults } = axios.defaults;
34+
35+
return axios.create({
36+
...defaults,
37+
...config
38+
});
39+
},
40+
axiosWithDefaultInterceptors: () => (config?: AxiosRequestConfig) => {
41+
return container.applyAxiosInterceptors(container.getAxiosInstance(config), {
42+
request: [container.authService.withAnonymousUserHeader]
43+
});
44+
},
45+
46+
defaultAxios: () => container.axiosWithDefaultInterceptors(),
47+
mainnetAxios: () => container.axiosWithDefaultInterceptors(apiConfig),
48+
mainNetAxiosWithNoAnonymousUserHeaderInterceptor: () => container.applyAxiosInterceptors(container.getAxiosInstance(apiConfig)),
49+
managedWalletAxios: () =>
50+
container.axiosWithDefaultInterceptors({
51+
baseURL: container.apiUrlService.getBaseApiUrlFor(config.MANAGED_WALLET_NETWORK_ID)
52+
}),
53+
3154
getTraceData: () => getTraceData,
3255
applyAxiosInterceptors: (): typeof withInterceptors => {
3356
const otelInterceptor = (config: InternalAxiosRequestConfig) => {
@@ -36,51 +59,37 @@ export const createAppRootContainer = (config: ServicesConfig) => {
3659
if (traceData?.baggage) config.headers.set("Baggage", traceData.baggage);
3760
return config;
3861
};
62+
3963
return (axiosInstance, interceptors?) =>
4064
withInterceptors(axiosInstance, {
4165
request: [config.globalRequestMiddleware, otelInterceptor, ...(interceptors?.request || [])],
42-
response: [...(interceptors?.response || [])]
66+
response: [
67+
response => {
68+
if (response.config.url?.startsWith("/v1/anonymous-users") && response.config.method === "post" && response.status === 200) {
69+
container.analyticsService.track("anonymous_user_created", { category: "user", label: "Anonymous User Created" });
70+
}
71+
return response;
72+
},
73+
response => {
74+
if (response.config.url === "v1/start-trial" && response.config.method === "post" && response.status === 200) {
75+
container.analyticsService.track("trial_started", { category: "billing", label: "Trial Started" });
76+
}
77+
return response;
78+
},
79+
...(interceptors?.response || [])
80+
]
4381
});
4482
},
4583
authService: () => new AuthService(),
46-
user: () =>
47-
container.applyAxiosInterceptors(new UserHttpService(apiConfig), {
48-
request: [container.authService.withAnonymousUserHeader],
49-
response: [
50-
response => {
51-
if (response.config.url?.startsWith("/v1/anonymous-users") && response.config.method === "post" && response.status === 200) {
52-
container.analyticsService.track("anonymous_user_created", { category: "user", label: "Anonymous User Created" });
53-
}
54-
return response;
55-
}
56-
]
57-
}),
58-
stripe: () =>
59-
container.applyAxiosInterceptors(new StripeService(apiConfig), {
60-
request: [container.authService.withAnonymousUserHeader]
61-
}),
62-
tx: () =>
63-
container.applyAxiosInterceptors(new TxHttpService(customRegistry, apiConfig), {
64-
request: [container.authService.withAnonymousUserHeader]
65-
}),
66-
template: () => container.applyAxiosInterceptors(new TemplateHttpService(apiConfig)),
67-
usage: () =>
68-
container.applyAxiosInterceptors(new UsageHttpService(apiConfig), {
69-
request: [container.authService.withAnonymousUserHeader]
70-
}),
71-
auth: () =>
72-
container.applyAxiosInterceptors(new AuthHttpService(apiConfig), {
73-
request: [container.authService.withAnonymousUserHeader]
74-
}),
84+
user: () => new UserHttpService(container.mainnetAxios),
85+
stripe: () => new StripeService(container.mainnetAxios),
86+
tx: () => new TxHttpService(container.mainnetAxios, customRegistry),
87+
template: () => new TemplateHttpService(container.mainNetAxiosWithNoAnonymousUserHeaderInterceptor),
88+
usage: () => new UsageHttpService(container.mainnetAxios),
89+
auth: () => new AuthHttpService(container.mainnetAxios),
7590
providerProxy: () => new ProviderProxyService(container.applyAxiosInterceptors(container.createAxios({ baseURL: config.BASE_PROVIDER_PROXY_URL }), {})),
76-
deploymentSetting: () =>
77-
container.applyAxiosInterceptors(new DeploymentSettingHttpService(apiConfig), {
78-
request: [container.authService.withAnonymousUserHeader]
79-
}),
80-
apiKey: () =>
81-
container.applyAxiosInterceptors(new ApiKeyHttpService(), {
82-
request: [container.authService.withAnonymousUserHeader]
83-
}),
91+
deploymentSetting: () => new DeploymentSettingHttpService(container.mainnetAxios),
92+
apiKey: () => new ApiKeyHttpService(container.defaultAxios),
8493
externalApiHttpClient: () =>
8594
container.createAxios({
8695
headers: {
@@ -97,26 +106,7 @@ export const createAppRootContainer = (config: ServicesConfig) => {
97106
certificateManager: () => certificateManager,
98107
analyticsService: () => analyticsService,
99108
apiUrlService: config.apiUrlService,
100-
managedWalletService: () =>
101-
container.applyAxiosInterceptors(
102-
new ManagedWalletHttpService(
103-
{
104-
baseURL: container.apiUrlService.getBaseApiUrlFor(config.MANAGED_WALLET_NETWORK_ID)
105-
},
106-
container.analyticsService
107-
),
108-
{
109-
request: [container.authService.withAnonymousUserHeader],
110-
response: [
111-
response => {
112-
if (response.config.url === "v1/start-trial" && response.config.method === "post" && response.status === 200) {
113-
container.analyticsService.track("trial_started", { category: "billing", label: "Trial Started" });
114-
}
115-
return response;
116-
}
117-
]
118-
}
119-
),
109+
managedWalletService: () => new ManagedWalletHttpService(container.managedWalletAxios, container.analyticsService),
120110
queryClient: () =>
121111
new QueryClient({
122112
queryCache: new QueryCache({

apps/deploy-web/src/services/http/http-browser.service.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ const rootContainer = createAppRootContainer({
1919
});
2020

2121
export const services = createChildContainer(rootContainer, {
22-
userProviderService: () => new UserProviderService(),
22+
userProviderService: () => new UserProviderService(services.defaultAxios),
2323
notificationsApi: () =>
2424
createAPIClient({
2525
requestFn,

0 commit comments

Comments
 (0)