A common pattern when using Axios in Vue.js apps, is to create a custom axios
instance with interceptors attached in order to handle things (like e.g authentication and error reporting) globally.
We then use that instance in our API functions that are grouped inside files and/or folders depending on the business context.
Finally we import the API functions inside our components in order to fetch data.
Let's look at how we can implement the same pattern in Nuxt when using the composition api.
Install Nuxt composition API
Since we'll be using the Vue.js composition API we'll install the Nuxt plugin that will allow us to use the Vue 3 Composition API with Nuxt-specific features.
npm install @nuxtjs/composition-api
Let's add it in nuxt.config.js
inside the buildModules
array.
nuxt.config.js
{
...
buildModules: [
'@nuxtjs/composition-api/module'
]
...
}
Install, setup, and configure Nuxt Axios
We also need the nuxt/axios
plugin which integrates Axios to Nuxt. There's no need to install axios as a standalone package, as the plugin takes care of that under the hood.
npm install @nuxtjs/axios
We'll add it in nuxt.config.js
inside the modules
array.
We're also using the axios
key in order to set some global options which will be applied to all requests. In this case we're only adding our API base URL as an example.
nuxt.config.js
{
...
modules: [
'@nuxtjs/axios'
],
axios: {
baseURL: 'https://reqres.in/api/',
}
...
}
Create and customize the Axios instance
In order to customize Axios by registering interceptors and changing global config, we have to create and register a Nuxt plugin. We are injecting our instance as api
into the context so that we can use it later in our functions as $api
using the useContext
composable.
plugins/api.js
export default function ({ $axios, app }, inject) {
const api = $axios.create()
api.onRequest((config) => {
console.log(`Making request to ${config.url}`)
})
api.onError((error) => {
const code = parseInt(error.response && error.response.status)
const errorText = code
? `A request failed with status code ${code}`
: `A network error occurred`
console.error(errorText)
})
api.onResponse((res) => {
return res.data
})
inject('api', api)
}
We can use the onRequest
, onResponse
, and onError
helpers to intercept the request/response and handle errors respectively. Learn more about nuxt/axios
helpers here. In our example we'll just use the onResponse
helper to return the data from the response instead of the whole response object.
We are now ready to create our API functions and use them inside our Vue.js components
API functions
We are using the reqres API in our example to setup two methods for fetching users.
Notice how we're implementing our module as a composable so that it exports a function that returns an object with our data-fetching methods. We need to do this because
useContext
only works inside the Vue component'ssetup
method.
api/user.js
import { useContext } from '@nuxtjs/composition-api'
export const userApi = () => {
const { $api } = useContext()
const fetchUser = async (userId) => {
const res = await $api.get(`users/${userId}`)
return res
}
const fetchUsers = async () => {
const res = await $api.get('users')
return res
}
return {
fetchUser,
fetchUsers,
}
}
finally we can
Use the API functions inside our components
We can call our API function directly or use useFetch or useAsync depending on what we want to achieve.
<template>
<div>
<div>
<button type="button" class="btn btn-primary" @click="loadUsers">
Fetch users
</button>
</div>
<div>
<pre>{{ users }}</pre>
</div>
</div>
</template>
<script>
import { defineComponent, ref } from '@nuxtjs/composition-api'
import { userApi } from '@/api/user'
export default defineComponent({
setup() {
const { fetchUsers } = userApi()
const users = ref([])
const loadUsers = async () => {
const res = await fetchUsers()
users.value = res.data
}
return {
users,
loadUsers,
}
},
})
</script>
That was it, using this technique we can group our API calls in functions as we would do in a plain Vue.js app.
Here's a StackBlitz example that demonstrates it in action.
Thanks for reading!
Top comments (0)