From a91013976cab00ee3084dea2c9cc5a65faeedfa8 Mon Sep 17 00:00:00 2001 From: Shubham Padkonde Date: Fri, 2 Oct 2026 11:45:15 +0530 Subject: [PATCH] fix: parse JSON API errors with content type parameters --- appstoreserverlibrary/api_client.py | 3 ++- tests/test_api_client.py | 15 +++++++++++++++ tests/test_api_client_async.py | 15 +++++++++++++++ 3 files changed, 32 insertions(+), 1 deletion(-) diff --git a/appstoreserverlibrary/api_client.py b/appstoreserverlibrary/api_client.py index 072c2b51..60ec8d2c 100644 --- a/appstoreserverlibrary/api_client.py +++ b/appstoreserverlibrary/api_client.py @@ -790,7 +790,8 @@ def _parse_response(self, status_code: int, headers: MutableMapping, json_suppli else: normalized_headers = self._normalize_headers(headers) # Best effort parsing of the response body - if not 'content-type' in headers or headers['content-type'] != 'application/json': + content_type = headers.get('content-type', '').split(';', 1)[0].strip().lower() + if content_type != 'application/json': raise APIException(status_code, headers=normalized_headers) try: response_body = json_supplier() diff --git a/tests/test_api_client.py b/tests/test_api_client.py index 5f6a799a..1a4c2ce5 100644 --- a/tests/test_api_client.py +++ b/tests/test_api_client.py @@ -464,6 +464,21 @@ def test_api_too_many_requests(self): self.assertFalse(True) + def test_api_error_with_content_type_parameters(self): + for content_type in ['application/json; charset=utf-8', 'Application/JSON; charset=UTF-8']: + with self.subTest(content_type=content_type): + client = self.get_client_with_body_from_file( + 'tests/resources/models/apiTooManyRequestsException.json', + 'POST', + 'https://local-testing-base-url/inApps/v1/notifications/test', + {}, None, 429, + response_headers={'Content-Type': content_type, 'Retry-After': '123'}) + with self.assertRaises(APIException) as caught: + client.request_test_notification() + self.assertEqual(APIError.RATE_LIMIT_EXCEEDED, caught.exception.api_error) + self.assertEqual('Rate limit exceeded.', caught.exception.error_message) + self.assertEqual(123, caught.exception.retry_after) + def test_api_too_many_requests_with_retry_after(self): client = self.get_client_with_body_from_file('tests/resources/models/apiTooManyRequestsException.json', 'POST', diff --git a/tests/test_api_client_async.py b/tests/test_api_client_async.py index 2f5a2296..65ffc507 100644 --- a/tests/test_api_client_async.py +++ b/tests/test_api_client_async.py @@ -469,6 +469,21 @@ async def test_api_too_many_requests(self): self.assertFalse(True) + async def test_api_error_with_content_type_parameters(self): + for content_type in ['application/json; charset=utf-8', 'Application/JSON; charset=UTF-8']: + with self.subTest(content_type=content_type): + client = self.get_client_with_body_from_file( + 'tests/resources/models/apiTooManyRequestsException.json', + 'POST', + 'https://local-testing-base-url/inApps/v1/notifications/test', + {}, None, 429, + response_headers={'Content-Type': content_type, 'Retry-After': '123'}) + with self.assertRaises(APIException) as caught: + await client.request_test_notification() + self.assertEqual(APIError.RATE_LIMIT_EXCEEDED, caught.exception.api_error) + self.assertEqual('Rate limit exceeded.', caught.exception.error_message) + self.assertEqual(123, caught.exception.retry_after) + async def test_api_too_many_requests_with_retry_after(self): client = self.get_client_with_body_from_file('tests/resources/models/apiTooManyRequestsException.json', 'POST',