57.1 requests.get, post, put, delete: The Basics
The requests library provides a set of straightforward and intuitive methods for making HTTP requests, mirroring the verbs of the HTTP protocol itself. The get(), post(), put(), and delete() functions are the primary entry points for interacting with web services. Each function returns a Response object, which contains all the information returned by the server, from the status code and headers to the actual body of the response.
The GET Request
The requests.get() function is used to retrieve information from a given server using a URI (Uniform Resource Identifier). By definition, a GET request should only retrieve data and should have no other effect on the data. The optional params keyword argument allows you to send a dictionary or bytes to be encoded into the query string of the URL, which is the proper way to pass data for a GET request.
import requests
# Basic GET request
response = requests.get('https://api.github.com/events')
# GET request with query parameters
params = {'q': 'requests+language:python', 'sort': 'stars'}
response = requests.get('https://api.github.com/search/repositories', params=params)
print(f"Status Code: {response.status_code}")
print(f"URL sent to server: {response.url}") # Shows the final URL with encoded params
print(f"First 100 characters of response: {response.text[:100]}...")
The POST Request
The requests.post() function is used to send data to a server to create a new resource. The data is sent in the body of the request, not in the URL. The most common way to send data is as form-encoded data using the data keyword argument, or as JSON using the json keyword argument. Using json is highly recommended when interacting with RESTful APIs as it automatically sets the Content-Type header to application/json.
import requests
# POST with form data
form_data = {'username': 'john_doe', 'password': 'secret'}
response_form = requests.post('https://httpbin.org/post', data=form_data)
# POST with JSON data (the modern, preferred way for APIs)
json_data = {'name': 'New Project', 'description': 'A fantastic new endeavor.'}
response_json = requests.post('https://api.example.com/projects', json=json_data)
print("Form POST Response JSON:")
print(response_form.json())
print("\nJSON POST Response Status Code:")
print(response_json.status_code)
The PUT Request
The requests.put() function is used to send data to a server to update an existing resource. It is intended to be idempotent, meaning that making the same request multiple times will produce the same result as making it once. It typically replaces the entire resource at the target URI with the new data provided. Like post(), it uses the data or json arguments.
# Update a user's entire profile
updated_user_data = {
'name': 'Jane Smith',
'email': 'jane.smith@example.com',
'title': 'Senior Developer'
}
response = requests.put('https://api.example.com/users/123', json=updated_user_data)
if response.status_code == 200:
print("User updated successfully.")
else:
print(f"Update failed with status {response.status_code}: {response.text}")
The DELETE Request
The requests.delete() function is used to delete a resource identified by a specific URI. A successful deletion is often indicated by a 200 OK or 204 No Content status code.
# Delete a specific item
response = requests.delete('https://api.example.com/items/456')
if response.status_code == 204:
print("Item deleted successfully.")
else:
print(f"Deletion failed. Status code: {response.status_code}")
Common Pitfalls and Best Practices
A common pitfall is not checking the response status code before attempting to process the response body. A request can be successfully sent and a response received, but that response might be an error (e.g., 404 Not Found, 500 Internal Server Error). Always check response.status_code or use response.raise_for_status(), which will raise an exception for 4xx or 5xx status codes.
response = requests.get('https://api.example.com/missing-resource')
try:
response.raise_for_status() # Will raise an HTTPError for bad status codes
data = response.json() # Only parse JSON if the request was successful
except requests.exceptions.HTTPError as err:
print(f"HTTP error occurred: {err}")
except requests.exceptions.RequestException as err:
print(f"An error occurred: {err}")
Another critical best practice is to always use a timeout parameter. Without it, your request could hang indefinitely, causing your application to stall. The timeout parameter defines the maximum time to wait for both connection establishment and reading data.
# Timeout if the connection isn't established in 3 seconds
# and if the server doesn't send a byte of data for 5 seconds after connection.
try:
response = requests.get('https://api.example.com/slow', timeout=(3, 5))
except requests.exceptions.Timeout:
print("The request timed out. Please try again later.")
Furthermore, when making authenticated requests, use sessions (requests.Session()) to persist cookies and connection pooling across multiple requests, which significantly improves performance. Avoid putting sensitive information like API keys directly in the URL; instead, use the auth parameter or a custom header.
# Using a session for multiple requests and authentication
with requests.Session() as session:
session.auth = ('username', 'password')
session.headers.update({'X-API-Key': 'your-secret-key'})
# All requests made with this session will use the same auth and headers
first_response = session.get('https://api.example.com/user')
second_response = session.post('https://api.example.com/data', json={'data': 'value'})