@@ -2223,7 +2223,8 @@ async def test_invoke_tool_rest_post_with_path_query_and_body_params(self, tool_
22232223 - Path parameters (e.g., {user_id}) are substituted into the URL path
22242224 - Query parameters can also use templates (e.g., ?api_key={api_key})
22252225 - Static query parameters (e.g., ?version=v2) are preserved as-is
2226- - Remaining payload goes to the JSON body
2226+ - Query parameters are merged into the JSON body for POST requests
2227+ - Remaining payload goes to the JSON body alongside merged query params
22272228 """
22282229 mock_tool .integration_type = "REST"
22292230 mock_tool .request_type = "POST"
@@ -2234,10 +2235,10 @@ async def test_invoke_tool_rest_post_with_path_query_and_body_params(self, tool_
22342235
22352236 # Payload contains: path param (user_id), query param (api_key), and body params (title, content)
22362237 payload = {
2237- "user_id" : 456 , # Will be substituted into URL path
2238- "api_key" : "secret123" , # Will be substituted into query parameter
2239- "title" : "New Post" , # Will go to JSON body
2240- "content" : "Hello World" # Will go to JSON body
2238+ "user_id" : 456 , # Will be substituted into URL path
2239+ "api_key" : "secret123" , # Template in query string portion of URL; substituted then extracted as query param
2240+ "title" : "New Post" , # Will go to JSON body
2241+ "content" : "Hello World" , # Will go to JSON body
22412242 }
22422243
22432244 setup_db_execute_mock (test_db , mock_tool , mock_global_config_obj )
@@ -2251,16 +2252,83 @@ async def test_invoke_tool_rest_post_with_path_query_and_body_params(self, tool_
22512252
22522253 await tool_service .invoke_tool (test_db , "test_tool" , payload , request_headers = None )
22532254
2254- # Verify the complete parameter separation :
2255+ # Verify parameter handling for POST :
22552256 # 1. Path parameter substituted: /users/456/posts
22562257 # 2. Query param template substituted: api_key=secret123
22572258 # 3. Static query param preserved: version=v2
2258- # 4. Body params: title and content (user_id and api_key removed after substitution)
2259+ # 4. Query params merged into JSON body (backward-compatible behavior for POST)
2260+ # 5. Body params: title and content (user_id and api_key removed after path/query substitution)
22592261 tool_service ._http_client .request .assert_called_once_with (
22602262 "POST" ,
2261- "http://example.com/api/users/456/posts" , # Path param substituted, query string removed
2262- json = {"title" : "New Post" , "content" : "Hello World" }, # Body params only
2263- params = {"api_key" : "secret123" , "version" : "v2" }, # Query params (both templated and static)
2263+ "http://example.com/api/users/456/posts" , # Path param substituted, query string stripped
2264+ json = {"title" : "New Post" , "content" : "Hello World" , "api_key" : "secret123" , "version" : "v2" }, # Body + merged query params
2265+ headers = mock_tool .headers ,
2266+ )
2267+
2268+ @pytest .mark .asyncio
2269+ async def test_invoke_tool_rest_get_with_static_query_params_no_mapping (self , tool_service , mock_tool , mock_global_config_obj , test_db ):
2270+ """Test GET request with static URL query params and no query_mapping.
2271+
2272+ Verifies that query params extracted from the URL are merged into the
2273+ payload and sent together via params= on the GET request.
2274+ """
2275+ mock_tool .integration_type = "REST"
2276+ mock_tool .request_type = "GET"
2277+ mock_tool .jsonpath_filter = ""
2278+ mock_tool .auth_value = None
2279+ mock_tool .url = "http://example.com/api/search?version=v2&format=json"
2280+
2281+ payload = {"q" : "hello" }
2282+
2283+ setup_db_execute_mock (test_db , mock_tool , mock_global_config_obj )
2284+
2285+ mock_response = Mock ()
2286+ mock_response .raise_for_status = Mock ()
2287+ mock_response .status_code = 200
2288+ mock_response .json = Mock (return_value = {"results" : []})
2289+
2290+ tool_service ._http_client .get = AsyncMock (return_value = mock_response )
2291+
2292+ await tool_service .invoke_tool (test_db , "test_tool" , payload , request_headers = None )
2293+
2294+ # URL query params (version, format) are merged into payload alongside the user-provided "q"
2295+ tool_service ._http_client .get .assert_called_once_with (
2296+ "http://example.com/api/search" ,
2297+ params = {"q" : "hello" , "version" : "v2" , "format" : "json" },
2298+ headers = mock_tool .headers ,
2299+ )
2300+
2301+ @pytest .mark .asyncio
2302+ async def test_invoke_tool_rest_put_with_query_params (self , tool_service , mock_tool , mock_global_config_obj , test_db ):
2303+ """Test PUT request with URL query params merges them into the JSON body.
2304+
2305+ Verifies that non-GET methods other than POST (e.g. PUT) also merge
2306+ URL query params into the JSON body for backward compatibility.
2307+ """
2308+ mock_tool .integration_type = "REST"
2309+ mock_tool .request_type = "PUT"
2310+ mock_tool .jsonpath_filter = ""
2311+ mock_tool .auth_value = None
2312+ mock_tool .url = "http://example.com/api/items/1?version=v2"
2313+
2314+ payload = {"name" : "updated" }
2315+
2316+ setup_db_execute_mock (test_db , mock_tool , mock_global_config_obj )
2317+
2318+ mock_response = Mock ()
2319+ mock_response .raise_for_status = Mock ()
2320+ mock_response .status_code = 200
2321+ mock_response .json = Mock (return_value = {"status" : "ok" })
2322+
2323+ tool_service ._http_client .request = AsyncMock (return_value = mock_response )
2324+
2325+ await tool_service .invoke_tool (test_db , "test_tool" , payload , request_headers = None )
2326+
2327+ # Query params merged into JSON body, same as POST
2328+ tool_service ._http_client .request .assert_called_once_with (
2329+ "PUT" ,
2330+ "http://example.com/api/items/1" ,
2331+ json = {"name" : "updated" , "version" : "v2" },
22642332 headers = mock_tool .headers ,
22652333 )
22662334
0 commit comments