fetch, Axios et API Client typé
Utilisez les flèches, cliquez ou glissez pour naviguer
1. Comprendre fetch()
Et ses pièges (pas de throw sur erreurs HTTP)
2. Utiliser Axios
Appels HTTP plus ergonomiques
3. Construire un client API
Réutilisable avec interceptors
4. Typer les réponses
Interfaces TypeScript
5. Configurer les variables d'environnement
Et comprendre CORS
Rappel HTTP
Verbes, status codes, headers, JSON
fetch() natif
Syntaxe, async/await, gestion d'erreur
Axios
Installation, avantages, interceptors
Client API réutilisable
baseURL, headers, TypeScript
Live coding
Connecter React à une API REST
Ce que le backend attend de vous
HTTP = HyperText Transfer Protocol
Le langage de communication client-serveur
GET
Récupérer des données
Sans effet de bord
POST
Créer une ressource
Envoyer des données
PUT
Remplacer une ressource
Mise à jour complète
PATCH
Modifier partiellement
Mise à jour partielle
DELETE
Supprimer une ressource
Succès
200 OK, 201 Created, 204 No Content
Redirection
301 Moved, 304 Not Modified
Erreur client
400 Bad Request, 401 Unauthorized, 404 Not Found
Erreur serveur
500 Internal Server Error, 503 Service Unavailable
Request Headers
Content-Type: application/json
Authorization: Bearer <token>
Accept: application/json
Pourquoi JSON ?
💡 Toujours définir Content-Type: application/json quand vous envoyez du JSON
fetch() natifL'API native du navigateur
Disponible dans tous les navigateurs modernes
Pas d'installation nécessaire
const response = await fetch('https://api.example.com/users')
const data = await response.json()
// data contient les utilisateurs
1. fetch()
Retourne une Promise<Response>
2. response.json()
Parse le body en JSON (async!)
async function getUsers() {
try {
const response = await fetch('https://api.example.com/users')
const data = await response.json()
return data
} catch (error) {
console.error('Erreur:', error)
}
}
Deux await nécessaires : un pour la réponse, un pour le JSON
fetch() ne throw PAS sur les erreurs HTTP!
❌ 404 Not Found → Pas d'exception!
❌ 500 Server Error → Pas d'exception!
❌ 401 Unauthorized → Pas d'exception!
Le catch() n'attrape QUE les erreurs réseau
❌ Code trompeur
try {
const res = await fetch('/api/404')
const data = await res.json()
// data = { error: 'Not found' }
// Pas d'erreur lancée!
} catch (e) {
// Jamais exécuté!
}
✅ Code correct
try {
const res = await fetch('/api/users')
if (!res.ok) {
throw new Error(`HTTP ${res.status}`)
}
const data = await res.json()
} catch (e) {
// Gère les erreurs HTTP!
}
🔑 response.ok est un booléen (true si status 200-299)
const response = await fetch('/api/users', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
name: 'Alice',
email: '[email protected]'
})
})
method
GET, POST, PUT, DELETE
headers
Objet key-value
body
String (JSON.stringify)
Le client HTTP populaire
Plus ergonomique que fetch
Gère automatiquement les erreurs HTTP
# npm
npm install axios
# yarn
yarn add axios
# pnpm
pnpm add axios
📦 ~13 KB gzipped — worth it!
| Critère | fetch() | Axios |
|---|---|---|
| Installation | Natif | npm install |
| JSON parsing | Manuel (await res.json()) | Automatique |
| Erreurs HTTP (4xx/5xx) | Ne throw pas | Throw automatique |
| Timeout | AbortController complexe | Simple config |
| Interceptors | Non | Oui |
| Taille | 0 KB | ~13 KB |
Axios : plus intuitif pour la gestion d'erreurs
GET
import axios from 'axios'
const response = await axios.get('/api/users')
const users = response.data
POST
✅ Pas besoin de JSON.stringify — Axios le fait automatiquement!
try {
const response = await axios.get('/api/users/999')
// Si 404, on n'arrive jamais ici!
} catch (error) {
if (error.response) {
// Erreur HTTP (4xx ou 5xx)
console.log(error.response.status) // 404
} else {
// Erreur réseau
}
}
error.response contient la réponse HTTP même en cas d'erreur
Réutilisable et typé
Une instance Axios configurée une seule fois
Utilisée partout dans l'application
import axios from 'axios'
const api = axios.create({
baseURL: 'https://api.example.com',
timeout: 5000,
headers: {
'Content-Type': 'application/json',
},
})
export default api
baseURL
Préfixe pour toutes les requêtes
timeout
5 secondes max
headers
Défaut pour toutes les requêtes
api.interceptors.request.use((config) => {
const token = localStorage.getItem('token')
if (token) {
config.headers.Authorization = `Bearer ${token}`
}
return config
})
Chaque requête inclut automatiquement le token JWT
Plus besoin de le gérer manuellement dans chaque appel
api.interceptors.response.use(
// Succès
(response) => response,
// Erreur
(error) => {
if (error.response?.status === 401) {
// Token expiré → redirect login
window.location.href = '/login'
}
return Promise.reject(error)
}
)
💡 Gestion centralisée des erreurs 401 — redirection automatique vers login
interface User {
id: number
name: string
email: string
phone?: string // optionnel
}
interface ApiResponse<T> {
data: T
status: number
}
Utiliser api.get<User[]>('/users') pour typer la réponse
Configurer sans hardcoded
Différentes URLs pour dev, staging, production
Jamais de secrets dans le code!
.env.local
VITE_API_URL=http://localhost:3000/api
VITE_API_KEY=dev-key-123
api.ts
const api = axios.create({
baseURL: import.meta.env.VITE_API_URL,
})
⚠️ Seules les variables préfixées par VITE_ sont exposées au client
Cross-Origin Resource Sharing
Pourquoi vos requêtes échouent parfois
Et comment les résoudre
Le problème
Frontend sur localhost:5173 appelle API sur localhost:3000
Origines différentes = blocage par le navigateur
La solution
Le serveur doit autoriser votre origine
Header: Access-Control-Allow-Origin: *
⚠️ CORS se configure côté SERVEUR, pas côté frontend!
C'est une protection du navigateur pour l'utilisateur
Connecter React à une API REST
API publique : JSONPlaceholder
https://jsonplaceholder.typicode.com
src/
api/
client.ts
types.ts
users.ts
hooks/
useUsers.ts
components/
UserList.tsx
api/
Client Axios + types
hooks/
Logique de fetch
components/
UI
export interface User {
id: number
name: string
username: string
email: string
phone: string
website: string
company: {
name: string
}
}
Interface basée sur la réponse de JSONPlaceholder
import axios from 'axios'
const api = axios.create({
baseURL: import.meta.env.VITE_API_URL,
timeout: 10000,
headers: { 'Content-Type': 'application/json' },
})
export default api
✅ Une seule instance configurée — réutilisée partout
import api from './client'
import type { User } from './types'
export const userApi = {
getAll: async (): Promise<User[]> => {
const { data } = await api.get<User[]>('/users')
return data
},
getById: async (id: number): Promise<User> => {
const { data } = await api.get<User>(`/users/${id}`)
return data
},
}
Fonctions typées — IntelliSense complet dans VS Code
import { useState, useEffect } from 'react'
import { userApi } from '../api/users'
import type { User } from '../api/types'
export function useUsers() {
const [users, setUsers] = useState<User[]>([])
const [loading, setLoading] = useState(true)
const [error, setError] = useState<string | null>(null)
Trois états : data, loading, error — le pattern standard
useEffect(() => {
async function fetchUsers() {
try {
const data = await userApi.getAll()
setUsers(data)
} catch (err) {
setError('Erreur lors du chargement')
} finally {
setLoading(false)
}
}
fetchUsers()
}, [])
return { users, loading, error }
}
import { useUsers } from '../hooks/useUsers'
export function UserList() {
const { users, loading, error } = useUsers()
if (loading) return <p>Chargement...</p>
if (error) return <p>{error}</p>
return (
<ul>
{users.map((user) => (
<li key={user.id}>{user.name}</li>
))}
</ul>
)
}
Les erreurs à éviter absolument
❌ Incorrect
const data = response.json()
// data est une Promise!
✅ Correct
const data = await response.json()
// data est l'objet JSON
💡 Double await nécessaire avec fetch : un pour la réponse, un pour le JSON
Avec fetch(), le catch() n'attrape PAS les erreurs HTTP!
try {
const res = await fetch('/api/inexistant')
// res.status = 404, mais pas d'erreur!
} catch (e) {
// Jamais exécuté pour un 404
}
✅ Solution : Vérifier response.ok ou utiliser Axios
❌ Jamais!
const API_KEY = 'sk-abc123...'
// Visible dans le code client!
✅ Utiliser .env
const key = import.meta.env.VITE_API_KEY
// Configurable par environnement
⚠️ Les clés API exposées au client sont visibles par tous — utiliser un backend comme proxy si possible
CORS se configure côté SERVEUR, pas côté frontend!
❌ Frontend ne peut rien faire
Pas de config magique dans React
✅ Backend doit autoriser
Header Access-Control-Allow-Origin
💡 En développement, utiliser un proxy Vite ou configurer le backend
fetch()
Axios
API Client
Sécurité
Vous avez appris
Prochaines étapes
Questions ?