Skip to Content

Chapitre 9.3 — Créer ses endpoints REST

⏱️ TL;DR — Quand les routes natives ne suffisent pas (logique métier, données agrégées, actions custom), on enregistre ses propres routes avec register_rest_route() sur le hook rest_api_init. Une route déclare : un namespace/version (wpr-books/v1), un chemin, une méthode (GET/POST…), un callback (la logique) et — obligatoire — un permission_callback (l’autorisation). On valide/assainit les arguments (args) et on retourne une WP_REST_Response (ou une WP_Error). C’est propre, sécurisé, et versionné.

🎯 Objectifs

  • Enregistrer une route REST custom.
  • Écrire un callback et surtout un permission_callback.
  • Valider et assainir les arguments.
  • Retourner des réponses et des erreurs correctes.

1. Enregistrer une route

add_action( 'rest_api_init', function () { register_rest_route( 'wpr-books/v1', '/stats', array( 'methods' => 'GET', 'callback' => 'wpr_books_stats', 'permission_callback' => '__return_true', // public (lecture) ) ); } ); function wpr_books_stats( WP_REST_Request $request ) { $count = wp_count_posts( 'livre' )->publish; return new WP_REST_Response( array( 'total_livres' => (int) $count ), 200 ); }
  • Namespace/version : wpr-books/v1 → route accessible sous /wp-json/wpr-books/v1/stats. Le versionnage (v1) permet d’évoluer sans casser les clients.
  • callback : la logique ; reçoit une WP_REST_Request et retourne une réponse.
  • permission_callback : qui a le droit (voir §2).

2. permission_callback : jamais l’oublier

Le permission_callback est obligatoire : il décide qui peut appeler la route.

// Lecture publique 'permission_callback' => '__return_true', // Réservé aux utilisateurs pouvant éditer des livres 'permission_callback' => function () { return current_user_can( 'edit_posts' ); }, // Vérifier un droit sur un objet précis 'permission_callback' => function ( WP_REST_Request $req ) { return current_user_can( 'edit_post', (int) $req['id'] ); },

⚠️ Piège critique — permission_callback manquant ou __return_true par défaut. Depuis WP 5.5, une route sans permission_callback déclenche un avertissement et est considérée non sécurisée. Ne mettez __return_true que pour de la lecture publique assumée. Pour toute écriture ou donnée sensible, vérifiez une capability (et l’authentification, ch. 9.2). C’est l’équivalent REST du « on autorise par capability » (ch. 7.7).


3. Valider et assainir les arguments

On déclare les args avec validation/sanitisation — WordPress les applique avant le callback :

register_rest_route( 'wpr-books/v1', '/livres', array( 'methods' => 'GET', 'callback' => 'wpr_books_liste', 'permission_callback' => '__return_true', 'args' => array( 'genre' => array( 'required' => false, 'type' => 'string', 'sanitize_callback' => 'sanitize_title', ), 'nombre' => array( 'default' => 10, 'type' => 'integer', 'sanitize_callback' => 'absint', 'validate_callback' => function ( $v ) { return $v > 0 && $v <= 100; }, ), ), ) ); function wpr_books_liste( WP_REST_Request $request ) { $args = array( 'post_type' => 'livre', 'posts_per_page' => (int) $request['nombre'] ); if ( $request['genre'] ) { $args['tax_query'] = array( array( 'taxonomy' => 'genre', 'field' => 'slug', 'terms' => $request['genre'] ) ); } $q = new WP_Query( $args ); $data = array_map( function ( $p ) { return array( 'id' => $p->ID, 'titre' => get_the_title( $p ), 'prix' => (float) get_post_meta( $p->ID, 'wpr_prix', true ), ); }, $q->posts ); return rest_ensure_response( $data ); }

sanitize_callback nettoie, validate_callback rejette les valeurs invalides (avec une erreur 400 automatique). On récupère les valeurs via $request['param'].


4. Réponses et erreurs

// Succès avec code + en-têtes $resp = new WP_REST_Response( $data, 200 ); $resp->header( 'X-Total', 42 ); return $resp; // Erreur normalisée return new WP_Error( 'wpr_not_found', __( 'Livre introuvable', 'wpr-books' ), array( 'status' => 404 ) );
  • rest_ensure_response() enveloppe un tableau/objet en réponse REST.
  • WP_Error avec status produit une erreur HTTP propre (code + message JSON) — le client peut la gérer.

💡 Pour un dev Reactregister_rest_route = définir un route handler (comme un app/api/route.ts de Next.js), avec permission_callback = votre middleware d’auth, args = la validation de schéma (façon zod), et WP_Error = une réponse d’erreur typée. Le versionnage dans le namespace (v1) est la bonne pratique d’API que vous connaissez. Vous exposez de la logique métier WordPress exactement comme vous écririez une API Next.


5. Bonnes pratiques

  • Namespace propre et versionné (monplugin/v1).
  • permission_callback explicite sur chaque route (jamais omis).
  • Valider/assainir tous les arguments (args + callbacks).
  • Ne pas ré-exposer ce que wp/v2 fait déjà : n’écrivez un endpoint que pour de la logique custom ou de l’agrégation.
  • Échapper ce qui doit l’être ; ne pas fuiter de données privées.
  • Documenter le schéma ('schema' => …) pour l’auto-découverte.

✏️ Exercices

  1. Quel argument de register_rest_route est indispensable pour la sécurité, et que se passe-t-il si on l’omet ?
  2. Vous voulez un endpoint GET /wpr-books/v1/livres?nombre=5. Comment garantir que nombre est un entier entre 1 et 100 ?
  3. Comment renvoyer une erreur 404 « Livre introuvable » proprement ?

✅ Solution

  1. Le permission_callback : il décide qui peut appeler la route. L’omettre déclenche un avertissement (depuis WP 5.5) et laisse la route non sécurisée. On met __return_true seulement pour de la lecture publique, sinon on vérifie une capability.
  2. Déclarer l’argument dans args avec type => 'integer', sanitize_callback => 'absint' et un validate_callback qui retourne ($v > 0 && $v <= 100) — WordPress rejette (400) les valeurs invalides avant le callback.
  3. return new WP_Error( 'wpr_not_found', __( 'Livre introuvable', 'wpr-books' ), array( 'status' => 404 ) ); — produit une réponse d’erreur JSON avec le code HTTP 404.

🧠 Quiz de révision

1. Sur quel hook enregistre-t-on une route REST ?

Sur rest_api_init (via register_rest_route).

2. Que déclare-t-on obligatoirement pour chaque route ?

Un permission_callback (l’autorisation) — en plus de methods et callback.

3. Comment valider/assainir un paramètre ?

Via args avec sanitize_callback (nettoyage) et validate_callback (validation, rejet 400).

4. Comment retourner une erreur HTTP ?

Avec WP_Error en incluant array( 'status' => 4xx/5xx ).

5. Pourquoi versionner le namespace ?

Pour faire évoluer l’API (v1v2) sans casser les clients existants.


Chapitre suivant : WPGraphQL.