web-dev-qa-db-fra.com

Pourquoi HTTP POST le corps de la demande doit-il être codé JSON en Python?

J'ai rencontré ce problème lorsque je jouais avec une API externe. J'envoyais les données de mon corps sous forme de dictionnaire directement dans la demande et je recevais 400 erreurs:

data = {
  "someParamRange": {
    "to": 1000, 
    "from": 100
  }, 
  "anotherParamRange": {
    "to": True, 
    "from": False
  }
}

Quand j'ai ajouté un wrap json.dumps, ça fonctionne:

data = json.dumps({
  "someParamRange": {
    "to": 1000, 
    "from": 100
  }, 
  "anotherParamRange": {
    "to": True, 
    "from": False
  }
})

Je ne comprends pas tout à fait pourquoi cela est nécessaire, car les dictionnaires et les objets JSON sont syntaxiquement identiques. Quelqu'un peut-il m'aider à comprendre ce qui se passe dans les coulisses?

Pour être complet, voici mes en-têtes:

headers = {'API-KEY': 'blerg', 'Accept-Encoding': 'UTF-8', 'Content-Type': 'application/json', 'Accept': '*/*', 'username': 'user', 'password': 'pwd'}

MODIFIER:

Je n'en ai pas parlé plus tôt, mais maintenant, je pense que cela pourrait être pertinent. J'utilise la bibliothèque de requêtes Python, et un autre post semble suggérer que vous ne devriez jamais coder de paramètres dans un objet de requête: https://stackoverflow.com/a/14804320/1012040

"Indépendamment du fait que GET/POST vous ne devez plus jamais encoder de paramètres, cela prend simplement un dictionnaire comme argument et c'est bon à aller."

On dirait que la sérialisation ne devrait pas être nécessaire?

Mon objet de requête:

response = requests.post(url, data=data, headers=headers)
18
acpigeon

Apparemment, votre API nécessite des données codées JSON et non codées sous forme. Lorsque vous passez dict en tant que paramètre data, les données sont codées sous forme de formulaire. Lorsque vous transmettez une chaîne (comme le résultat de json.dumps), les données ne sont pas codées sous forme.

Considérez cette citation de la documentation des demandes:

En règle générale, vous souhaitez envoyer des données codées par formulaire, un peu comme un formulaire HTML. Pour ce faire, il suffit de passer un dictionnaire à l’argument data. Votre dictionnaire de données sera automatiquement codé sous forme de formulaire lors de la demande.

Il est fréquent que vous souhaitiez envoyer des données qui ne sont pas codées en forme. Si vous transmettez une chaîne au lieu d'un dict, ces données seront directement publiées.

Par exemple, l'API GitHub v3 accepte les données POST/PATCH codées JSON:

>>> import json
>>> url = 'https://api.github.com/some/endpoint'
>>> payload = {'some': 'data'}

>>> r = requests.post(url, data=json.dumps(payload))

Refs: 

32
Robᵩ

Bien qu'ils semblent synticalement identiques, il existe une différence: JSON est une représentation sous forme de chaîne d'un objet sérialisé; dans ce cas, Python dict. Dans cet exemple, vous devez envoyer des données sérialisées sous forme de chaîne. Json.dumps est donc nécessaire pour effectuer la sérialisation.

modifier

Comme suggéré dans les commentaires sur la question, il est relatif à l'API utilisé, mais néanmoins, la sérialisation doit être effectuée quelque part pour envoyer un objet sur le réseau.

1
Piotr Hajduga