One common thing in most web apps is API calling. So often the first thing I usually end up making in any web app is a request wrapper.
Why is it needed and how it helps -
- Prevent writing repetitive code.
- Enforcing code structure by defining the API cases only once.
- Adding multiple enhancements in future like performance monitoring by firebase.
- Getting environment based URL as well as Authentication tokens.
- Handle basic error codes and show errors to user from 1 place.
Prerequisites
To create the wrapper we'd be using axios and qs for querystring parsing and stringifying.
Run this command to install them -npm install axios && npm i qs
Setting up baseURL for API in .env file like this
REACT_APP_API_HOST=https://api.example.io/v1
Usage in redux files
It's generally good practice to define URL's as constants module specific in one file as well.
import { DoRequest, REQUEST_TYPE } from "../../helpers/doRequest";
let response = await DoRequest({
method: REQUEST_TYPE.POST,
url: '/login',
data: {username, password}
});
API Wrapper Code
import axios from "axios";
import qs from "qs";
import { useDispatch } from "react-redux";
import { logout } from "../../store/authReducer";
export const REQUEST_TYPE = {
POST: "post",
GET: "get",
PUT: "put",
DELETE: "delete",
};
export const DoRequest = async (requestData) => {
const dispatch = useDispatch();
const token = localStorage.getItem("token"); //Authorization token to use for API's
const defaultHeader = {
Authorization: token ? `Token ${token}` : null,
Accept: "*/*", //NOTE: Default Accept value sometimes gives error 406 on some clients
};
const {
headers = {},
method = "get", //Default initialization method type
url = "", //Default URL to hit
baseURL = process.env.REACT_APP_API_HOST, //Base url ex - in .env file
params = {}, //Default extra params
data = {}, //Default data to send
} = requestData;
//create request config according to data
const requestConfig = {
headers: Object.assign(defaultHeader, headers),
method,
url,
baseURL,
params,
paramsSerializer: (params) => {
return qs.stringify(params, { arrayFormat: "comma" });
},
data, //POST request data to send
};
try {
const response = await axios(requestConfig);
const limit = response.headers["x-collection-range"]; //For pagination
if (limit) {
const total = limit?.split("/")[1]; //For pagination purposes
return { data: response.data, total };
}
return { data: response.data }; //Success API response based on API endpoints
} catch (error) {
const { response: { status, data } = {} } = error || {}; //Based on ur API endpoints
if (status === 401) { //Handle API codes as necessary
dispatch(logout()); // Use hooks to handle Logout or redirection or anything
} else if (status === 404) {
window.location.replace("/not-found"); //Redirect to any page via hooks or window object.
} else {
alert(`${data.message}`); //Show notifications or alerts from 1 place instead of repetitive code
}
return data;
}
};
Extra axios integrations
Also adding additional performance metric tools like Firebase Performance Monitoring with Axios can also be easily setup with this.
Top comments (0)