diff --git a/lago_python_client/services/response.py b/lago_python_client/services/response.py index a699b5ba..1e6d9720 100644 --- a/lago_python_client/services/response.py +++ b/lago_python_client/services/response.py @@ -54,7 +54,13 @@ def verify_response(response: Response) -> Optional[Response]: headers=response.headers, ) - response_data: Any = from_json(response) # type: ignore + response_data: Any + try: + response_data = from_json(response) # type: ignore + except LagoApiError: + # The error body is not JSON, e.g. an HTML 502 page from a proxy or an + # empty body: keep the raw body and still report the real status code. + response_data = response.text or None raise LagoApiError( status_code=response.status_code, url=str(response.request.url), diff --git a/tests/test_response_services.py b/tests/test_response_services.py index 26e47351..d25ead4b 100644 --- a/tests/test_response_services.py +++ b/tests/test_response_services.py @@ -85,6 +85,43 @@ def test_verify_response(): verify_response(response404) +@pytest.mark.parametrize( + ("status_code", "content"), + [ + (502, b"

502 Bad Gateway

"), + (503, b"upstream connect error"), + (404, b""), + ], +) +def test_verify_response_with_non_json_error_body(status_code, content): + """Keep the real status code and url when an error body is not JSON.""" + # Given an error response whose body is not JSON (e.g. from a proxy) + url = "https://api.getlago.com/api/v1/customers/123" + response = Response(content=content, status_code=status_code, request=Request(method="GET", url=url)) + + # When service is applied + # Then the raised error carries the response status, url and raw body + with pytest.raises(LagoApiError) as exc_info: + verify_response(response) + assert exc_info.value.status_code == status_code + assert exc_info.value.url == url + assert exc_info.value.response == (content.decode() or None) + + +def test_verify_response_with_json_error_body(): + """Keep the decoded body of a JSON error response.""" + # Given an error response with a JSON body + content = b'{"status":422,"error":"Unprocessable Entity","code":"validation_errors"}' + response = Response(content=content, status_code=422, request=Request(method="POST", url="")) + + # When service is applied + # Then the raised error carries the decoded body + with pytest.raises(LagoApiError) as exc_info: + verify_response(response) + assert exc_info.value.status_code == 422 + assert exc_info.value.response == {"status": 422, "error": "Unprocessable Entity", "code": "validation_errors"} + + def test_get_response_data(): """Get response data.""" # Given instanse of ``httpx.Response`` class with successful status code and content