Data fetching is one of the most important parts of front-end programming. There are quite a few libraries and packages like fetch API, TanStack, etc. Axios is my choice but is it easy and efficient enough?
We used to use Axios traditionally like the code below
axios({ url:"/some-api-url", method: "GET", }).then((res) => { // more response code here }).catch((err) => { // more error code here })
Or maybe like this
axios .get("/some-api-url") .then((res) => { // more response code here }).catch((err) => { // more error code here })
These codes are the same and simple, right? But what if I like to add some loaders?
Okay That's simple as well, I will code this one
const loader = ref(false) loader.value = true axios .get("/some-api-url") .then((res) => { // more response code here }).catch((err) => { // more error code here }) .finally(() => { loader.value = false })
See! It's simple!
But what if I want to have 10 different requests on a single page or component? well, I have to make 10 different loader refs and manually set them true and false! And what if I want to set an alert for the request if its response is an error? Yes, it's complicated and dirty now!
So I decided to code a custom hook for Axios to make my life easier
First, I created useAxios.js file and created a function in it like so:
const useAxios = ({ url, data: userData, headers }) => { const loading = ref(false) // for making loaders easily const error = ref(null) // getting error if there is any const data = ref(null) // the response of the request const status = ref(null) // status code const response = ref(null) // response obj (data, headers, etc.) const errorMessage = ref(null) // error message to show }
Then I created the request function so I can invoke it whenever I want with the given arguments
const useAxios = ({ url, data: userData, headers }) => { const loading = ref(false) // for making loaders easily const error = ref(null) // getting error if there is any const data = ref(null) // the response of the request const status = ref(null) // status code const response = ref(null) // response obj (data, headers, etc.) const errorMessage = ref(null) // error message to show const request = async (method) => { // Implementing loading functionality loading.value = true // Don't forget to put in try/catch statement! try { const res = await axios({ url, method, userData, headers }) // Response data data.value = res.data // Response Obj response.value = res // Response status code status.value = res.status } catch (e) { // Response Obj response.value = e.response // Error obj error.value = e // Error status code status.value = e.response.status // Error message errorMessage.value = e.messaage } loading.value = false } }
create axiosInstance file, so we can set default base url and add manual configuration into axios
axiosInstance.js
import axios from 'axios' import axiosConfig from '../axios.config.js' const axiosInstance = axios.create() axiosInstance.defaults.baseURL = "http://localhost:8000" export default axiosInstance
Logic is done, we just need some more functions to make it much easier, when we want to make a request, So we add request functions with different methods and return them
And that's it, the final code should be look like this:
useAxios.js
import axiosInstance from './axiosInstance.js' const alert = useAlert() const objectToQueryString = (obj, withQuestionMark = true) => { let r = [] Object.keys(obj).forEach((key) => { if (obj[key] !== null && obj[key] !== undefined) { r.push(key + `=` + obj[key]) } }) return r.length > 0 ? `${withQuestionMark ? '?' : ''}${r.join('&')}` : null } const useAxios = ({ url, data: userData, headers, name = null, notif = true, notification, }) => { const loading = ref(false) const error = ref(null) const data = ref(null) const status = ref(null) const response = ref(null) const errorMessage = ref(null) const useNotificationForAllRef = ref(notif) const request = async (method, payload = {}, noLoading = false) => { if (!noLoading) { loading.value = true } const axiosObj = { method, headers, } if (method === 'GET') { if (objectToQueryString(payload)) { axiosObj.url = url + objectToQueryString(payload) } else { axiosObj.url = url } } else { axiosObj.url = url axiosObj.data = payload } try { const res = await axiosInstance(axiosObj) data.value = res.data response.value = res status.value = res.status loading.value = false // Add your alert here if you have any if (notif) { // TODO translate first then // alert({ // title: data.value.status, // type: 'success', // text: data.value.message, // }) } return res.data } catch (e) { response.value = e.response error.value = e status.value = e.response.status errorMessage.value = e.response.data.message loading.value = false // Add your alert here if you have any if (notif) { // TODO translate first then // alert({ // title: e.response.data.status, // type: 'error', // text: e.response.data.message, // }) } throw e } } const getReq = async (data, noLoading = false) => await request('GET', data, noLoading) const postReq = async (data, noLoading = false) => await request('POST', data, noLoading) const putReq = async (data, noLoading = false) => await request('PUT', data, noLoading) const patchReq = async (data, noLoading = false) => await request('PATCH', data, noLoading) const deleteReq = async (data, noLoading = false) => await request('DELETE', data, noLoading) const returnObj = { error, data, response, status, errorMessage, loading, getReq, postReq, putReq, patchReq, deleteReq, } if (name) { // name sanitization returnObj['get' + name] = getReq returnObj['post' + name] = postReq returnObj['put' + name] = putReq returnObj['patch' + name] = patchReq returnObj['delete' + name] = deleteReq returnObj['loading' + name] = loading returnObj['data' + name] = data returnObj['error' + name] = error } return returnObj }
Let's see, how can we use it in a component
component.js
<template> <div> <LoadingComponent loading="loading" /> <button @click="clickFunction"> Click me <button /> <div /> <template /> <script setup> import useAxios from '~/utils/useAxios' const { postReq, getReq, loading, data } = useAxios({ url: '/product', name: 'Product', }) const { putProduct2, loadingProduct2 } = useAxios({ url: '/product/2', name: 'Product2', }) const clickFunction = async () => { await putProduct2({ name: "Product 2 new name" }) // will get products in /api/v2/product await getReq() // you can also get in variable const productsData = await getReq() } <script />
Hope you like it!
Thanks for reading :)
Top comments (0)