Compresser systématiquement chaque réponse d’un serveur GraphQL, quelle que soit sa taille, part d’une bonne intention mais produit parfois l’effet inverse de celui recherché : sur une réponse déjà minuscule, le coût CPU de la compression peut dépasser le gain de bande passante obtenu, surtout si le serveur applique un niveau de compression élevé par défaut.
Le problème observé
Sur un projet exposant WPGraphQL derrière un serveur PHP-FPM sans compression gérée directement par un CDN, l’activation de la compression Gzip au niveau applicatif, pour toutes les réponses sans distinction, a fait apparaître un usage CPU sensiblement plus élevé sur les requêtes GraphQL les plus courtes et les plus fréquentes — typiquement des requêtes de vérification d’état ou des requêtes très ciblées ne renvoyant que quelques champs. Ces requêtes, déjà légères en poids, n’avaient presque rien à gagner d’une compression, tout en payant intégralement son coût de calcul.
La logique retenue : un seuil de taille

// Démarre la mise en tampon dès que la requête cible l'endpoint /graphql,
// avant que WPGraphQL ne commence à écrire sa réponse.
add_action( 'init', function () {
if ( false !== strpos( $_SERVER['REQUEST_URI'] ?? '', '/graphql' ) ) {
ob_start();
}
} );
add_action( 'shutdown', function () {
if ( ! ob_get_level() ) {
return;
}
$contenu = ob_get_clean();
$accepte_gzip = isset( $_SERVER['HTTP_ACCEPT_ENCODING'] )
&& false !== strpos( $_SERVER['HTTP_ACCEPT_ENCODING'], 'gzip' );
if ( $accepte_gzip && strlen( $contenu ) > 4096 ) {
header( 'Content-Encoding: gzip' );
echo gzencode( $contenu, 6 );
} else {
echo $contenu;
}
}, 0 );
Ce mécanisme s’appuie sur la mise en tampon de sortie native de PHP, disponible sans aucune extension supplémentaire, et sur gzencode(), également native via l’extension zlib presque systématiquement activée sur les hébergements PHP courants. Le seuil de 4 kilo-octets a été choisi empiriquement sur ce projet, après avoir observé la distribution réelle des tailles de réponses GraphQL sur plusieurs jours de trafic : la grande majorité des requêtes courtes restaient sous ce seuil, tandis que les requêtes imbriquées les plus coûteuses le dépassaient largement.
Ce que ce mécanisme évite
- Compresser une réponse de quelques centaines d’octets pour un gain de transfert négligeable
- Appliquer un niveau de compression élevé à toutes les réponses sans distinction de taille
- Dépendre uniquement de la configuration du serveur web pour ce comportement, ce qui le rend portable d’un environnement d’hébergement à un autre
Vérifier le comportement obtenu
curl -s -H "Accept-Encoding: gzip" -o /dev/null -w "%{size_download}\n" \
https://exemple.test/graphql -d '{"query":"{ posts { nodes { id } } } "}'
Comparer la taille annoncée par cette commande, avec et sans l’en-tête Accept-Encoding, permet de confirmer que la compression ne s’active bien qu’au-delà du seuil fixé, et que les réponses courtes restent transmises telles quelles, sans en-tête Content-Encoding superflu.
Une limite à connaître
Cette approche suppose de désactiver la compression gérée automatiquement par le serveur web ou par un éventuel module PHP de compression de sortie, sous peine de compresser deux fois la même réponse ou de provoquer des en-têtes contradictoires. Sur un projet où un CDN gère déjà la compression en frontal, ce mécanisme applicatif devient redondant, voire contre-productif : mieux vaut alors s’appuyer sur les règles de seuil que propose directement ce CDN plutôt que de dupliquer la logique côté PHP.
En résumé
Compresser une réponse GraphQL n’est pas systématiquement rentable : en dessous d’une certaine taille, le coût CPU dépasse le gain de transfert. Introduire un seuil simple avant de déclencher la compression, appuyé sur la mise en tampon native de PHP et sur gzencode(), permet de réserver cet effort aux réponses qui en tirent réellement profit, sans sacrifier les requêtes courtes et fréquentes qui composent souvent l’essentiel du trafic d’une API GraphQL.