Skip to content

Commit 80ca41a

Browse files
Add json_safe method to Response class
This commit adds a new json_safe() method to the Response class that provides graceful error handling for JSON parsing. Unlike the standard json() method, json_safe() returns a default value instead of raising exceptions when: - The response body is empty - The response contains invalid JSON - Unicode decode errors occur The method also supports an optional raise_for_status parameter to validate HTTP status codes before parsing, making it easier to handle API responses that may fail or return malformed data. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
1 parent ee1a3cc commit 80ca41a

1 file changed

Lines changed: 61 additions & 0 deletions

File tree

httpx/_models.py

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -831,6 +831,67 @@ def raise_for_status(self) -> Response:
831831
def json(self, **kwargs: typing.Any) -> typing.Any:
832832
return jsonlib.loads(self.content, **kwargs)
833833

834+
def json_safe(
835+
self,
836+
default: typing.Any = None,
837+
*,
838+
raise_for_status: bool = True,
839+
**kwargs: typing.Any,
840+
) -> typing.Any:
841+
"""
842+
Safely parse JSON response content with error handling.
843+
844+
Unlike the standard `json()` method, this method provides graceful error
845+
handling for common failure cases when parsing JSON responses.
846+
847+
Args:
848+
default: Value to return if JSON parsing fails or response is empty.
849+
Defaults to None.
850+
raise_for_status: If True (default), raises HTTPStatusError for 4xx/5xx
851+
responses before attempting to parse JSON. If False, attempts
852+
to parse JSON regardless of status code.
853+
**kwargs: Additional arguments passed to json.loads()
854+
855+
Returns:
856+
The parsed JSON data, or the default value if parsing fails.
857+
858+
Example:
859+
>>> response = httpx.get("https://api.example.com/data")
860+
>>> data = response.json_safe(default={}) # Returns {} if parsing fails
861+
>>> # Handle rate limiting gracefully
862+
>>> response = httpx.get("https://api.example.com/endpoint")
863+
>>> data = response.json_safe(default={"error": "rate limited"}, raise_for_status=False)
864+
865+
Note:
866+
This method is particularly useful when:
867+
- Dealing with unreliable APIs that may return malformed JSON
868+
- You want a default value instead of raising exceptions
869+
- You need to handle both HTTP errors and JSON parse errors uniformly
870+
"""
871+
# Check status code if requested
872+
if raise_for_status and self.is_error:
873+
request = self._request
874+
if request is None:
875+
raise RuntimeError(
876+
"Cannot call `json_safe` with raise_for_status=True "
877+
"as the request instance has not been set on this response."
878+
)
879+
raise HTTPStatusError(
880+
f"HTTP error {self.status_code} while requesting {request.url}",
881+
request=request,
882+
response=self,
883+
)
884+
885+
# Return default for empty content
886+
if not self.content:
887+
return default
888+
889+
# Try to parse JSON
890+
try:
891+
return jsonlib.loads(self.content, **kwargs)
892+
except (jsonlib.JSONDecodeError, UnicodeDecodeError, ValueError):
893+
return default
894+
834895
@property
835896
def cookies(self) -> Cookies:
836897
if not hasattr(self, "_cookies"):

0 commit comments

Comments
 (0)