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

  1. json= sérialise le dict et définit Content-Type: application/json, de sorte que le serveur reçoit un objet JSON plutôt que des champs de formulaire.
  2. timeout=10 limite l’attente, pour qu’un endpoint inaccessible échoue vite plutôt que de bloquer l’exécution.
  3. raise_for_status() transforme une réponse 4xx ou 5xx en exception, de sorte qu’une réponse échouée ne continue jamais silencieusement.
  4. response.json() retourne la réponse comme un dict Python. Cette API de test renvoie vos champs et ajoute un id attribué par le serveur ; le statut 201 Created confirme 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 DetailsCe qu’il confirme
Un POST sur jsonplaceholder.typicode.com, statut 201L’appel est parti en POST et le serveur a créé une ressource
La colonne méthode affiche POST, pas GETrequests.post a envoyé le verbe souhaité
La durée de la requête en msTemps aller-retour, mesuré séparément du parsing JSON
Statut bloqué ou échoué, sans code HTTPLa requête n’a pas atteint le serveur (voir CORS ci-dessous)
Packages liste requestsweb.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.

ArgumentCe que requests envoieCe que le serveur interprète
json={"stars": 3}corps JSON et Content-Type: application/jsonun objet JSON
data={"stars": 3}corps form-encodé et application/x-www-form-urlencodeddes champs de formulaire, pas du JSON
data=json.dumps({"stars": 3})une chaîne JSON brute sans en-tête JSONdu 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.