Useful JavaScript helper for setting up and using Axios API as a HTTP client for your frontend app.

In this article I will share a github gist explaning how to setup Axios API for the first time, mainly, how to create an instance with some configuration, adding global interceptors for requests and responses.

You can read the previous article to understand what is http_helper.js used here.

1 – Basic configuration

You can add some basic configuration to Axios instance exported and used in your app. For example a “base url” of your backend api, this let you do not specify the whole url every time in your requests (magic string, risk of mistake, etc.).


Note that I’m using “environment variable” to store the base url configuration. You can read more about environment variables and setup dotenv.

2 – Global interceptors

You may would to setup a global interceptors to your Http requests and responses. For example, intercepting requests and adding special headers like “Authorization” or, responses to check for important errors like “WWW-Authenticate” and format those responses depeding on thier status.

3 – Code

You can find an example on how to use Axios after setting it up, at the end of this gist

import axios from "axios";
require("dotenv").config();
const authTokenKey = "blabla"; /* Example of a bearer token stored in localStorage */
/*Axios configuration*/
const axiosInstance = axios.create({
baseURL: process.env.REACT_APP_API_URL,
});
export const configWithAuthorization = { _withAuthorization: true }; /* This will be used to specify that the request need to include the auth token */
const withAuthorization = (config = {}) => {
return (
config.hasOwnProperty("_withAuthorization") && config._withAuthorization
);
};
const interceptRequest = (request) => {
if (withAuthorization(request)) {
const token = localStorage.getItem(authTokenKey);
if (!!token) {
request.headers["Authorization"] = `Bearer ${token}`;
}
}
return request;
};
const interceptResponseOnFullfilled = (response) => {
return new Result(response.data, null, response.headers);
};
const interceptResponseOnRejected = (error) => {
if (
error.response &&
error.response.headers["WWW-Authenticate".toLowerCase()]
) {
/* e.g. WWW-Authenticate : Bearer error="invalid_token", error_description="The token is expired" */
localStorage.removeItem(authTokenKey);
window.location.reload();
return;
}
let appError = {};
let headers = null;
if (error.response) {
headers = error.response.headers;
const { status, data } = error.response;
switch (status) {
case Status.BadRequest:
appError = new BadRequestError(data);
break;
case Status.Unauthorized:
appError = new UnauthorizedError(data);
break;
case Status.NotFound:
appError = new NotFoundError(data);
break;
default:
appError = new AppError(data);
break;
}
} else if (error.request) {
appError = new AppError(error.request);
} else {
appError = new AppError(error.message);
}
return new Result(
null,
appError,
headers
); /* Nota : use 'Promise.reject' if you need to get the response in Promise.catch (or try-catch with await syntax) */
};
axiosInstance.interceptors.request.use(interceptRequest);
axiosInstance.interceptors.response.use(
interceptResponseOnFullfilled,
interceptResponseOnRejected
);
const requestConfigFactory = (
params = null,
headers = null,
withAuthorization = false
) => {
const config = {};
if (params) {
config.params = params;
}
if (headers) {
config.headers = params;
}
if (withAuthorization) {
config._withAuthorization = true; /* This is not defined in AxiosRequestConfig interface */
}
return config;
};
/*HttpHelper*/
class HttpHelper {
static async getAsync(
url,
params = null,
requestHeaders = null,
withAuthorization = false
) {
const config = requestConfigFactory(
params,
requestHeaders,
withAuthorization
);
const { payload, error, headers } = await axiosInstance.get(url, config);
return new Result(
payload,
error,
headers
); /* This is a hack, because axions cannot infer the type returned from interceptors. */
}
static async postAsync(
url,
data = null,
requestHeaders = null,
withAuthorization = false
) {
const config = requestConfigFactory(
null,
requestHeaders,
withAuthorization
);
const { payload, error, headers } = await axiosInstance.post(
url,
data,
config
);
return new Result(payload, error, headers);
}
static async putAsync(
url,
data = null,
requestHeaders = null,
withAuthorization = false
) {
const config = requestConfigFactory(
null,
requestHeaders,
withAuthorization
);
const { payload, error, headers } = await axiosInstance.put(
url,
data,
config
);
return new Result(payload, error, headers);
}
static async deleteAsync(
url,
requestHeaders = null,
withAuthorization = false
) {
const config = requestConfigFactory(
null,
requestHeaders,
withAuthorization
);
const { payload, error, headers } = await axiosInstance.delete(url, config);
return new Result(payload, error, headers);
}
}
export default HttpHelper;
/*Constants*/
export const Status = {
Ok: 200,
Unassigned: 299,
BadRequest: 400,
Unauthorized: 401,
NotFound: 404,
};
export const Methods = {
Get: "GET",
Post: "POST",
Put: "PUT",
Delete: "DELETE",
};
export const Headers = {
Accept: "application/json",
"Content-Type": "application/json",
};
export const AuthorizationType = {
Bearer: "bearer ",
Basic: "basic ",
};
export const Credentials = {
SameOrigin: "same-origin" /* default */,
Include: "include",
Omit: "omit",
};
/*Types*/
export class Result {
constructor(payload = null, error = null, headers = null) {
this.succeeded = error === null || error === undefined;
this.payload = payload;
this.error = error;
this.headers = headers;
}
succeeded;
payload;
error; /* AppError : check using 'instanceof' to get the status */
headers;
}
export class AppError {
constructor(body = null) {
this.body = body;
}
}
export class NotFoundError extends AppError {
constructor(body = null) {
super(body);
}
}
export class BadRequestError extends AppError {
constructor(body = null) {
super(body);
}
}
export class UnauthorizedError extends AppError {
constructor(body = null) {
super(body);
}
}
view raw axios_helper.js hosted with ❤ by GitHub