@@ -36,75 +36,89 @@ def __init__(
3636 self .disable_request_logging = config .get ("disable_request_logging" )
3737 self .stream = stream
3838
39+ def __convert_params (self , params : Union [Dict [Any , Any ], List [Dict [Any , Any ]]]) -> Dict [str , str ]:
40+ """
41+ Convert parameters to string values for URL encoding.
42+ """
43+ if params is None :
44+ return {}
45+
46+ if isinstance (params , str ):
47+ return params
48+
49+ if isinstance (params , list ):
50+ return {} # List params are only used in JSON body
51+
52+ converted = {}
53+ for key , value in params .items ():
54+ if isinstance (value , bool ):
55+ converted [key ] = str (value ).lower ()
56+ else :
57+ converted [key ] = str (value )
58+ return converted
59+
3960 async def perform (self ) -> Union [T , None ]:
4061 """
4162 Async method to make an HTTP request to the JigsawStack API.
42-
43- Returns:
44- Union[T, None]: A generic type of the Request class or None
45-
46- Raises:
47- aiohttp.ClientResponseError: If the request fails
4863 """
4964 async with self .__get_session () as session :
5065 resp = await self .make_request (session , url = f"{ self .api_url } { self .path } " )
5166
52- # delete calls do not return a body
53- if await resp .text () == "" and resp .status == 200 :
54- return None
55-
56- # safety net for non-JSON responses
57- content_type = resp .headers .get ("content-type" , "" )
58- if "application/json" not in content_type :
59- raise_for_code_and_type (
60- code = 500 ,
61- message = "Failed to parse JigsawStack API response. Please try again." ,
62- )
67+ # For binary responses
68+ if resp .status == 200 :
69+ content_type = resp .headers .get ("content-type" , "" )
70+ if not resp .text or any (t in content_type for t in ["audio/" , "image/" , "application/octet-stream" , "image/png" ]):
71+ content = await resp .read ()
72+ return cast (T , content )
6373
64- # handle error responses
74+ # For error responses
6575 if resp .status != 200 :
66- error = await resp .json ()
67- raise_for_code_and_type (
68- code = resp .status ,
69- message = error .get ("message" ),
70- err = error .get ("error" ),
71- )
72-
73- return cast (T , await resp .json ())
74-
75- async def perform_file (self ) -> Union [aiohttp .ClientResponse , None ]:
76- """
77- Async method to make an HTTP request and return the raw response.
78-
79- Returns:
80- Union[aiohttp.ClientResponse, None]: The raw response object
81- """
76+ try :
77+ error = await resp .json ()
78+ raise_for_code_and_type (
79+ code = resp .status ,
80+ message = error .get ("message" ),
81+ err = error .get ("error" ),
82+ )
83+ except json .JSONDecodeError :
84+ raise_for_code_and_type (
85+ code = 500 ,
86+ message = "Failed to parse response. Invalid content type or encoding." ,
87+ )
88+
89+ # For JSON responses
90+ try :
91+ return cast (T , await resp .json ())
92+ except json .JSONDecodeError :
93+ content = await resp .read ()
94+ return cast (T , content )
95+
96+ async def perform_file (self ) -> Union [T , None ]:
8297 async with self .__get_session () as session :
8398 resp = await self .make_request (session , url = f"{ self .api_url } { self .path } " )
8499
85- # delete calls do not return a body
86- if await resp .text () == "" and resp .status == 200 :
87- return None
88-
89- # handle error responses
90- if (
91- "application/json" not in resp .headers .get ("content-type" , "" )
92- and resp .status != 200
93- ):
94- raise_for_code_and_type (
95- code = 500 ,
96- message = "Failed to parse JigsawStack API response. Please try again." ,
97- error_type = "InternalServerError" ,
98- )
99-
100100 if resp .status != 200 :
101- error = await resp .json ()
102- raise_for_code_and_type (
103- code = resp .status ,
104- message = error .get ("message" ),
105- err = error .get ("error" ),
106- )
107- return resp
101+ try :
102+ error = await resp .json ()
103+ raise_for_code_and_type (
104+ code = resp .status ,
105+ message = error .get ("message" ),
106+ err = error .get ("error" ),
107+ )
108+ except json .JSONDecodeError :
109+ raise_for_code_and_type (
110+ code = 500 ,
111+ message = "Failed to parse response. Invalid content type or encoding." ,
112+ )
113+
114+ # For binary responses
115+ if resp .status == 200 :
116+ content_type = resp .headers .get ("content-type" , "" )
117+ if "application/json" not in content_type :
118+ content = await resp .read ()
119+ return cast (T , content )
120+
121+ return cast (T , await resp .json ())
108122
109123 async def perform_with_content (self ) -> T :
110124 """
@@ -203,34 +217,36 @@ async def perform_with_content_streaming(
203217 async def make_request (
204218 self , session : aiohttp .ClientSession , url : str
205219 ) -> aiohttp .ClientResponse :
206- """
207- Make the actual async HTTP request.
208-
209- Args:
210- session (aiohttp.ClientSession): The client session
211- url (str): The URL to make the request to
212-
213- Returns:
214- aiohttp.ClientResponse: The response object from the request
215- """
216220 headers = self .__get_headers ()
217- params = self .params
218221 verb = self .verb
219222 data = self .data
220223
221- request_params = None if verb .lower () not in ["get" , "delete" ] else params
224+ # Convert params to string values for URL encoding
225+ converted_params = self .__convert_params (self .params )
222226
223- try :
227+ if verb . lower () in [ "get" , "delete" ] :
224228 return await session .request (
225229 verb ,
226230 url ,
227- params = request_params ,
228- json = params ,
231+ params = converted_params ,
229232 headers = headers ,
230- data = data ,
231233 )
232- except aiohttp .ClientError as e :
233- raise e
234+ else :
235+ if data is not None :
236+ return await session .request (
237+ verb ,
238+ url ,
239+ data = data ,
240+ params = converted_params , # Use converted params
241+ headers = headers ,
242+ )
243+ else :
244+ return await session .request (
245+ verb ,
246+ url ,
247+ json = self .params , # Keep JSON body as original
248+ headers = headers ,
249+ )
234250
235251 def __get_session (self ) -> aiohttp .ClientSession :
236252 """
0 commit comments