Python Requests: Send JSON and Query Parameters
Use Python’s requests library to send structured JSON in an HTTP request body and query parameters in the URL. The json and params arguments handle encoding and URL formatting for you, so you can focus on the data your API expects.
What You’ll Need
- Python installed, plus the
requestspackage. Install it withpython -m pip install requestsif needed; on some systems, usepython3instead ofpython. - The API endpoint and its documentation, including the required HTTP method, parameter names, JSON fields, and any authentication requirements.
- Network access to the endpoint. Avoid putting passwords, API keys, or private data in code you plan to share.
Step-by-Step
- Import requests and define the endpoint. Use the full URL for the API resource. For example:
import requestsurl = "https://api.example.com/items"
The example domain is a placeholder; replace it with a real endpoint from your API documentation. - Prepare query parameters as a dictionary. Query parameters are values sent in the URL after a question mark. The
paramsargument encodes them correctly, including spaces and special characters.params = {"category": "books", "limit": 10}
Requests builds a URL similar to?category=books&limit=10. Do not manually concatenate values into the URL unless you have a specific reason. - Prepare the JSON body as Python data. Use a dictionary, list, or another JSON-compatible structure, with string keys and values such as strings, numbers, booleans, lists, dictionaries, or
None.payload = {"name": "Notebook", "in_stock": True, "tags": ["paper", "office"]}
Python’sTrue,False, andNoneare converted to JSON’strue,false, andnull. - Choose the method the API requires. For an endpoint that creates or updates a resource, documentation may specify
POSTorPUT. Send both kinds of data like this:response = requests.post(url, params=params, json=payload, timeout=20)paramsadds values to the URL;jsonserializes the payload and sends it in the request body. Userequests.put,requests.patch, or another method only when the API calls for it. - Set a timeout and handle network errors. A timeout prevents a request from waiting forever. Catch request exceptions when a script should report failures cleanly:
try:response = requests.post(url, params=params, json=payload, timeout=20)except requests.exceptions.RequestException as exc:print(f"Request failed: {exc}")
A timeout is not a guarantee that the server did not process the request. Before retrying a write operation, check whether the API supports safe retries or idempotency keys. - Check the HTTP status before using the response. A server may return an error status even when the network request succeeded. Use
raise_for_status()to raise an exception for unsuccessful HTTP responses, then parse JSON if the response contains JSON:try:response.raise_for_status()result = response.json()print(result)except requests.exceptions.HTTPError as exc:print(f"API returned an HTTP error: {exc}")except requests.exceptions.JSONDecodeError:print("The response was not valid JSON")
Some successful responses have no body, such as a204 No Contentresponse; do not callresponse.json()in that case. - Inspect what was sent when debugging. Check
response.urlto see the encoded query string, andresponse.status_codeandresponse.textto examine the server’s response. Avoid printing authorization headers or sensitive request data in logs.
Here is the complete pattern in one place:
import requests
url = "https://api.example.com/items"
params = {"category": "books", "limit": 10}
payload = {
"name": "Notebook",
"in_stock": True,
"tags": ["paper", "office"],
}
try:
response = requests.post(
url,
params=params,
json=payload,
timeout=20,
)
response.raise_for_status()
if response.content:
print(response.json())
else:
print("Request succeeded with no response body")
except requests.exceptions.RequestException as exc:
print(f"Request failed: {exc}")
Common Mistakes
- Using
data=instead ofjson=.data=payloadtypically sends form data when given a dictionary. For a JSON request body, pass the Python object usingjson=payload. - Manually serializing JSON unnecessarily. Passing
json=json.dumps(payload)sends a string as the JSON value, often resulting in double encoding. Pass the dictionary directly tojson=. If you must serialize manually, usedata=and set the appropriate content type. - Putting query parameters in the JSON body. Query parameters belong in
params=; JSON fields belong injson=. An API may require different fields or methods, so follow its documentation. - Assuming a response is successful because no exception occurred. Requests does not automatically treat every 4xx or 5xx response as an exception. Call
raise_for_status()or inspect the status code. - Forcing a content type without a reason. The
json=argument sets the JSON content type automatically. A manually added, conflictingContent-Typeheader can confuse the server.
Tips
- Use descriptive parameter names and simple dictionaries; Requests handles URL encoding for values such as spaces and ampersands.
- For repeated query keys, provide a list of pairs, such as
params=[("tag", "blue"), ("tag", "large")]. Confirm that the API accepts repeated keys. - Use headers for API requirements such as authentication or a version identifier. Store secrets outside source code, for example in environment variables, and follow the service’s authentication instructions.
- For multiple requests to the same host, a
requests.Session()can reuse connections. Close a session when finished, for example with awith requests.Session() as session:block. - Keep JSON values compatible with JSON. For dates or custom Python objects, convert them to documented string or numeric formats before sending.
Troubleshooting
If the server rejects the request, first check the status code and read the response body; APIs often explain which field or parameter is missing. Compare the exact HTTP method, endpoint path, parameter spelling, JSON structure, and required headers with the API documentation. Inspect response.url to confirm query parameters were included, but do not share URLs containing secrets.
A 400 response often points to invalid input or a mismatched format; verify required fields and expected types. A 401 or 403 generally means authentication or permissions need attention. A 404 may indicate the wrong endpoint. A 415 can indicate that the server did not receive the content type it expects. These are common clues, not universal rules; use the API’s error details.
If you see a connection error or timeout, check the URL, network connection, DNS, proxy settings, and whether the service is available. Increase the timeout only when a longer response is reasonable. If response.json() fails, inspect response.text: the server may have returned HTML, plain text, or an empty response instead of JSON.
Frequently Asked Questions
Can I send query parameters and JSON in the same request?
Yes. Pass a dictionary to params= and a JSON-compatible Python value to json= in the same call.
Does params= add values to the request body?
No. It adds encoded values to the URL’s query string. Use json= for a JSON request body.
Should I use json= or data=?
Use json= for a JSON body. Use data= when the API expects form-encoded data or when you are deliberately sending a prepared body.
Can a GET request include JSON?
HTTP clients can technically be configured to send a body with a GET request, but servers often ignore or reject it. Follow the API documentation; GET requests normally use query parameters.
How can I send a list as query parameters?
Pass a list as a value, such as {"tag": ["blue", "large"]}, or use repeated key-value pairs. APIs differ in how they expect lists to be encoded, so check their requirements.
Why does response.json() raise an error?
The response may be empty or not valid JSON. Check the status code and response.text, and parse JSON only when the endpoint returns a JSON body.
Related
Method: the standard formula for this calculation, rounded as each result states. See how the calculators work or report an error.