Envoyer un POST JSON avec Python requests
requests.post(url, json=payload) envoie un corps JSON à un serveur en une seule ligne. L’argument json= sérialise le dictionnaire, définit l’en-tête Content-Type: application/json et écrit le corps de la requête. La réponse renvoie un code de statut et, pour la plupart des APIs, les données que le serveur a stockées, ce qui permet de confirmer que l’appel a fait ce qu’il devait. C’est le pattern derrière les écritures REST API, les webhooks et tout endpoint attendant une charge JSON.
Exemple Python requests.post pour JSON
Sortie :
La sortie apparaîtra ici...
Sortie :
Status: 201
Server stored: {'language': 'Python', 'stars': 3, 'id': 101}
Comment Fonctionne Cet Exemple
json=sérialise le dict et définitContent-Type: application/json, de sorte que le serveur reçoit un objet JSON plutôt que des champs de formulaire.timeout=10limite l’attente, pour qu’un endpoint inaccessible échoue vite plutôt que de bloquer l’exécution.raise_for_status()transforme une réponse 4xx ou 5xx en exception, de sorte qu’une réponse échouée ne continue jamais silencieusement.response.json()retourne la réponse comme un dict Python. Cette API de test renvoie vos champs et ajoute unidattribué par le serveur ; le statut201 Createdconfirme que l’appel a été traité comme une nouvelle ressource.
Vérifier Ce que le Serveur a Réellement Reçu
Deux signaux indépendants confirment que le POST a fonctionné ; une vérification fiable utilise les deux. Le corps de la réponse prouve que le contenu est arrivé : les champs renvoyés plus un nouvel id signifient que le serveur a interprété votre JSON. Run Details prouve le transport : il enregistre la requête que le navigateur a réellement envoyée.
| Signal Run Details | Ce qu’il confirme |
|---|---|
| Un POST sur jsonplaceholder.typicode.com, statut 201 | L’appel est parti en POST et le serveur a créé une ressource |
| La colonne méthode affiche POST, pas GET | requests.post a envoyé le verbe souhaité |
| La durée de la requête en ms | Temps aller-retour, mesuré séparément du parsing JSON |
| Statut bloqué ou échoué, sans code HTTP | La requête n’a pas atteint le serveur (voir CORS ci-dessous) |
| Packages liste requests | web.run a chargé le paquet requests à l’import |
Quand le code de statut est 2xx mais que le corps renvoyé ne contient pas vos champs, le transport a réussi, pas le contenu. Cette distinction est ce que la plupart des tutoriels POST ne peuvent pas montrer, car ils ne mettent jamais la requête envoyée et la réponse du serveur côte à côte.
json vs data : Le Bug Silencieux de Perte de Données
Envoyer la même charge avec data= au lieu de json= fait que le serveur répond tout de même en 2xx, mais le corps renvoyé n’aura pas vos champs. La requête était correcte ; l’encodage était mauvais.
| Argument | Ce que requests envoie | Ce que le serveur interprète |
|---|---|---|
json={"stars": 3} | corps JSON et Content-Type: application/json | un objet JSON |
data={"stars": 3} | corps form-encodé et application/x-www-form-urlencoded | des champs de formulaire, pas du JSON |
data=json.dumps({"stars": 3}) | une chaîne JSON brute sans en-tête JSON | du texte qu’il pourrait refuser d’interpréter comme JSON |
Règle : passez un dict à json= pour toute API attendant un corps JSON, et utilisez data= seulement lors de l’envoi d’un formulaire HTML. Une API JSON recevant un encodage de formulaire répond généralement en 2xx et supprime silencieusement les données, raison pour laquelle vérifier le code de statut seul ne suffit jamais.
Quand un POST du Navigateur Est Bloqué, Pas Rejeté
Un POST cross-origin se comporte différemment dans le navigateur que dans un script serveur. Comme le corps est application/json, le navigateur envoie un preflight CORS OPTIONS avant le POST. Si l’endpoint ne renvoie pas les en-têtes Access-Control-Allow-Origin et Access-Control-Allow-Headers correspondants, le navigateur bloque le POST avant qu’il parte.
Dans ce cas, requests lève une erreur de connexion comme requests.exceptions.ConnectionError, pas HTTPError, et Run Details marque la requête comme bloquée ou échouée sans code HTTP. Un 403 ou 422 est le signal inverse : la requête a atteint le serveur, qui a choisi de la rejeter.
Règle : aucun code HTTP signifie un problème réseau ou CORS avant le serveur ; un code HTTP signifie que le serveur a répondu, même avec une erreur. jsonplaceholder est CORS-compatible, donc l’exemple envoie proprement. De nombreuses APIs publiques ne le sont pas, raison pour laquelle le même code requests.post peut fonctionner dans un terminal mais échouer dans ce runtime ou tout Python dans le navigateur.
Erreurs Courantes
Erreur : envoyer un dict avec data= quand l’API attend du JSON.
Incorrect :
requests.post(url, data={"stars": 3})
Correct :
requests.post(url, json={"stars": 3})
Pourquoi ça arrive : data= form-encode le dict et définit un Content-Type de formulaire, donc une API JSON ne reçoit pas d’objet JSON et vos champs disparaissent du résultat.
Erreur : sérialiser le corps deux fois.
Incorrect :
requests.post(url, json=json.dumps({"stars": 3}))
Correct :
requests.post(url, json={"stars": 3})
Pourquoi ça arrive : json= sérialise déjà la valeur. Passer une chaîne prête la double-encode en une chaîne JSON plutôt qu’un objet.
Envoyer des En-têtes et l’Auth avec le POST
La plupart des APIs d’écriture requièrent une authentification, qui voyage dans les en-têtes de la requête à côté du corps :
response = requests.post(
url,
json=payload,
headers={"Authorization": "Bearer TOKEN"},
timeout=10,
)
requests fusionne vos en-têtes avec le Content-Type qu’il définit pour json=, donc vous ne fournissez que ce qui est spécifique à l’API. Ne jamais coder en dur un vrai token dans du code partagé ; le lire depuis une variable d’environnement. Un en-tête personnalisé comme Authorization suffit à déclencher le preflight CORS décrit ci-dessus. Pour le côté lecture correspondant, voir lire du JSON depuis une URL, et enveloppez l’appel dans try/except pour gérer les erreurs de connexion.
FAQ
Comment envoyer un POST en Python ?
Appelez requests.post(url, json=payload) avec un dictionnaire comme charge. L’argument json= sérialise le dict, définit l’en-tête Content-Type: application/json et l’envoie en un appel. Lisez la réponse avec response.json().
Pourquoi mon POST renvoie 200 mais le serveur ignore les données ?
Le corps a été envoyé dans le mauvais format, généralement comme champs de formulaire via data= au lieu de JSON via json=. Le serveur répond en 2xx à la requête elle-même mais n’interprète jamais d’objet JSON. Passez à json= et confirmez que le serveur a renvoyé vos champs.
Pourquoi mon POST avec requests est-il bloqué dans le navigateur ?
Un POST JSON cross-origin déclenche un preflight CORS. Si l’endpoint ne renvoie pas Access-Control-Allow-Origin et Access-Control-Allow-Headers, le navigateur bloque la requête avant qu’elle parte ; requests lève alors une erreur de connexion sans code HTTP plutôt qu’un 4xx. Le même code peut fonctionner dans un terminal.
Quelle est la différence entre json et data dans requests.post ?
json= sérialise un dict en corps JSON et définit Content-Type: application/json. data= envoie des champs form-encodés ou une chaîne brute sans l’en-tête JSON. Utilisez json= pour les APIs JSON et data= pour les soumissions de formulaires HTML.