Data Fetching
Vue.js enthält bewusst keine eingebaute Lösung für HTTP-Requests. Die Wahl des HTTP-Clients bleibt dem Entwickler überlassen.
Optionen im Überblick
Abschnitt betitelt „Optionen im Überblick“| Lösung | Typ | Größe | Besonderheiten |
|---|---|---|---|
| fetch | Browser API | 0 KB | Eingebaut, Promise-basiert |
| axios | Library | ~14 KB | Interceptors, weit verbreitet |
| ky | Library | ~4 KB | Fetch-Wrapper, modern |
| ofetch | Library | ~6 KB | Von Nuxt-Team, universal |
| wretch | Library | ~3 KB | Fluent API, klein |
Fetch API: Grundlagen
Abschnitt betitelt „Fetch API: Grundlagen“Die Fetch API ist in allen modernen Browsern eingebaut:
// GET Requestconst response = await fetch('https://api.example.com/users')const users = await response.json()
// POST Requestconst 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üfenif (!response.ok) { throw new Error(`HTTP ${response.status}`)}Fetch API: In Vue-Komponenten
Abschnitt betitelt „Fetch API: In Vue-Komponenten“<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>Fetch API: Limitierungen
Abschnitt betitelt „Fetch API: Limitierungen“- Kein automatisches JSON
- Fehler bei 4xx/5xx nicht geworfen
- Kein Request-Timeout (nativ)
- Kein einfaches Abbrechen
- Keine Interceptors
- Kein automatisches Retry
// fetch wirft NICHT bei HTTP-Fehlernconst response = await fetch('/api/users')// response.ok ist false bei 404/500// aber kein Error geworfen!
// Manuell prüfen nötigif (!response.ok) { throw new Error(`HTTP ${response.status}`)}const data = await response.json()npm install axios- Automatisches JSON
- Wirft bei HTTP-Fehlern
- Request/Response Interceptors
- Timeout-Unterstützung
- Request-Abbruch
- Browser + Node.js
import axios from 'axios'
// GETconst { data } = await axios.get('/api/users')
// POSTconst { data } = await axios.post('/api/users', { name: 'Max', email: 'max@test.de'})
// Fehler werden automatisch geworfentry { await axios.get('/api/not-found')} catch (error) { console.log(error.response.status) // 404}Axios: Instanz konfigurieren
Abschnitt betitelt „Axios: Instanz konfigurieren“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 apiAlternative: ky
Abschnitt betitelt „Alternative: ky“npm install kyimport ky from 'ky'
// Einfacher als fetchconst users = await ky.get('/api/users').json()
// POST mit JSONconst user = await ky.post('/api/users', { json: { name: 'Max' }}).json()
// Mit Optionenconst api = ky.create({ prefixUrl: 'https://api.example.com', timeout: 10000, retry: 2})- Moderner Fetch-Wrapper
- Nur ~4 KB
- Automatisches JSON
- Retry-Support
Alternative: ofetch
Abschnitt betitelt „Alternative: ofetch“npm install ofetchimport { ofetch } from 'ofetch'
// Automatisch JSONconst users = await ofetch('/api/users')
// POSTconst user = await ofetch('/api/users', { method: 'POST', body: { name: 'Max' }})
// Mit Basis-URLconst 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
Vergleich
Abschnitt betitelt „Vergleich“| Feature | fetch | axios | ky | ofetch |
|---|---|---|---|---|
| Größe | 0 KB | ~14 KB | ~4 KB | ~6 KB |
| Auto JSON | - | Ja | Ja | Ja |
| Error bei 4xx/5xx | - | Ja | Ja | Ja |
| Interceptors | - | Ja | Hooks | Hooks |
| Timeout | - | Ja | Ja | Ja |
| Retry | - | - | Ja | Ja |
| Node.js | -* | Ja | - | Ja |
* Node 18+ hat fetch eingebaut
Composable für Data Fetching
Abschnitt betitelt „Composable für Data Fetching“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 ändertconst { 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>TanStack Query (Vue Query)
Abschnitt betitelt „TanStack Query (Vue Query)“Für komplexere Anforderungen bietet TanStack Query erweiterte Features:
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
API-Schicht strukturieren
Abschnitt betitelt „API-Schicht strukturieren“src/├── api/│ ├── client.js # Axios/fetch Instanz│ ├── users.js # User-bezogene Endpoints│ ├── products.js # Produkt-bezogene Endpoints│ └── index.js # Re-exportsimport 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 Komponenteimport { usersApi } from '@/api'const { data } = await usersApi.getById(123)Empfehlungen
Abschnitt betitelt „Empfehlungen“- fetch + eigenes Composable
- Oder ofetch / ky
- Kein zusätzlicher Overhead
- axios mit Interceptors
- Zentrale API-Instanz
- Strukturierte API-Schicht
- TanStack Query
- Caching & Sync
- Optimistic Updates
- Pagination Support
- ofetch /
$fetch useFetchComposable- Server-Side Rendering
Dokumentation
Abschnitt betitelt „Dokumentation“Libraries:
Erweitert:
- TanStack Query - Data Fetching Library
- MDN Fetch API
- VueUse useFetch - Fertiges Composable