# Négocier le format d’une réponse REST avec l’en-tête Accept, sans paramètre

> Un paramètre d'URL comme ?format=xml fonctionne, mais un en-tête Accept standard évite d'exposer ce détail dans chaque appel du front.

- Auteur : WordPress Développement
- Publié le : 2022-04-22
- Mis à jour le : 2022-04-22
- Catégorie : Headless &amp; API
- URL : https://www.wpmoderne.fr/headless/negocier-format-reponse-rest-accept-sans-parametre/

## L’essentiel

- L'en-tête Accept exprime une préférence de format sans polluer l'URL
- WP_REST_Request expose get_header pour lire cette préférence
- La réponse doit annoncer son propre Content-Type en retour

Un paramètre `?format=csv` dans l'URL fonctionne parfaitement pour choisir un format de sortie alternatif, mais il mélange une information de transport — comment le client souhaite recevoir la donnée — avec les paramètres métier de la requête elle-même. L'en-tête HTTP `Accept`, prévu précisément pour cet usage depuis les débuts du protocole, permet de séparer les deux préoccupations sans rien ajouter à l'URL.

## Ce que fait normalement Accept

Dans une architecture REST classique, un client envoie `Accept: application/json` ou `Accept: text/csv` pour indiquer au serveur le format de réponse qu'il préfère recevoir, laissant au serveur la responsabilité de choisir la représentation la plus adaptée parmi celles qu'il sait produire. L'API REST native de WordPress ne pratique pas cette négociation automatiquement : elle renvoie toujours du JSON, quel que soit l'en-tête `Accept` transmis. Pour un contrôleur personnalisé, rien n'empêche cependant d'implémenter cette logique soi-même.

## Implémenter la négociation dans un contrôleur

> L'essentiel à retenir : L'en-tête Accept exprime une préférence de format sans polluer l'URL ; WP_REST_Request expose get_header pour lire cette préférence ; La réponse doit annoncer son propre Content-Type en retour

```
register_rest_route( 'catalogue/v1', '/produits', array(
    'methods'  => 'GET',
    'callback' => 'lister_produits_negocie',
) );

function lister_produits_negocie( WP_REST_Request $request ) {
    $accept   = $request->get_header( 'accept' );
    $produits = get_produits_actifs();

    if ( $accept && false !== strpos( $accept, 'text/csv' ) ) {
        $lignes = array( 'id,nom,prix' );
        foreach ( $produits as $produit ) {
            $lignes[] = sprintf( '%d,%s,%s', $produit->id, $produit->nom, $produit->prix );
        }
        $reponse = new WP_REST_Response( implode( "\n", $lignes ) );
        $reponse->header( 'Content-Type', 'text/csv; charset=utf-8' );
        return $reponse;
    }

    return new WP_REST_Response( $produits );
}
```

La méthode `get_header()` de l'objet `WP_REST_Request` lit directement la valeur de l'en-tête transmis par le client, sans distinction de casse. La comparaison se fait ici de façon simple par recherche de sous-chaîne, ce qui suffit dans la majorité des cas concrets, même si une implémentation plus stricte pourrait analyser précisément la syntaxe complète de l'en-tête `Accept`, qui autorise plusieurs types pondérés séparés par des virgules.

## Annoncer correctement la réponse

Le point souvent oublié dans ce genre d'implémentation tient à l'en-tête `Content-Type` de la réponse elle-même. Sans lui, un client qui a demandé du CSV recevrait un contenu au bon format mais annoncé comme du JSON, ce qui perturbe les bibliothèques HTTP qui décident de leur méthode de parsing en fonction de cet en-tête plutôt que du contenu réel reçu.

## Limites de cette approche

- Chaque contrôleur doit implémenter sa propre logique de négociation ; rien n'est mutualisé nativement par WordPress
- Un en-tête `Accept` mal formé ou absent doit toujours retomber sur un format par défaut raisonnable, ici JSON
- Les outils de mise en cache intermédiaires doivent être configurés pour varier leur clé de cache selon l'en-tête `Accept`, via l'en-tête de réponse `Vary: Accept`, sous peine de servir le mauvais format à un client suivant

## Variante

Pour une route qui doit gérer plus de deux formats, structurer la négociation autour d'un tableau associant chaque type MIME à sa fonction de sérialisation dédiée reste plus maintenable qu'une cascade de conditions `if` répétées, surtout si de nouveaux formats sont amenés à s'ajouter par la suite.

## En résumé

Négocier le format d'une réponse REST via l'en-tête `Accept` plutôt qu'un paramètre d'URL dédié garde l'URL propre et respecte l'esprit du protocole HTTP tel qu'il a été pensé. WordPress ne fournit aucun mécanisme automatique pour cela, mais l'implémenter manuellement dans un contrôleur personnalisé reste accessible, à condition de soigner à la fois la lecture de l'en-tête entrant et l'annonce correcte du `Content-Type` en sortie.
