aslain.dev
0%
01 Hizmetler 02 Hakkımda 03 Projeler 04 Stack 05 Blog 06 İletişim
← Tüm makaleler Développement Web

Next.js Server Actions : des formulaires sans API

Les Next.js Server Actions suppriment l'obligation d'écrire une route API séparée juste pour traiter un formulaire : tu places la logique de mutation dans une fonction qui s'exécute sur le serveur et tu relies le formulaire directement à elle. Résultat : tu peux créer et mettre à jour des données sans appel fetch, sans sérialisation JSON manuelle et sans fichier app/api/... dédié. Dans cet article, je mets en place les Server Actions à partir de zéro avec l'App Router, j'ajoute la validation et la gestion des erreurs, et j'aborde les points à surveiller en production.

Qu'est-ce qu'une Server Action et comment fonctionne-t-elle ?

Une Server Action est une fonction asynchrone dont le corps commence par la directive 'use server'. Cette fonction ne s'exécute que sur le serveur ; son code n'est jamais inclus dans le bundle client. Lorsque le formulaire est soumis, Next.js met en place l'appel réseau entre le navigateur et le serveur à ta place. Tu écris simplement la fonction, et Next.js en fait un point de terminaison appelable.

Il existe deux manières de la placer : au niveau du module dans un fichier dédié avec 'use server' en haut, ou définie en ligne à l'intérieur d'un Server Component. Pour du code réutilisable et testable, je préfère l'approche par fichier séparé.

Écris ta première Server Action

Plaçons d'abord l'action dans son propre fichier. Le 'use server' en haut du fichier transforme chaque fonction exportée en Server Action :

// app/actions.ts
'use server'

import { revalidatePath } from 'next/cache'
import { redirect } from 'next/navigation'

export async function createPost(formData: FormData) {
  const title = formData.get('title')
  const body = formData.get('body')

  // écris en base de données ici (Prisma, Drizzle, etc.)
  await db.post.create({ data: { title, body } })

  revalidatePath('/posts')
  redirect('/posts')
}

Le côté formulaire est étonnamment simple. Tu passes la fonction elle-même à l'attribut action, et non une URL :

// app/posts/new/page.tsx
import { createPost } from '@/app/actions'

export default function NewPost() {
  return (
    <form action={createPost}>
      <input name="title" />
      <textarea name="body" />
      <button type="submit">Enregistrer</button>
    </form>
  )
}

Remarque : le formulaire peut vivre dans un Server Component et fonctionne même si aucun JavaScript n'a été téléchargé. C'est une conséquence naturelle de l'amélioration progressive.

Valide l'entrée — ne fais jamais confiance aux données brutes

Une Server Action est un point de terminaison accessible publiquement ; elle peut être appelée directement quel que soit ce que tu affiches côté client. Valide donc toujours le FormData reçu sur le serveur. La validation basée sur un schéma avec Zod est une approche propre :

'use server'
import { z } from 'zod'

const PostSchema = z.object({
  title: z.string().min(3, 'Le titre doit comporter au moins 3 caractères'),
  body: z.string().min(10),
})

export async function createPost(prevState, formData: FormData) {
  const parsed = PostSchema.safeParse({
    title: formData.get('title'),
    body: formData.get('body'),
  })

  if (!parsed.success) {
    return { errors: parsed.error.flatten().fieldErrors }
  }

  await db.post.create({ data: parsed.data })
  revalidatePath('/posts')
  return { success: true }
}

safeParse renvoie un objet de résultat au lieu de lever une exception, ce qui te permet de renvoyer les erreurs de validation à l'utilisateur.

Gestion des erreurs et de l'état : useActionState

Pour relier au formulaire les erreurs renvoyées par l'action ci-dessus, on utilise le hook React useActionState (c'est son nom dans React 19 / Next.js 15 ; dans les versions plus anciennes c'était useFormState). Le hook nécessite un composant client :

'use client'
import { useActionState } from 'react'
import { createPost } from '@/app/actions'

export function PostForm() {
  const [state, formAction, pending] = useActionState(createPost, {})

  return (
    <form action={formAction}>
      <input name="title" />
      {state?.errors?.title && <p>{state.errors.title}</p>}
      <button disabled={pending}>
        {pending ? 'Enregistrement...' : 'Enregistrer'}
      </button>
    </form>
  )
}

La troisième valeur de retour, pending, vaut true pendant l'exécution de l'action et convient parfaitement pour désactiver le bouton. Pour des indicateurs de chargement plus granulaires, tu peux utiliser le hook useFormStatus dans un composant de bouton distinct.

Rafraîchir le cache : revalidatePath et revalidateTag

Après une mutation, l'écran doit afficher les données à jour. Comme Next.js met les données en cache de façon agressive, tu invalides explicitement le chemin concerné :

  • revalidatePath('/posts') — vide le cache d'une route spécifique.
  • revalidateTag('posts') — si tu as étiqueté tes appels fetch, rafraîchit toutes les données liées à ce tag.
  • redirect('/posts') — envoie l'utilisateur vers une autre page après la mutation ; appelle-le en dehors de tout bloc try/catch, car en interne il lève une erreur spéciale.

Points à surveiller en production

  • L'autorisation est obligatoire : une action est un point de terminaison. Vérifie la session/les permissions au début de chaque action ; masquer un bouton dans l'UI n'est pas une sécurité.
  • Isole les effets de bord : déplace la base de données, l'e-mail et le paiement dans des fonctions pures appelées par l'action ; garde l'action comme une fine couche.
  • Les valeurs de retour doivent être sérialisables : l'état renvoyé au client doit être des objets/tableaux simples — pas d'instances de classe ni de fonctions.
  • Tu peux quand même avoir besoin d'une API : si tu as une application mobile ou une intégration tierce, une Server Action ne la remplace pas ; il te faudra une vraie API.

Questions fréquentes

Les Server Actions ne s'utilisent-elles qu'avec des formulaires ?

Non. Relier à l'attribut action est la voie la plus courante, mais tu peux aussi appeler une Server Action depuis un gestionnaire onClick de bouton ou à l'intérieur de startTransition. La liaison au formulaire est préférée car elle fonctionne même lorsque JavaScript est désactivé.

Dois-je abandonner totalement les routes API ?

Non. Les Server Actions sont idéales pour les mutations déclenchées depuis ta propre UI. Lorsque tu as besoin de webhooks, de clients externes ou d'une interface REST/JSON publique, les route handlers classiques (app/api/...) restent le bon outil.

Les Server Actions sont-elles sécurisées ?

L'infrastructure est sécurisée — Next.js protège les identifiants d'action et associe les soumissions via des références chiffrées. Mais la sécurité de ta logique métier t'incombe : valide l'entrée et vérifie l'autorisation. Sans cela, tu laisses un point de terminaison ouvert.

Tes formulaires se compliquent-ils à cause du code réseau dans ton projet ? Je peux t'aider à construire une couche de données propre, validée et sécurisée avec les Next.js Server Actions — contacte-moi.

Bu kategorideki tüm yazılar →

Devamı için