Skip to content

Commit 879718f

Browse files
author
Weffe
committed
feat: expose axios types at the top-level
1 parent 957bc24 commit 879718f

File tree

11 files changed

+192
-194
lines changed

11 files changed

+192
-194
lines changed

src/axios-api-versioning-interceptor.ts

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
11
import { AxiosInstance } from 'axios';
2-
import { VersioningStrategy, IVersioningConfig, } from './types'
3-
import { AxiosRequestConfigWithVersioning } from './types/axios';
2+
import { VersioningStrategy, IVersioningConfig, AxiosRequestConfigWithVersioning } from './types';
43

54
function replaceUrlPathWithVersion(url: string, apiVersion: string) {
65
// the template name of the api version must be "apiVersion"
76
return url.replace('{apiVersion}', apiVersion);
87
}
98

10-
function enhanceConfigByVersioningStrategy(requestConfig: AxiosRequestConfigWithVersioning, versioningConfig: IVersioningConfig): AxiosRequestConfigWithVersioning {
11-
9+
function enhanceConfigByVersioningStrategy(
10+
requestConfig: AxiosRequestConfigWithVersioning,
11+
versioningConfig: IVersioningConfig
12+
): AxiosRequestConfigWithVersioning {
1213
// we prioritize the apiVersion passed via the RequestConfig first
1314
// then use the initial versioningConfig last
1415
const apiVersion = requestConfig['apiVersion'] || versioningConfig['apiVersion'];
@@ -19,13 +20,13 @@ function enhanceConfigByVersioningStrategy(requestConfig: AxiosRequestConfigWith
1920
if (versioningStrategy === VersioningStrategy.QueryString) {
2021
requestConfig.params = {
2122
...requestConfig.params,
22-
[versioningConfig.queryStringKeyName]: apiVersion
23+
[versioningConfig.queryStringKeyName]: apiVersion,
2324
};
2425
}
2526

2627
if (versioningStrategy === VersioningStrategy.MediaType) {
27-
const defaultAcceptHeader: string = requestConfig.headers.common["Accept"];
28-
const reqAcceptHeader: string | undefined = requestConfig.headers["Accept"] || undefined;
28+
const defaultAcceptHeader: string = requestConfig.headers.common['Accept'];
29+
const reqAcceptHeader: string | undefined = requestConfig.headers['Accept'] || undefined;
2930

3031
// we prioritize an accept header passed in the RequestConfig but default to the
3132
// the common default accept header value axios provides
@@ -35,19 +36,18 @@ function enhanceConfigByVersioningStrategy(requestConfig: AxiosRequestConfigWith
3536
const formattedAcceptHeader = versioningConfig.mediaTypeFormatter({
3637
apiVersion,
3738
acceptHeader,
38-
mediaTypeKeyName: versioningConfig.mediaTypeKeyName
39-
})
39+
mediaTypeKeyName: versioningConfig.mediaTypeKeyName,
40+
});
4041

4142
requestConfig.headers = {
4243
...requestConfig.headers,
43-
["Accept"]: formattedAcceptHeader
44-
}
45-
}
46-
else {
44+
['Accept']: formattedAcceptHeader,
45+
};
46+
} else {
4747
requestConfig.headers = {
4848
...requestConfig.headers,
49-
["Accept"]: acceptHeader + `;${versioningConfig.mediaTypeKeyName}=${apiVersion}`
50-
}
49+
['Accept']: acceptHeader + `;${versioningConfig.mediaTypeKeyName}=${apiVersion}`,
50+
};
5151
}
5252
}
5353

src/axios-api-versioning.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import axios, { AxiosInstance, AxiosStatic } from 'axios';
22
import { AxiosInstanceWithVersioning } from './types/axios';
3-
import { IWithVersioningConfig, IVersioningConfig } from './types'
4-
import { injectApiVersioningInterceptor } from './axios-api-versioning-interceptor'
3+
import { IWithVersioningConfig, IVersioningConfig } from './types';
4+
import { injectApiVersioningInterceptor } from './axios-api-versioning-interceptor';
55
import { defaultWithVersioningConfig } from './defaultConfig';
66

