Skip to content

Commit

Permalink
feature: configure axios instance
Browse files Browse the repository at this point in the history
When this library is used by other libraries to perform requests, things
like custom interceptors configured in the application don't trigger on
those requests. Therefor we need a way to set and use a custom axios
instance.

Added config to set custom axios instance used by all requests, which
defaults to the global axios.

Closes #60
  • Loading branch information
Gido Manders committed May 25, 2022
1 parent 3a1eff8 commit a5ccf05
Show file tree
Hide file tree
Showing 6 changed files with 94 additions and 9 deletions.
10 changes: 7 additions & 3 deletions docs/guide/2. migration.md
Original file line number Diff line number Diff line change
Expand Up @@ -85,9 +85,13 @@ can be replaced with:

```ts
import { getXSRFToken, authInterceptor } from '@42.nl/authentication';
import { configureApi } from '@42.nl/spring-connect';
import axios from 'axios';

axios.defaults.headers.common['X-XSRF-TOKEN'] = getXSRFToken();
axios.defaults.withCredentials = true;
axios.interceptors.response.use(undefined, authInterceptor);
const api = axios.create();
api.defaults.headers.common['X-XSRF-TOKEN'] = getXSRFToken();
api.defaults.withCredentials = true;
api.interceptors.response.use(undefined, authInterceptor);

configureApi(api);
```
44 changes: 44 additions & 0 deletions src/config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import axios, { AxiosInstance } from 'axios';

type Config = {
// The fetch variant which is used to make requests.
api?: AxiosInstance;
};

export default Config;

const config: Config = {
api: undefined // by default use axios as is
};

/**
* Configures the MadConnect library axios instance.
*
* @param {AxiosInstance} api An axios instance with extra configurations like interceptors
*/
export function configureApi(api: AxiosInstance): void {
config.api = api;
}

/**
* Returns the config for the mad-connect library.
*
* @returns The Config
*/
export function getConfig(): Config {
return config;
}

/**
* Convenience function to return 'api' from the config.
*
* Returns either a custom axios instance configured by
* the user via 'configureApi' or the default axios
* implementation provided by the Axios library.
*
* @export
* @returns {AxiosInstance} Either the default axios or the configured axios instance.
*/
export function getApi(): AxiosInstance {
return config.api ? config.api : axios;
}
1 change: 1 addition & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
export { get, post, put, patch, remove } from './request';
export { default as Config, configureApi, getApi } from './config';
export { makeResource, MakeResourceConfig, Mapper } from './resource';
export { Page, emptyPage } from './spring-models';
export { makeInstance, buildUrl } from './utils';
Expand Down
17 changes: 11 additions & 6 deletions src/request.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { buildUrl } from './utils';
import { Payload, QueryParams } from './types';
import axios, { AxiosResponse } from 'axios';
import { AxiosResponse } from 'axios';
import { getApi } from './config';

/**
* Does a GET request to the given url, with the query params if
Expand All @@ -24,7 +25,9 @@ export async function get<T>(
): Promise<T> {
const finalUrl = buildUrl(url, queryParams);

return axios.get<T>(finalUrl).then((res) => res.data);
return getApi()
.get<T>(finalUrl)
.then((res) => res.data);
}

/**
Expand All @@ -45,7 +48,7 @@ export async function get<T>(
* @returns {Promise} Returns a Promise, the content of the promise depends on the configured middleware.
*/
export function post<T, D = Payload<T>>(url: string, payload: D): Promise<T> {
return axios
return getApi()
.post<T, AxiosResponse<T>, D>(url, payload)
.then((res) => res.data);
}
Expand All @@ -68,7 +71,7 @@ export function post<T, D = Payload<T>>(url: string, payload: D): Promise<T> {
* @returns {Promise} Returns a Promise, the content of the promise depends on the configured middleware.
*/
export function put<T, D = Payload<T>>(url: string, payload: D): Promise<T> {
return axios
return getApi()
.put<T, AxiosResponse<T>, D>(url, payload)
.then((res) => res.data);
}
Expand All @@ -91,7 +94,7 @@ export function put<T, D = Payload<T>>(url: string, payload: D): Promise<T> {
* @returns {Promise} Returns a Promise, the content of the promise depends on the configured middleware.
*/
export function patch<T, D = Payload<T>>(url: string, payload: D): Promise<T> {
return axios
return getApi()
.patch<T, AxiosResponse<T>, D>(url, payload)
.then((res) => res.data);
}
Expand All @@ -116,5 +119,7 @@ export function patch<T, D = Payload<T>>(url: string, payload: D): Promise<T> {
* @returns {Promise} Returns a Promise, the content of the promise depends on the configured middleware.
*/
export function remove<T>(url: string): Promise<T> {
return axios.delete<T>(url).then((res) => res.data);
return getApi()
.delete<T>(url)
.then((res) => res.data);
}
29 changes: 29 additions & 0 deletions tests/config.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { configureApi, getConfig, getApi } from '../src/config';
import axios, { AxiosInstance } from 'axios';

let windowSpy: jest.SpyInstance;

beforeEach(() => {
windowSpy = jest.spyOn(window, 'window', 'get');
});

afterEach(() => {
windowSpy.mockRestore();
});

test('configuration lifecycle', async () => {
expect.assertions(4);

// By default it should use regular axios.
expect(getConfig().api).toBe(undefined);
expect(getApi()).toBe(axios);

// @ts-expect-error Test mock
const fakeApi: AxiosInstance = { test: true };

configureApi(fakeApi);

// Now we expect the config to be set.
expect(getConfig().api).toBe(fakeApi);
expect(getApi()).toBe(fakeApi);
});
2 changes: 2 additions & 0 deletions tests/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,10 @@ describe('index', () => {
expect(index).toMatchInlineSnapshot(`
Object {
"buildUrl": [Function],
"configureApi": [Function],
"emptyPage": [Function],
"get": [Function],
"getApi": [Function],
"makeInstance": [Function],
"makeResource": [Function],
"patch": [Function],
Expand Down

0 comments on commit a5ccf05

Please sign in to comment.