Les routes API
Ce que tu vas apprendre
- Créer une route d'API qui renvoie la liste des recettes.
- Lire un paramètre d'adresse, une requête et le corps d'un envoi.
- Renvoyer une erreur propre, comme une 404.
- Ranger une clé secrète pour qu'elle n'arrive jamais dans le navigateur.
Une route, un fichier
Les fichiers de server/api/ deviennent des adresses préfixées par /api. La fin du nom de fichier choisit la méthode HTTP : .get.ts pour lire, .post.ts pour créer.
| Fichier | Requête |
|---|---|
server/api/recettes.get.ts | GET /api/recettes |
server/api/recettes.post.ts | POST /api/recettes |
server/api/recettes/[id].get.ts | GET /api/recettes/12 |
Chaque fichier exporte un gestionnaire, defineEventHandler. Ce qu'il renvoie part en JSON :
// Pour l'exemple, les recettes sont dans un tableau.
// Dans un vrai projet, elles viendraient d'une base (Supabase par exemple).
const recettes = [
{ id: 1, titre: 'Crêpes', duree: 20, categorie: 'dessert' },
{ id: 2, titre: 'Ratatouille', duree: 60, categorie: 'plat' }
]
export default defineEventHandler(() => {
return recettes
})
Lance npm run dev et ouvre http://localhost:3000/api/recettes : le JSON s'affiche. C'est l'adresse que ta page appelle avec useFetch.
Lire ce que la requête contient
Le gestionnaire reçoit un event, qui décrit la requête. Des fonctions toutes prêtes en extraient les morceaux.
Un paramètre d'adresse, avec getRouterParam :
// recettes : le même tableau. Range-le dans server/utils/recettes.ts
// avec export const : Nuxt l'importe automatiquement dans tout server/.
export default defineEventHandler((event) => {
const id = Number(getRouterParam(event, 'id'))
const recette = recettes.find(r => r.id === id)
if (!recette) {
throw createError({ statusCode: 404, statusMessage: 'Recette introuvable' })
}
return recette
})
createError renvoie un vrai code HTTP. Côté page, useFetch le récupère dans error.
Une requête (/api/recettes?categorie=dessert), avec getQuery :
const { categorie } = getQuery(event)
Le corps d'un envoi, avec readBody (la fonction est asynchrone, d'où le await) :
export default defineEventHandler(async (event) => {
const corps = await readBody(event)
if (!corps?.titre) {
throw createError({ statusCode: 400, statusMessage: 'Le titre est obligatoire' })
}
// ... enregistrer la recette
return { ok: true }
})
Les secrets restent sur le serveur
Le code de server/ n'est jamais envoyé au navigateur. C'est le seul endroit où utiliser une clé secrète (clé de base de données, clé d'un service payant). Déclare-la dans runtimeConfig :
export default defineNuxtConfig({
runtimeConfig: {
cleApi: '', // secrète : lisible seulement côté serveur
public: {
nomSite: 'Mes recettes' // publique : lisible partout
}
}
})
La vraie valeur se met dans le fichier .env, jamais dans le code. Le nom de la variable suit une règle : NUXT_ puis le nom en majuscules, mots séparés par _.
NUXT_CLE_API=ta-cle-secrete
Dans une route d'API, tu la lis avec useRuntimeConfig(event) :
export default defineEventHandler((event) => {
const config = useRuntimeConfig(event)
// config.cleApi est disponible ici, jamais dans le navigateur
})
.env à ton .gitignore : un secret poussé sur GitHub doit être considéré comme volé, il faut le changer.À retenir
server/api/nom.get.tsrépond àGET /api/nom; ce que renvoiedefineEventHandlerpart en JSON.getRouterParam,getQueryetreadBodylisent la requête ;createErrorrenvoie un code d'erreur.- Vérifie toujours les données reçues.
- Les secrets vont dans
runtimeConfiget.env, et se lisent seulement côté serveur.
Pour aller plus loin
Sources officielles
Ensuite
Récupérer des données
Charger des données avec useFetch, gérer le chargement et les erreurs, et savoir quand utiliser $fetch.
Les modes de rendu
Universel, client, statique ou hybride : où la page est fabriquée, et comment choisir pour chaque partie du site.
- Projet
- Lignes de code
- Niveau
- Toit-terrasse
- Appartement
- Nuxt
- Pièce
- 6/8
- Plan n°
- nuxt/06.routes-api