77
export function withVersioning(instance: AxiosInstance | AxiosStatic, config: IWithVersioningConfig) {
@@ -15,4 +15,4 @@ export function withVersioning(instance: AxiosInstance | AxiosStatic, config: IW
1515
injectApiVersioningInterceptor(clonedInstance, versioningConfig);
1616

1717
return clonedInstance as AxiosInstanceWithVersioning;
18-
}
18+
}

src/defaultConfig.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { IVersioningConfig, PickPartial } from './types';
22

3-
export const defaultWithVersioningConfig: PickPartial<IVersioningConfig, "apiVersion" | "versioningStrategy"> = {
3+
export const defaultWithVersioningConfig: PickPartial<IVersioningConfig, 'apiVersion' | 'versioningStrategy'> = {
44
mediaTypeKeyName: 'v',
55
queryStringKeyName: 'api-version',
6-
}
6+
};

src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
export { withVersioning } from './axios-api-versioning';
22
export { VersioningStrategy, IWithVersioningConfig, MediaTypeFormatterFn } from './types';
3+
export * from './types/axios';

src/types/axios/axios.types.ts

Lines changed: 22 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,6 @@
11
// Matching type definitions for axios 0.18
22

3-
import {
4-
AxiosRequestConfig,
5-
AxiosPromise,
6-
AxiosInterceptorManager,
7-
AxiosResponse,
8-
} from 'axios';
3+
import { AxiosRequestConfig, AxiosPromise, AxiosInterceptorManager, AxiosResponse } from 'axios';
94

