Zum Inhalt springen

Data Fetching

Vue.js enthält bewusst keine eingebaute Lösung für HTTP-Requests. Die Wahl des HTTP-Clients bleibt dem Entwickler überlassen.

LösungTypGrößeBesonderheiten
fetchBrowser API0 KBEingebaut, Promise-basiert
axiosLibrary~14 KBInterceptors, weit verbreitet
kyLibrary~4 KBFetch-Wrapper, modern
ofetchLibrary~6 KBVon Nuxt-Team, universal
wretchLibrary~3 KBFluent API, klein

Die Fetch API ist in allen modernen Browsern eingebaut:

// GET Request
const response = await fetch('https://api.example.com/users')
const users = await response.json()
// POST Request
const response = await fetch('https://api.example.com/users', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ name: 'Max', email: 'max@test.de' })
})
// Response prüfen
if (!response.ok) {
throw new Error(`HTTP ${response.status}`)
}
<script setup>
import { ref, onMounted } from 'vue'
const users = ref([])
const isLoading = ref(false)
const error = ref(null)
async function fetchUsers() {
isLoading.value = true
error.value = null
try {
const response = await fetch('/api/users')
if (!response.ok) throw new Error(`HTTP ${response.status}`)
users.value = await response.json()
} catch (e) {
error.value = e.message
} finally {
isLoading.value = false
}
}
onMounted(fetchUsers)
</script>
  • Kein automatisches JSON
  • Fehler bei 4xx/5xx nicht geworfen
  • Kein Request-Timeout (nativ)
  • Kein einfaches Abbrechen
  • Keine Interceptors
  • Kein automatisches Retry
Terminal-Fenster
npm install axios
  • Automatisches JSON
  • Wirft bei HTTP-Fehlern
  • Request/Response Interceptors
  • Timeout-Unterstützung
  • Request-Abbruch
  • Browser + Node.js
api/client.js
import axios from 'axios'
const api = axios.create({
baseURL: 'https://api.example.com',
timeout: 10000,
headers: {
'Content-Type': 'application/json'
}
})
// Request Interceptor (z.B. für Auth Token)
api.interceptors.request.use((config) => {
const token = localStorage.getItem('token')
if (token) {
config.headers.Authorization = `Bearer ${token}`
}
return config
})
// Response Interceptor (z.B. für Error Handling)
api.interceptors.response.use(
(response) => response,
(error) => {
if (error.response?.status === 401) {
// Logout oder Token Refresh
}
return Promise.reject(error)
}
)
export default api
Terminal-Fenster
npm install ky
import ky from 'ky'
// Einfacher als fetch
const users = await ky.get('/api/users').json()
// POST mit JSON
const user = await ky.post('/api/users', {
json: { name: 'Max' }
}).json()
// Mit Optionen
const api = ky.create({
prefixUrl: 'https://api.example.com',
timeout: 10000,
retry: 2
})
  • Moderner Fetch-Wrapper
  • Nur ~4 KB
  • Automatisches JSON
  • Retry-Support
Terminal-Fenster
npm install ofetch
import { ofetch } from 'ofetch'
// Automatisch JSON
const users = await ofetch('/api/users')
// POST
const user = await ofetch('/api/users', {
method: 'POST',
body: { name: 'Max' }
})
// Mit Basis-URL
const api = ofetch.create({
baseURL: 'https://api.example.com',
headers: { Authorization: 'Bearer ...' }
})
  • Von Nuxt/UnJS Team
  • Universal (Browser + Node)
  • Wird in Nuxt 3 als Standard verwendet
Featurefetchaxioskyofetch
Größe0 KB~14 KB~4 KB~6 KB
Auto JSON-JaJaJa
Error bei 4xx/5xx-JaJaJa
Interceptors-JaHooksHooks
Timeout-JaJaJa
Retry--JaJa
Node.js-*Ja-Ja

* Node 18+ hat fetch eingebaut

composables/useFetch.js
import { ref, watchEffect, toValue } from 'vue'
export function useFetch(url) {
const data = ref(null)
const error = ref(null)
const isLoading = ref(false)
async function execute() {
isLoading.value = true
error.value = null
try {
const response = await fetch(toValue(url))
if (!response.ok) throw new Error(`HTTP ${response.status}`)
data.value = await response.json()
} catch (e) {
error.value = e
} finally {
isLoading.value = false
}
}
watchEffect(() => {
if (toValue(url)) execute()
})
return { data, error, isLoading, refetch: execute }
}
<script setup>
import { ref } from 'vue'
import { useFetch } from '@/composables/useFetch'
const userId = ref(1)
// Reaktiv - lädt neu wenn userId sich ändert
const { data: user, error, isLoading } = useFetch(
() => `/api/users/${userId.value}`
)
function nextUser() {
userId.value++
}
</script>
<template>
<div v-if="isLoading">Laden...</div>
<div v-else-if="error">Fehler: {{ error.message }}</div>
<div v-else>
<h2>{{ user?.name }}</h2>
<button @click="nextUser">Nächster</button>
</div>
</template>

Für komplexere Anforderungen bietet TanStack Query erweiterte Features:

Terminal-Fenster
npm install @tanstack/vue-query
<script setup>
import { useQuery } from '@tanstack/vue-query'
const { data: users, isLoading, error } = useQuery({
queryKey: ['users'],
queryFn: () => fetch('/api/users').then(r => r.json()),
staleTime: 5 * 60 * 1000, // 5 Minuten Cache
})
</script>

Features:

  • Automatisches Caching
  • Background Refetching
  • Pagination & Infinite Scroll
  • Mutations mit optimistischen Updates
  • DevTools
src/
├── api/
│ ├── client.js # Axios/fetch Instanz
│ ├── users.js # User-bezogene Endpoints
│ ├── products.js # Produkt-bezogene Endpoints
│ └── index.js # Re-exports
api/users.js
import api from './client'
export const usersApi = {
getAll: () => api.get('/users'),
getById: (id) => api.get(`/users/${id}`),
create: (data) => api.post('/users', data),
update: (id, data) => api.put(`/users/${id}`, data),
delete: (id) => api.delete(`/users/${id}`)
}
// In Komponente
import { usersApi } from '@/api'
const { data } = await usersApi.getById(123)
  • fetch + eigenes Composable
  • Oder ofetch / ky
  • Kein zusätzlicher Overhead

Libraries:

  • axios - HTTP Client
  • ky - Fetch Wrapper
  • ofetch - Universal Fetch

Erweitert: