How do I Send PUT requests with JSON Data Using Requests?
Sending PUT requests with JSON data is a common requirement when working with REST APIs that support data updates. The Python Requests library provides several convenient methods to send JSON payloads in PUT requests, making it straightforward to update resources on web servers.
Basic PUT Request with JSON Data
The simplest way to send a PUT request with JSON data using Requests is to use the json
parameter:
import requests
# JSON data to send
data = {
"name": "John Doe",
"email": "john.doe@example.com",
"age": 30
}
# Send PUT request with JSON data
response = requests.put('https://api.example.com/users/123', json=data)
# Check the response
if response.status_code == 200:
print("Update successful!")
print(response.json())
else:
print(f"Request failed with status code: {response.status_code}")
When you use the json
parameter, Requests automatically:
- Sets the Content-Type
header to application/json
- Serializes your Python dictionary or list to JSON format
- Encodes the JSON data as UTF-8
Manual JSON Encoding and Headers
For more control over the request, you can manually encode JSON data and set headers:
import requests
import json
# Prepare JSON data
data = {
"product_name": "Laptop",
"price": 999.99,
"category": "Electronics"
}
# Convert to JSON string
json_data = json.dumps(data)
# Set headers
headers = {
'Content-Type': 'application/json',
'Accept': 'application/json'
}
# Send PUT request
response = requests.put(
'https://api.example.com/products/456',
data=json_data,
headers=headers
)
print(f"Status Code: {response.status_code}")
print(f"Response: {response.text}")
PUT Requests with Authentication
Many APIs require authentication for PUT operations. Here's how to include various authentication methods:
Bearer Token Authentication
import requests
# Your data and authentication token
data = {"status": "active", "permissions": ["read", "write"]}
token = "your_bearer_token_here"
headers = {
'Authorization': f'Bearer {token}',
'Content-Type': 'application/json'
}
response = requests.put(
'https://api.example.com/users/789',
json=data,
headers=headers
)
if response.status_code == 200:
print("User updated successfully")
else:
print(f"Error: {response.status_code} - {response.text}")
Basic Authentication
import requests
from requests.auth import HTTPBasicAuth
data = {"title": "Updated Article", "content": "New content here"}
response = requests.put(
'https://api.example.com/articles/101',
json=data,
auth=HTTPBasicAuth('username', 'password')
)
print(f"Response: {response.status_code}")
Advanced PUT Request Examples
Complex JSON Structure
import requests
# Complex nested JSON data
complex_data = {
"user": {
"personal_info": {
"first_name": "Jane",
"last_name": "Smith",
"address": {
"street": "123 Main St",
"city": "New York",
"zip_code": "10001"
}
},
"preferences": {
"notifications": True,
"theme": "dark",
"languages": ["en", "es"]
}
},
"metadata": {
"updated_by": "admin",
"version": "2.1"
}
}
response = requests.put(
'https://api.example.com/users/profile/456',
json=complex_data,
timeout=30
)
if response.status_code in [200, 204]:
print("Profile updated successfully")
else:
print(f"Update failed: {response.text}")
PUT Request with Query Parameters
import requests
# Data to update
update_data = {
"price": 1299.99,
"stock_quantity": 15
}
# Query parameters
params = {
"version": "v2",
"format": "json",
"notify": "true"
}
response = requests.put(
'https://api.example.com/inventory/items/SKU123',
json=update_data,
params=params
)
print(f"Final URL: {response.url}")
print(f"Status: {response.status_code}")
Error Handling and Response Processing
Proper error handling is crucial when working with PUT requests:
import requests
from requests.exceptions import RequestException, Timeout, ConnectionError
def update_resource(url, data, headers=None, timeout=30):
"""
Send a PUT request with comprehensive error handling
"""
try:
response = requests.put(
url,
json=data,
headers=headers,
timeout=timeout
)
# Raise exception for bad status codes
response.raise_for_status()
# Process successful response
if response.status_code == 200:
return {"success": True, "data": response.json()}
elif response.status_code == 204:
return {"success": True, "message": "Updated successfully (no content)"}
else:
return {"success": True, "status": response.status_code}
except Timeout:
return {"success": False, "error": "Request timed out"}
except ConnectionError:
return {"success": False, "error": "Connection error"}
except requests.exceptions.HTTPError as e:
return {"success": False, "error": f"HTTP error: {e}"}
except RequestException as e:
return {"success": False, "error": f"Request error: {e}"}
# Usage example
update_data = {"name": "Updated Product", "price": 299.99}
result = update_resource(
'https://api.example.com/products/789',
update_data,
headers={'Authorization': 'Bearer your_token'}
)
if result["success"]:
print("Update successful!")
if "data" in result:
print(f"Response data: {result['data']}")
else:
print(f"Update failed: {result['error']}")
Session-Based PUT Requests
For multiple requests, using a session can improve performance and maintain state:
import requests
# Create a session
session = requests.Session()
# Set default headers for all requests in this session
session.headers.update({
'Authorization': 'Bearer your_api_token',
'Content-Type': 'application/json',
'User-Agent': 'MyApp/1.0'
})
# Multiple PUT requests using the same session
products_to_update = [
{"id": 1, "data": {"price": 99.99, "stock": 50}},
{"id": 2, "data": {"price": 149.99, "stock": 25}},
{"id": 3, "data": {"price": 199.99, "stock": 10}}
]
for product in products_to_update:
response = session.put(
f'https://api.example.com/products/{product["id"]}',
json=product["data"]
)
if response.status_code == 200:
print(f"Product {product['id']} updated successfully")
else:
print(f"Failed to update product {product['id']}: {response.status_code}")
# Close the session
session.close()
Content-Type Variations
While JSON is the most common format, you might need to send other content types:
Sending Form Data with PUT
import requests
# Form data instead of JSON
form_data = {
'name': 'Updated Name',
'description': 'Updated description'
}
response = requests.put(
'https://api.example.com/items/123',
data=form_data # Use 'data' instead of 'json'
)
Custom Content-Type
import requests
import json
data = {"key": "value"}
custom_json = json.dumps(data)
headers = {
'Content-Type': 'application/vnd.api+json', # Custom content type
'Accept': 'application/vnd.api+json'
}
response = requests.put(
'https://api.example.com/resources/456',
data=custom_json,
headers=headers
)
Best Practices and Tips
1. Always Validate Response Status
import requests
def safe_put_request(url, data):
response = requests.put(url, json=data)
# Check for successful status codes
if response.status_code in [200, 201, 204]:
return response
else:
raise Exception(f"PUT request failed: {response.status_code} - {response.text}")
2. Use Timeouts
Always set timeouts to prevent hanging requests:
response = requests.put(
'https://api.example.com/data',
json=data,
timeout=(5, 30) # (connection timeout, read timeout)
)
3. Handle Large JSON Payloads
For large datasets, consider streaming:
import requests
import json
def stream_put_request(url, large_data):
def json_generator():
yield json.dumps(large_data).encode('utf-8')
headers = {'Content-Type': 'application/json'}
response = requests.put(
url,
data=json_generator(),
headers=headers
)
return response
Integration with Web Scraping
When building web scraping applications, PUT requests are often used to update scraped data in your backend systems. For complex scenarios involving dynamic content updates, you might also need to handle AJAX requests using Puppeteer for browser-based scraping tasks.
Common HTTP Status Codes for PUT Requests
Understanding the response codes helps in proper error handling:
- 200 OK: The resource was successfully updated
- 201 Created: A new resource was created (if PUT is used for creation)
- 204 No Content: The update was successful, but no content is returned
- 400 Bad Request: The request data is invalid
- 401 Unauthorized: Authentication is required
- 403 Forbidden: The client doesn't have permission
- 404 Not Found: The resource doesn't exist
- 422 Unprocessable Entity: The request is valid but cannot be processed
When scraping websites that require authentication or session management, you might find it useful to understand how to handle browser sessions in Puppeteer for more complex authentication flows.
Conclusion
The Python Requests library makes sending PUT requests with JSON data straightforward and flexible. Whether you're updating user profiles, modifying product information, or synchronizing data between systems, the techniques covered in this guide will help you implement robust PUT request functionality in your applications.
Remember to always include proper error handling, use appropriate timeouts, and validate your JSON data before sending requests. For production applications, consider implementing retry logic and logging to make your code more resilient and maintainable.