105
/**
116
* In order to only expose the apiVersion and versioningStrategy to axios instances with
@@ -44,15 +39,27 @@ export interface AxiosInstanceWithVersioning {
4439
get<T = any, R = AxiosResponseWithVersioning<T>>(url: string, config?: AxiosRequestConfigWithVersioning): Promise<R>;
4540
delete<T = any, R = AxiosResponseWithVersioning<T>>(url: string, config?: AxiosRequestConfigWithVersioning): Promise<R>;
4641
head<T = any, R = AxiosResponseWithVersioning<T>>(url: string, config?: AxiosRequestConfigWithVersioning): Promise<R>;
47-
post<T = any, R = AxiosResponseWithVersioning<T>>(url: string, data?: any, config?: AxiosRequestConfigWithVersioning): Promise<R>;
48-
put<T = any, R = AxiosResponseWithVersioning<T>>(url: string, data?: any, config?: AxiosRequestConfigWithVersioning): Promise<R>;
49-
patch<T = any, R = AxiosResponseWithVersioning<T>>(url: string, data?: any, config?: AxiosRequestConfigWithVersioning): Promise<R>;
42+
post<T = any, R = AxiosResponseWithVersioning<T>>(
43+
url: string,
44+
data?: any,
45+
config?: AxiosRequestConfigWithVersioning
46+
): Promise<R>;
47+
put<T = any, R = AxiosResponseWithVersioning<T>>(
48+
url: string,
49+
data?: any,
50+
config?: AxiosRequestConfigWithVersioning
51+
): Promise<R>;
52+
patch<T = any, R = AxiosResponseWithVersioning<T>>(
53+
url: string,
54+
data?: any,
55+
config?: AxiosRequestConfigWithVersioning
56+
): Promise<R>;
5057
}
5158

5259
export default interface AxiosTypes {
53-
AxiosRequestConfigWithVersioning: AxiosRequestConfigWithVersioning,
54-
AxiosAdapterWithVersioning: AxiosAdapterWithVersioning,
55-
AxiosResponseWithVersioning: AxiosResponseWithVersioning,
56-
AxiosErrorWithVersioning: AxiosErrorWithVersioning,
57-
AxiosInstanceWithVersioning: AxiosInstanceWithVersioning,
58-
}
60+
AxiosRequestConfigWithVersioning: AxiosRequestConfigWithVersioning;
61+
AxiosAdapterWithVersioning: AxiosAdapterWithVersioning;
62+
AxiosResponseWithVersioning: AxiosResponseWithVersioning;
63+
AxiosErrorWithVersioning: AxiosErrorWithVersioning;
64+
AxiosInstanceWithVersioning: AxiosInstanceWithVersioning;
65+
}

src/types/axios/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,4 @@ export {
44
AxiosResponseWithVersioning,
55
AxiosErrorWithVersioning,
66
AxiosInstanceWithVersioning,
7-
} from './axios.types'
7+
} from './axios.types';

src/types/index.ts

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,3 @@
1-
export {
2-
VersioningStrategy,
3-
MediaTypeFormatterFn,
4-
IVersioningConfig,
5-
IWithVersioningConfig,
6-
PickPartial,
7-
} from './types'
1+
export { VersioningStrategy, MediaTypeFormatterFn, IVersioningConfig, IWithVersioningConfig, PickPartial } from './types';
2+
3+
export * from './axios';

src/types/types.ts

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,10 @@
11
export enum VersioningStrategy {
22
QueryString = 'QUERY_STRING',
33
UrlPath = 'URL_PATH',
4-
MediaType = 'MEDIA_TYPE'
4+
MediaType = 'MEDIA_TYPE',
55
}
66

7-
export type MediaTypeFormatterFn = (data: {
8-
apiVersion: string,
9-
mediaTypeKeyName: string,
10-
acceptHeader: string
11-
}) => string;
7+
export type MediaTypeFormatterFn = (data: { apiVersion: string; mediaTypeKeyName: string; acceptHeader: string }) => string;
128

139
export interface IVersioningConfig {
1410
apiVersion: string;
@@ -18,10 +14,8 @@ export interface IVersioningConfig {
1814
mediaTypeFormatter?: MediaTypeFormatterFn;
1915
}
2016

21-
export interface IWithVersioningConfig
22-
extends PickPartial<IVersioningConfig, "mediaTypeKeyName" | "queryStringKeyName"> {
23-
}
17+
export interface IWithVersioningConfig extends PickPartial<IVersioningConfig, 'mediaTypeKeyName' | 'queryStringKeyName'> {}
2418

2519
// type helper
2620
// @see https://stackoverflow.com/a/53742583
27-
export type PickPartial<T, K extends keyof T> = Pick<T, Exclude<keyof T, K>> & Partial<Pick<T, K>>
21+
export type PickPartial<T, K extends keyof T> = Pick<T, Exclude<keyof T, K>> & Partial<Pick<T, K>>;

tests/axios-api-versioning.mock.ts

Lines changed: 55 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -1,79 +1,79 @@
1-
import axios from "axios";
2-
import MockAdapter from "axios-mock-adapter";
3-
import * as status from "http-status-codes";
4-
import { withVersioning } from "../axios-api-versioning";
5-
import { IWithVersioningConfig, VersioningStrategy } from "../types";
6-
import { AxiosInstanceWithVersioning } from "../types/axios";
7-
8-
const test_url = "http://localhost:3000";
9-
const MOCK_RES = "hello_world";
1+
import axios, { AxiosInstance } from 'axios';
2+
import MockAdapter from 'axios-mock-adapter';
3+
import * as status from 'http-status-codes';
4+
import { withVersioning } from '../src/axios-api-versioning';
5+
import { IWithVersioningConfig, VersioningStrategy } from '../src/types';
6+
import { AxiosInstanceWithVersioning } from '../src/types/axios';
7+
8+
const test_url = 'http://localhost:3000';
9+
const MOCK_RES = 'hello_world';
1010
let mock: MockAdapter;
1111
let instance: AxiosInstanceWithVersioning;
1212

1313
describe('Testing correct response config of "QueryString" strategy', () => {
14-
let versioningConfig: IWithVersioningConfig = {
15-
apiVersion: "1.0",
16-
versioningStrategy: VersioningStrategy.QueryString
17-
};
14+
let versioningConfig: IWithVersioningConfig = {
15+
apiVersion: '1.0',
16+
versioningStrategy: VersioningStrategy.QueryString,
17+
};
1818

19-
beforeAll(() => {
20-
instance = withVersioning(axios, versioningConfig);
21-
mock = new MockAdapter(instance);
22-
});
19+
beforeAll(() => {
20+
instance = withVersioning(axios, versioningConfig);
21+
mock = new MockAdapter(instance as AxiosInstance);
22+
});
2323

24-
test('it should have the "apiVersion" as a query param in the response config', async () => {
25-
mock.onGet(test_url).reply(status.OK, MOCK_RES);
24+
test('it should have the "apiVersion" as a query param in the response config', async () => {
25+
mock.onGet(test_url).reply(status.OK, MOCK_RES);
2626

27-
const res = await instance.get(test_url);
28-
const { params } = res.config;
27+
const res = await instance.get(test_url);
28+
const { params } = res.config;
2929

30-
expect(params).toHaveProperty("api-version");
31-
expect(params["api-version"]).toBe(versioningConfig.apiVersion);
32-
});
30+
expect(params).toHaveProperty('api-version');
31+
expect(params['api-version']).toBe(versioningConfig.apiVersion);
32+
});
3333
});
3434

3535
describe('Testing correct response config of "MediaType" strategy', () => {
36-
let versioningConfig: IWithVersioningConfig = {
37-
apiVersion: "1.0",
38-
versioningStrategy: VersioningStrategy.MediaType
39-
};
36+
let versioningConfig: IWithVersioningConfig = {
37+
apiVersion: '1.0',
38+
versioningStrategy: VersioningStrategy.MediaType,
39+
};
4040

41-
beforeAll(() => {
42-
instance = withVersioning(axios, versioningConfig);
43-
mock = new MockAdapter(instance);
44-
});
41+
beforeAll(() => {
42+
instance = withVersioning(axios, versioningConfig);
43+
mock = new MockAdapter(instance as AxiosInstance);
44+
});
4545

46-
test('it should have the "apiVersion" as an accept-param in the Accept header', async () => {
47-
mock.onGet(test_url).reply(status.OK, MOCK_RES);
46+
test('it should have the "apiVersion" as an accept-param in the Accept header', async () => {
47+
mock.onGet(test_url).reply(status.OK, MOCK_RES);
4848

49-
const res = await instance.get(test_url);
50-
const { headers } = res.config;
49+
const res = await instance.get(test_url);
50+
const { headers } = res.config;
5151

52-
expect(headers).toHaveProperty("Accept");
53-
expect(headers["Accept"]).toMatch(`v=${versioningConfig.apiVersion}`);
54-
});
52+
expect(headers).toHaveProperty('Accept');
53+
expect(headers['Accept']).toMatch(`v=${versioningConfig.apiVersion}`);
54+
});
5555
});
5656

5757
describe('Testing correct response config of "UrlPath" strategy', () => {
58-
let versioningConfig: IWithVersioningConfig = {
59-
apiVersion: "1",
60-
versioningStrategy: VersioningStrategy.UrlPath
61-
};
58+
let versioningConfig: IWithVersioningConfig = {
59+
apiVersion: '1',
60+
versioningStrategy: VersioningStrategy.UrlPath,
61+
};
6262

63-
const blank_test_url = test_url + "/v{apiVersion}";
64-
const versioned_test_url = test_url + `/v${versioningConfig.apiVersion}`;
63+
const blank_test_url = test_url + '/v{apiVersion}';
64+
const versioned_test_url = test_url + `/v${versioningConfig.apiVersion}`;
6565

66-
beforeAll(() => {
67-
instance = withVersioning(axios, versioningConfig);
68-
mock = new MockAdapter(instance);
69-
});
66+
beforeAll(() => {
67+
instance = withVersioning(axios, versioningConfig);
68+
mock = new MockAdapter(instance as AxiosInstance);
69+
});
7070

71-
test('it should have the "apiVersion" as a url param in the url', async () => {
72-
mock.onGet(versioned_test_url).reply(status.OK, MOCK_RES);
71+
test('it should have the "apiVersion" as a url param in the url', async () => {
72+
mock.onGet(versioned_test_url).reply(status.OK, MOCK_RES);
7373

74-
const res = await instance.get(blank_test_url);
75-
const { url } = res.config;
74+
const res = await instance.get(blank_test_url);
75+
const { url } = res.config;
7676

77-
expect(url).toBe(versioned_test_url);
78-
});
77+
expect(url).toBe(versioned_test_url);
78+
});
7979
});

0 commit comments

Comments
 (0)