@personio/request
A helper library used in Personio UI to perform HTTP requests. It also takes care to include the X-CSRF-Token
on every request. Written in TypeScript, uses axios in the background.
Installation
Run
yarn add @personio/request
Usage
In the root of your project, import configureRequest
and execute it to provide a configuration to subsequent requests performed using the library:
import { configureRequest } from '@personio/request';
configureRequest({ baseURL: API_BASE_URL,
timeout: REQUEST_TIMEOUT,
// Default is false. When enabled, returns the data content instead of an object with data as prop.
// This is useful to avoid something like data.data when mapping the response.
retrieveDataFromResponse: true,
// Default is false, when enabled, dispatches the SESSION:EXPIRED event.
// This makes the login modal from the monolith be triggered.
dispatchSessionExpiredEvent: true,
// Number in milliseconds, default is 0. Adds a delay to the session expired event.
// Useful for finishing some animations like a closing a modal before it shows the login modal.
sessionExpiredDelay: 300
});
Perform an actual HTTP request anywhere in the code:
import request from '@personio/request';
const response = await request({ method: "GET", url: 'example' });
Behind the scenes, request
passes the arguments as is to axios. See more about possible options on https://github.com/axios/axios.
With useRequest hook
It's possible to perform HTTP requests directly in React components or create custom React hooks using the useRequest
hook provided by the library:
import { useRequest, wasRequestSuccessful } from '@personio/request';
import { useCallback, useEffect } from "react";
type DataType = { id: number, value: string };
type MetaType = { example: string };
const useRequestExample = () => {
const [
{
data = [],
statusCode,
hasRequested,
cancelSource,
meta,
isLoading,
error,
},
makeRequest,
{ resetData, setHasNotRequested }
] = useRequest<DataType[], MetaType>();
const fetch = useCallback((id: number) =>
makeRequest(
{
method: 'GET',
url: `example/${id}`,
}
), [makeRequest]);
useEffect(() => {
if (!statusCode) {
return;
}
if (wasRequestSuccessful(statusCode)) {
// do some action on success
} else {
// do some action on fail
}
}, [statusCode]);
return [
{ data, meta, isLoading, error, statusCode, hasRequested, cancelSource },
{ fetch, resetData, setHasNotRequested }
] as const;
};
export default useRequestExample
The makeRequest
function can also accept a second argument, an object that defines request options:
{
// prop to indicate if we should clear or persist the data between requests.
// default: false
persistData: boolean
}
Testing
Use createMock
and mockResponse
import request, { createMock, mockResponse, getRequestAmount } from '@personio/request';
import { render, screen } from '@testing-library/react';
type Response = {
data: { id: number; text: string }[];
};
const mockAdapter = createMock(request);
const exampleMock = mockResponse({ method: 'GET', url: /example/ });
describe('<Example/>', () => {
beforeEach(() => {
exampleMock.reply<Response>(200, { data: [{id: 1, text: 'example'}] });
});
afterEach(() => {
mockAdapter.reset();
});
it('should render with text "example"', async () => {
render(<Example />);
expect(await screen.findByText('example')).toBeInTheDocument();
});
it('should call the example API only once"', async () => {
render(<Example />);
await screen.findByText('example')
expect(getRequestAmount(mockAdapter.history.get, /example/)).toBe(1);
});
});
The axios-mock-adapter
with a modified API is used to mock HTTP requests. For more info, check https://github.com/ctimmerm/axios-mock-adapter.