Client, serveur et base de données
Le navigateur recueille les actions et affiche les résultats. PHP reçoit les requêtes, valide les données et interroge MySQL. MySQL conserve les enregistrements. Le navigateur ne reçoit pas les identifiants de connexion SQL : il parle à une API, pas directement à la base.
Une API est ici un ensemble d’adresses, de méthodes, de données attendues et de réponses. Le contrat permet à deux programmes d’être développés séparément tout en se comprenant. « Envoyer une tâche » doit préciser le nom du champ, son type, la méthode et la réponse de réussite.
| Situation | Méthode de notre API | Réponse attendue |
|---|---|---|
| Lire la liste. | GET | Tableau JSON, même si la liste est vide. |
| Ajouter une tâche. | POST | Tâche créée avec son identifiant. |
| Changer un champ. | PATCH | Tâche mise à jour. |
| Supprimer une tâche. | DELETE | Confirmation selon le contrat. |
Objets, tableaux et valeurs JSON
{"id": 3, "title": "Préparer les photos", "done": false}
Un objet associe des noms de propriétés à des valeurs. Les noms et les chaînes sont entre guillemets doubles. Un tableau utilise []. false est un booléen ; "false" est une chaîne ; null signale une absence explicitement prévue. JSON ne contient pas de fonction, de commentaire ni de virgule finale. Il s’agit d’un format de données, pas d’un programme exécuté.
Statut, en-têtes et corps HTTP
Le statut décrit le résultat de la requête ; les en-têtes précisent des informations comme le format ; le corps contient les données. Content-Type: application/json annonce le format du corps. Accept exprime le format souhaité par le client. Un statut 200 ne garantit pas que le corps possède les champs attendus : le client doit aussi contrôler sa forme.
404 et une liste vide ne signifient pas la même chose. Une liste vide peut être une lecture réussie ; une adresse inconnue produit une erreur de ressource. Dans notre API, 422 désigne des données analysables mais refusées par les règles. Ne choisissez pas un statut uniquement pour rendre un message vert ou rouge.
Le trajet d’une requête HTTP
Dans le TP du semestre, le navigateur affiche une liste de tâches. PHP décide quelles données lire et MySQL les conserve. Le navigateur ne connaît ni le mot de passe MySQL ni le code PHP exécuté : il échange des requêtes et des réponses HTTP avec le serveur. Une API constitue un contrat : une adresse, une méthode, un format et des statuts annoncés.
Imaginez un restaurant : le client formule une demande ; le serveur la transmet ; la cuisine prépare le résultat. Ce schéma aide à distinguer les rôles, mais une requête HTTP reçoit une réponse, même quand la préparation échoue. La base de données n’est pas directement accessible depuis fetch().
GET /api/todos.php HTTP/1.1
Host: localhost:8080
Accept: application/json
[
{ "id": 1, "title": "Préparer les photos", "done": false },
{ "id": 2, "title": "Écrire la légende", "done": true }
]
Résultat attendu : un tableau JSON contient deux objets. Les noms des propriétés sont entre guillemets doubles ; false est un booléen, pas la chaîne "false". JSON transporte des valeurs, pas une fonction JavaScript. Un texte JSON doit être analysé avant d’utiliser ses propriétés.
Suivre une requête et sa réponse — simulation
<style>
* {
box-sizing: border-box;
}
body {
margin: 0;
padding: 20px;
font-family: system-ui, sans-serif;
color: #18324c;
background: #f1f5f9;
}
button,
input,
select,
textarea {
font: inherit;
max-width: 100%;
}
button {
padding: 8px 12px;
cursor: pointer;
}
input,
select,
textarea {
padding: 8px;
}
:focus-visible {
outline: 3px solid #2563eb;
outline-offset: 3px;
}
article,
.panel {
padding: 16px;
background: white;
border-radius: 12px;
min-width: 0;
}
.cards {
display: grid;
gap: 16px;
}
label {
display: block;
margin-block: 12px 4px;
}
h1 {
font-size: 1.4rem;
}
h2 {
font-size: 1.15rem;
}
p,
h2,
a {
overflow-wrap: anywhere;
}
.note {
font-size: 0.9rem;
}
pre {
white-space: pre-wrap;
overflow-wrap: anywhere;
}
</style>
<h1>Navigateur → PHP → MySQL → réponse</h1>
<p>
Simulation pédagogique : aucun serveur PHP ni base ne s’exécute dans cet
aperçu.
</p>
<label for="scenario">Scénario</label>
<select id="scenario">
<option value="ok">Lecture réussie</option>
<option value="invalid">Titre refusé</option>
<option value="server">Base indisponible</option>
</select>
<button id="suivant">Étape suivante</button>
<button id="reset">Recommencer</button>
<ol id="trajet"></ol>
<pre id="sortie" aria-live="polite"></pre>
<script>
const scenarios = {
ok: [
"Navigateur : GET /api/todos.php",
"PHP : connexion PDO",
"MySQL : SELECT id, title, done FROM todos",
"PHP : réponse 200 application/json",
"Navigateur : JSON analysé, puis DOM construit",
],
invalid: [
"Navigateur : POST avec un titre vide",
"PHP : validation refusée avant SQL",
"PHP : réponse 422 application/json",
"Navigateur : message d’erreur ; saisie conservée",
],
server: [
"Navigateur : GET /api/todos.php",
"PHP : connexion PDO impossible",
"PHP : réponse 500 application/json",
"Navigateur : message général et possibilité de réessayer",
],
};
let index = 0;
const trajet = document.querySelector("#trajet");
const sortie = document.querySelector("#sortie");
function reset() {
index = 0;
trajet.replaceChildren();
sortie.textContent = "";
}
document.querySelector("#scenario").addEventListener("change", reset);
document.querySelector("#reset").addEventListener("click", reset);
document.querySelector("#suivant").addEventListener("click", () => {
const scenario = document.querySelector("#scenario").value;
const etapes = scenarios[scenario];
if (index >= etapes.length) return;
const li = document.createElement("li");
li.textContent = etapes[index++];
trajet.append(li);
if (index === etapes.length) {
sortie.textContent =
scenario === "ok"
? '[{"id":1,"title":"Préparer les photos","done":false}]'
: '{"error":"Opération impossible"}';
}
});
</script>Le panneau Réseau du navigateur
Dans F12 → Réseau, observez l’adresse, la méthode, le statut, les en-têtes et la réponse. 200 indique ici une lecture réussie ; 201 une création ; 400 une requête mal formée ; 404 une ressource absente ; 422 des données valides en JSON mais refusées par les règles du projet ; 500 une erreur du serveur. Le statut n’est pas la note de l’étudiant ! Content-Type décrit le corps envoyé ; Accept exprime le format souhaité par le client.
Les méthodes choisies pour notre contrat seront GET pour lire, POST pour créer, PATCH pour modifier certains champs et DELETE pour supprimer. Ce sont des conventions de cette API, qu’il faut respecter des deux côtés. GET ne doit pas supprimer une tâche au simple chargement d’un lien.