HTTP — fetch & axios

Get Data Into Your Components

HTTP — fetch & axios

Call APIs from onMounted, composables, or Pinia actions. Use the browser's fetch by default; reach for axios when you need interceptors and timeouts.

4 min read Level 2/5 #vue#http#fetch
What you'll learn
  • Fetch data inside onMounted
  • Wrap requests in a composable
  • Handle loading and error state

Vue has no built-in data layer — you call any HTTP library you like. The standards are the browser fetch for simple cases and axios when you want interceptors, request cancellation, or richer ergonomics.

fetch in onMounted

The simplest pattern: declare reactive state, fire the request in onMounted, store the result.

<script setup lang="ts">
import { ref, onMounted } from 'vue'

interface User { id: number; name: string }

const users = ref<User[]>([])
const loading = ref(false)
const error = ref<string | null>(null)

onMounted(async () => {
  loading.value = true
  try {
    const res = await fetch('/api/users')
    if (!res.ok) throw new Error(`HTTP ${res.status}`)
    users.value = await res.json()
  } catch (e: any) {
    error.value = e.message
  } finally {
    loading.value = false
  }
})
</script>

<template>
  <p v-if="loading">Loading…</p>
  <p v-else-if="error">Error: {{ error }}</p>
  <ul v-else>
    <li v-for="u in users" :key="u.id">{{ u.name }}</li>
  </ul>
</template>

axios

Axios sets timeouts, parses JSON, and supports interceptors out of the box.

import axios from 'axios'

const api = axios.create({ baseURL: '/api', timeout: 5000 })

api.interceptors.request.use(config => {
  config.headers.Authorization = `Bearer ${getToken()}`
  return config
})

const { data } = await api.get<User[]>('/users')

Where Should Requests Live?

  • One-off, component-local? Inline in onMounted.
  • Reused across components? A composable.
  • Shared, cached, or app-wide? A Pinia store action.
useFetch Composable →