Construisez une API JSON rigoureuse en maîtrisant les en-têtes, la lecture du corps brut et la sémantique fine des codes de statut.
Ouvrir cette leçon dans KodokonUne API JSON est un contrat : chaque réponse annonce son type (Content-Type: application/json), porte le bon code de statut et une structure stable. PHP n'envoie rien de tout cela par défaut - il déclare text/html. Première brique : un helper de réponse unique, typé never (PHP 8.1+). Ce type de retour garantit, au moteur comme aux outils d'analyse statique, que la fonction ne rend jamais la main : tout code écrit après un appel est prouvé inatteignable.
<?php
declare(strict_types=1);
function jsonResponse(
mixed $data,
int $status = 200
): never {
http_response_code($status);
header('Content-Type: application/json');
echo json_encode(
$data,
JSON_THROW_ON_ERROR | JSON_UNESCAPED_UNICODE
);
exit;
}
jsonResponse(['status' => 'ok']);Deuxième subtilité, souvent découverte trop tard : $_POST reste vide face à un corps JSON. PHP ne le remplit que pour application/x-www-form-urlencoded et multipart/form-data. Le corps brut se lit sur le flux php://input. Décodez-le avec JSON_THROW_ON_ERROR : sans ce drapeau, json_decode renvoie silencieusement null en cas d'erreur - indistinguable d'un corps contenant littéralement null. Et grâce au type never, le switch ci-dessous n'a besoin d'aucun break.
<?php
declare(strict_types=1);
switch ($_SERVER['REQUEST_METHOD']) {
case 'GET':
jsonResponse(['items' => []]);
case 'POST':
$raw = (string) file_get_contents(
'php://input'
);
try {
$payload = json_decode(
$raw,
true,
512,
JSON_THROW_ON_ERROR
);
} catch (JsonException) {
jsonResponse(
['error' => 'Malformed JSON'],
400
);
}
header('Location: /items/42');
jsonResponse(['created' => $payload], 201);
default:
header('Allow: GET, POST');
jsonResponse(
['error' => 'Method not allowed'],
405
);
}Choisissez les codes avec précision, car vos clients programmeront contre eux, pas contre vos messages : 200 lecture réussie, 201 création (accompagnée d'un en-tête Location pointant vers la ressource), 204 succès sans corps, 400 JSON malformé, 404 ressource absente, 405 méthode non gérée (avec l'en-tête Allow listant celles permises) et 422 pour un JSON syntaxiquement valide mais sémantiquement incorrect. Vérifiez le tout avec curl -i, qui affiche les en-têtes reçus.
curl -i -X POST http://localhost:8000/items \
-H 'Content-Type: application/json' \
-d '{"name":"Widget"}'