Toit-terrasseN NuxtPièce 6/8Intermédiaire

Les routes API

Écrire une petite API dans server/api : lire, créer, renvoyer des erreurs, et garder les secrets côté serveur.

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.

FichierRequête
server/api/recettes.get.tsGET /api/recettes
server/api/recettes.post.tsPOST /api/recettes
server/api/recettes/[id].get.tsGET /api/recettes/12

Chaque fichier exporte un gestionnaire, defineEventHandler. Ce qu'il renvoie part en JSON :

server/api/recettes.get.ts
// 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 :

server/api/recettes/[id].get.ts
// 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) :

server/api/recettes.post.ts
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 }
})
Ne fais jamais confiance aux données reçues : n'importe qui peut appeler ton API avec n'importe quel contenu. Vérifie chaque champ avant de l'enregistrer.

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 :

nuxt.config.ts
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 _.

.env
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
})
Ajoute .env à ton .gitignore : un secret poussé sur GitHub doit être considéré comme volé, il faut le changer.

À retenir

  • server/api/nom.get.ts répond à GET /api/nom ; ce que renvoie defineEventHandler part en JSON.
  • getRouterParam, getQuery et readBody lisent la requête ; createError renvoie un code d'erreur.
  • Vérifie toujours les données reçues.
  • Les secrets vont dans runtimeConfig et .env, et se lisent seulement côté serveur.

Pour aller plus loin

Sources officielles

Ensuite

Projet
Lignes de code
Niveau
Toit-terrasse
Appartement
Nuxt
Pièce
6/8
Plan n°
nuxt/06.routes-api
Lignes de code · fiches rédigées à partir des documentations officielles, sources citées en bas de chaque page.