Hi guys!
In this article I am sharing a small process of an auth system using axios interceptors. The concept below, is that, when you submit your email or password you want to check if that user exists on the server and if the user is authenticated then the user would be able to navigate to other pages.
More information about interceptors you can check here.
You could simply do a post request inside your SignIn component however if one day lets say axios doesn't exist anymore and you want to be able to change what you used in just one place but not the logic behind it then interceptors is the way to go. Also this is a concept recently came across called [MVP] - minimum viable product - LINK, still trying to get my head around it but is good to know.
By the way the article is giving you an idea how that works of course you would need to add your own bits and pieces, api etc...
So let's take a step back.
What I am sharing below is:
Setup the connection with a server.
Create a service layer
Set up with a server
- Create your client, which is the connection with your API.
Below the REACT_APP_API_URL
could be your own API saved on your .env file or .env.local
interface ConfigType {
ApiUrl: string
}
const config: ConfigType = {
ApiUrl: process.env.REACT_APP_API_URL || '',
}
export default config
Here we have our http-client file.
import axios from 'axios'
import config from './config'
import setupInterceptorsTo from './http-client-interceptor'
const instance = axios.create({
baseURL: config.ApiUrl,
headers: {
'Content-type': 'application/json',
},
})
export default setupInterceptorsTo(instance)
Create the service layer
Below we have the interceptors which will handle our error messages because there is always different type of errors.
import { AxiosError, AxiosInstance, AxiosRequestConfig } from 'axios'
import { toast } from 'react-toastify'
import { isObject, isEmpty } from 'lodash'
const API_DEFAULT_MESSAGE_REQUEST = 'The request is invalid'
function handleError(serverError: any) {
if (isObject(serverError)) {
Object.entries(serverError).forEach(([, value]) => {
const errorMessage = isEmpty(value) ? API_DEFAULT_MESSAGE_REQUEST : value
toast.error(`${errorMessage}`)
})
}
}
const onRequest = (config: AxiosRequestConfig): AxiosRequestConfig => {
return config
}
const onResponseError = (error: AxiosError): Promise<AxiosError> => {
handleError(error?.response?.data)
return Promise.reject(error)
}
export default function setupInterceptorsTo(axiosInstance: AxiosInstance): AxiosInstance {
axiosInstance.interceptors.request.use(onRequest, undefined)
axiosInstance.interceptors.response.use(undefined, onResponseError)
return axiosInstance
}
Here is where we actually send a request to the server in this case a post request.
import { BehaviorSubject } from 'rxjs'
import { isNull } from 'lodash'
import httpClient from '../../shared/http-client'
interface LoginRequestModel {
email: string
password: string
}
const currentUserSubject = isNull(localStorage.getItem('current_user'))
? new BehaviorSubject(null)
: new BehaviorSubject(JSON.parse(localStorage.getItem('current_user')!))
export const currentUserValue = currentUserSubject.value
export async function login(requestData: LoginRequestModel): Promise<string> {
const response = await httpClient.post('/auth/login', requestData)
const { access_token: accesstoken } = response.data
return accesstoken
}
Finally you can call your login function on your SignIn component and the only thing you need to do is to use it in an async way where await login(data)
. Thats the only input it gets since above you have the schema for this function and it does all the work for us isolated.
Top comments (2)
Hi it miss the httpclient file, and how to add bearer token on interceptor.
Hi I just added which picture is the http-client file.
As for the bearer token I will update the article once I finish it as well. The current code is not finished fully yet as I mentioned at the beginning of the article thats a part of a logic. But will update once I completed as well on the project. :)