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)