Creating or updating resources through an API means sending a body in the format the server expects.
Requests offers three ways to send a body, and each sets the right Content-Type for you:
json=objserialises a dict or list to JSON and setsContent-Type: application/json. This is what most modern REST APIs expect.data=dictsends an HTML-form body,application/x-www-form-urlencoded, the way a browser submits a simple form.data=str_or_bytessends the content as-is with noContent-Typeadded. Use it for XML, plain text or a pre-serialised payload, and set the header yourself.files={"field": file_obj}sendsmultipart/form-data, used for uploads (covered in a later lesson).
The methods are the usual HTTP verbs: post to create, put to replace, patch to update partially, delete to remove. They all accept the same keyword arguments as get.
Two classic mistakes:
- Using
data=when the API wants JSON.data={"a": 1}sendsa=1as a form, and a JSON API will reply with400or415. Usejson=. - Passing both
json=anddata=: whendatais given,jsonis ignored.
The response to a create call is often 201 Created with the new resource in the body and its URL in the Location header. Some APIs reply 204 No Content, where r.json() would fail because the body is empty.
Example
import requests
base = "https://httpbin.org"
r = requests.post(f"{base}/post", json={"name": "Ada", "tags": ["math"]}, timeout=10)
echo = r.json()
print(echo["headers"]["Content-Type"]) # application/json
print(echo["json"]) # {'name': 'Ada', 'tags': ['math']}
r = requests.post(f"{base}/post", data={"name": "Ada", "lang": "en"}, timeout=10)
echo = r.json()
print(echo["headers"]["Content-Type"]) # application/x-www-form-urlencoded
print(echo["form"]) # {'lang': 'en', 'name': 'Ada'}
xml = "<user><name>Ada</name></user>"
r = requests.put(f"{base}/put", data=xml,
headers={"Content-Type": "application/xml"}, timeout=10)
print(r.json()["data"]) # <user><name>Ada</name></user>
print(requests.delete(f"{base}/delete", timeout=10).status_code) # 200Remember
- json= for JSON APIs, data= for forms or raw bodies, files= for uploads
- Each sets Content-Type, except raw data= strings and bytes
- post, put, patch and delete take the same arguments as get
Watch out for
- Sending data={'a': 1} to a JSON API and getting a 400 or 415 back.