Axios v Fetch for API interactions
It is outside the code of this documentation to force a decision upon the developer as to which method for API interactions should be employed. Instead we have provided some comparisons, to assist in the decision making
fetch
fetch is a native API available in modern browsers. “Native” in the context of browser APIs means that the feature is built into the browser’s JavaScript environment without the need for external scripts or plugins. It’s a standard part of the environment. For instance, fetch is now a standard part of the Web Platform API, which modern browsers aim to support. While it’s native to modern browsers, it’s true that older browsers like IE require a polyfill (a script that provides the functionality of a newer feature in older browsers that don’t natively support it).
Pros:
Native: Doesn’t require any additional packages or libraries to use.
Promise-based: Easily use with async/await.
Readable syntax: Especially for simple GET requests.
Cons:
Error Handling: Doesn’t reject on HTTP error statuses (e.g., 404 or 500) but only on network errors or request failures.
Features: Some advanced features (like request timeout, request cancellation) are not natively supported or require additional work.
JSON Parsing: Requires an additional step to parse JSON (response.json()).
axios
axios is a popular third-party HTTP client library. Acknowledged as an industry standard.
Pros:
Error Handling: Rejects the promise on HTTP error statuses, which can simplify error handling.
Interceptors: Provides the ability to intercept requests and responses before they are handled or sent.
Timeouts: Built-in support for request timeouts.
Cancellable Requests: Supports request cancellation using the CancelToken feature.
Automatic JSON Parsing: Automatically parses JSON data from responses.
Wider Browser Support: Has built-in XHR handling which provides compatibility with older browsers.
Transforms: Allows data to be transformed before it’s sent or after it’s received.
Cons:
External Dependency: Adds an additional dependency to your project.
Size: While not massive, it’s still larger than the native fetch.
API Interactions with FETCH
The useAPIClient custom hook has been provided, which provides a clean and consistent way to interact with API’s For guidance on the usage of this hook, please refer to the documentation provided for that component
API Interactions with AXIOS
Using axios required the inclusion of the axios library. It was decided not to enforce this inclusion upon all uses of this library, so instead the usage has been provided by a number of code snippets that should added to the the parent application. This will result in the creation of a custom hook that can be used for axios interactions.
Creating the axios client
1. Install the axios dependency
Execute the following command, which will add the dependency to the application
yarn add axios
2. Add location for the axiosAuthCLient
It is recommended to add this into the services folder of your application, as this folder is intended for use with external interactions
services
axios
axiosAuthClient
3. Create the standard axiosAuthClient file
This file will be used by all axios calls, so it is recommended to have an appropriate name to indicated that it includes authentication
axiosAuthClient.tsx
4. Add the basic code for an axios client
The following code snippet is standard for both standard, and authenticated axios usage
import axios from 'axios';
export const useAxiosClient = (baseURL: string) => {
const { instance } = useMsal();
const axiosClient = axios.create({
baseURL,
headers: {
Accept: 'application/json',
'Content-Type': 'application/json'
}
});
export default useAxiosClient;
Tip
If there is a requirement for use of axios without authentication, it is recommended to create a second axios Client.
5. Rename the name of the axiosClient
As the code will be providing authentication, it is recommended that it is adjusted to reflect that
useAxiosClient ----- ( becomes ) -----> useAxiosAuthClient
axiosClient ----- ( becomes ) -----> axiosAuthClient
6. Add an axios interceptor
The following code snippet intercepts axios calls using this client and adds the required authentication functionality This interceptor can then be adjusted for the specific needs of the application - It includes code to allow the use of http during local development, but inhibits its use once deployed. - Fetching of a new token if the current one has expired is done automatically
export enum LogLevel {
Error,
Warning,
Info,
Verbose,
Trace
}
export const loginRequest = {
scopes: ['User.Read']
};
axiosAuthClient.interceptors.request.use(
async request => {
const isLocalhost =
window.location.hostname === 'localhost' || window.location.hostname === '127.0.0.1';
const isHttp = request?.baseURL?.startsWith('http://');
// Correct logic: Allow HTTP ONLY on localhost. Otherwise, force HTTPS.
if (isHttp && !isLocalhost) {
return Promise.reject('HTTP is not allowed except on localhost.');
} else if (
isHttp &&
!isLocalhost &&
request.baseURL &&
!request.baseURL.startsWith('https://')
) {
request.baseURL = request.baseURL.replace('http://', 'https://');
}
const account = instance.getAllAccounts()[0];
if (account) {
try {
const tokenResponse = await instance.acquireTokenSilent({
...loginRequest,
account: account
});
request.headers['Authorization'] = `Bearer ${tokenResponse.accessToken}`;
} catch (error) {
console.error('Error acquiring token silently:', error);
if (error instanceof InteractionRequiredAuthError) {
instance.loginRedirect({
...loginRequest,
redirectUri: window.location.origin
});
}
return Promise.reject(error);
}
}
return request;
},
error => Promise.reject(error)
);
Once the steps above have been completed, the axiosAuthClient` can be used for all API calls requiring authentication
Using the axios client within the codebase
With the custom hook for the axios authenticated client in place in the code, next it needs to be implemented. Below are the steps that should be employed. In this example the requirement is to add a POST to an API
Tip
It is advised that all the steps are reviewed before coding to ensure that the process is fully understood
1. Add location and file for the axios POST function
It is recommended to add this into the services folder of your application, as this will interact with external APIs
services
axios
postToAPI
postToAPI.tsx
2. Function is written to make use of the custom hook
Add the following into the postToAPI.tsx file.
import { AxiosResponse } from 'axios';
import { useAxiosAuthClient } from '@services/axios/axiosAuthClient/axiosAuthClient';
const PostToAPI = async (
axiosClient: ReturnType<typeof useAxiosAuthClient>, // Add the authAxiosClient parameter
options: object
): Promise<AxiosResponse> => {
try {
const response = await axiosClient.post(`/somePath`, options);
return response;
} catch (error) {
console.error('Error posting:', error);
if (error.response) { // Server error
throw error.response; // Re-throw the AxiosResponse error for the caller to handle
} else if (error.request) { // Request error (no response)
throw new Error('No response received from the server'); // Re-throw a custom error
} else { // Client-side error
throw error; // Re-throw the original error
}
}
};
export default PostToAPI;
3. Use the function
Add the function into the codebase into the location that it is required
import PostToAPI from '@services/axios/postToAPI/postToAPI';
...
const authAxiosClient = useAxiosAuthClient(... BASE URL OF THE APPLICATION ...);
...
const result = await PostToAPI(authAxiosClient, options);
if (![200, 201].includes(result.status)) {
// Do some error handling using `result.data.message`
} else {
// Do something with the information contained in `result.data`
... do some action
}