DEV Community

Ata Parvin Ghods
Ata Parvin Ghods

Posted on • Updated on

Easier way of data fetching with Axios in Vue3

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
  })
Enter fullscreen mode Exit fullscreen mode

Or maybe like this

axios
  .get("/some-api-url")
  .then((res) => {
     // more response code here
  }).catch((err) => {
     // more error code here
  })
Enter fullscreen mode Exit fullscreen mode

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
  })
Enter fullscreen mode Exit fullscreen mode

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
}
Enter fullscreen mode Exit fullscreen mode

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
  }
}
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
}

Enter fullscreen mode Exit fullscreen mode

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 />
Enter fullscreen mode Exit fullscreen mode

Hope you like it!
Thanks for reading :)

Top comments (0)