Skip to content

fix(api): move JSONPath modifier to query parameter with improved error handling#3159

Merged
crivetimihai merged 11 commits intomainfrom
issue_2848_no_req_body_tool
Mar 18, 2026
Merged

fix(api): move JSONPath modifier to query parameter with improved error handling#3159
crivetimihai merged 11 commits intomainfrom
issue_2848_no_req_body_tool

Conversation

@crivetimihai
Copy link
Copy Markdown
Member

Note: This PR was re-created from #3023 due to repository maintenance. Your code and branch are intact. @rakdutta please verify everything looks good.

closes #2848
This PR enhances the tools API endpoints (/tools and /tools/{tool_id}) by refactoring JSONPath modifier support from request body to query parameters, improving error handling, and adding comprehensive logging for better debugging.

Changes

API Parameter Changes

  • Moved apijsonpath parameter from request body to optional query parameter in both list_tools and get_tool endpoints
  • Enables JSONPath modifiers to be passed as JSON strings in GET requests, improving API usability
  • Added unified parsing logic to handle apijsonpath as either a string (HTTP requests) or model instance (internal calls/tests)

Response Handling

  • Changed endpoints to return ORJSONResponse when JSONPath modifiers are applied, bypassing FastAPI's response model validation
  • Ensures correct response format and prevents validation errors on modified responses

Error Handling

  • Improved error reporting for invalid JSONPath modifier input with appropriate HTTP exceptions
  • Added detailed error messages for parsing and processing failures

Test Updates

  • Updated unit tests to use new query parameter format for apijsonpath
  • Switched tests to use JsonPathModifier model instances
  • Validated that endpoints return ORJSONResponse objects when modifiers are applied

Documentation

  • Added docstring notes about raised exceptions
  • Clarified parameter descriptions in endpoint documentation

Impact

These changes improve API flexibility by allowing JSONPath modifiers in GET requests, enhance reliability through better error handling, and improve maintainability with comprehensive logging and updated tests.

Testing

All existing unit tests have been updated and pass successfully. The changes maintain backward compatibility for internal calls while adding new query parameter support for HTTP requests.

@crivetimihai crivetimihai added this to the Release 1.0.0-GA milestone Feb 24, 2026
@crivetimihai crivetimihai added bug Something isn't working fixed Issue has been resolved SHOULD P2: Important but not vital; high-value items that are not crucial for the immediate release labels Feb 24, 2026
@rakdutta rakdutta force-pushed the issue_2848_no_req_body_tool branch from 066bdf4 to 2e43d5c Compare February 27, 2026 05:28
@crivetimihai crivetimihai removed the fixed Issue has been resolved label Mar 7, 2026
@rakdutta rakdutta force-pushed the issue_2848_no_req_body_tool branch from dce8465 to 85dabff Compare March 9, 2026 09:39
@TS0713 TS0713 self-requested a review March 9, 2026 11:51
TS0713
TS0713 previously approved these changes Mar 9, 2026
Copy link
Copy Markdown
Collaborator

@TS0713 TS0713 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review: apijsonpath query parameter change

Tested all edge cases for the apijsonpath query parameter change. All tests pass as expected.

Tests executed

# Test Result
1 No apijsonpath — full object returned
2 {"jsonpath":"$[*].name"} — filters names
3 {"jsonpath":"$[*].id"} — filters IDs
4 Mapping {"tool_name":"name","tool_id":"id"} — renames fields
5 {"jsonpath":null} — defaults gracefully
6 {"jsonpath":""} — empty string defaults to $[*]
7 Invalid JSON string — returns 400 with clear message
8 Unknown fields {"unexpected_field":123} — returns 400 Extra inputs are not permitted
9 Invalid JSONPath syntax $$[invalid — returns 400
10 JSONPath matches nothing — returns []
11 Body on GET ignored — full object returned, not filtered ✅ regression confirmed fixed
12 Access to non-existent resource ID — returns 403, consistent with existing access control behaviour across all endpoints ✅ working as designed

Verdict: Approved ✅

@TS0713 TS0713 added the release-fix Critical bugfix required for the release label Mar 9, 2026
@ja8zyjits
Copy link
Copy Markdown
Member

Hi @crivetimihai , we need conflict resolution here.

TS0713
TS0713 previously approved these changes Mar 16, 2026
Copy link
Copy Markdown
Collaborator

@TS0713 TS0713 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tested the updated implementation for /tools and /tools/{tool_id} endpoints. All scenarios behave as expected.

Tests executed

# Test Result
1 No apijsonpath — full object returned
2 {"jsonpath":"$[*].name"} — filters tool names
3 {"jsonpath":"$[*].id"} — filters tool IDs
4 Mapping {"tool_name":"name","tool_id":"id"} — renames fields correctly
5 {"jsonpath":null} — defaults gracefully
6 {"jsonpath":""} — empty string defaults to $[*]
7 Invalid JSON string — returns 400 Bad Request
8 Unknown fields {"unexpected_field":123} — returns 400
9 Invalid JSONPath syntax — returns 400
10 JSONPath matches nothing — returns []
11 Body on GET ignored — full object returned (regression fixed)
12 Access to non-existent resource ID — returns 403
13 Pagination works with JSONPath (include_pagination=true)

Pagination verification

Verified pagination works correctly when JSONPath is used.

curl -G "$BASE/tools" \
  -H "Authorization: Bearer $MY_BEARER" \
  --data-urlencode "include_pagination=true" \
  --data-urlencode 'apijsonpath={"jsonpath":"$[*].name"}'

Approved!

@rakdutta rakdutta added the ica ICA related issues label Mar 16, 2026
@rakdutta rakdutta force-pushed the issue_2848_no_req_body_tool branch from e859a84 to c0ae6e2 Compare March 17, 2026 04:23
@crivetimihai crivetimihai self-assigned this Mar 18, 2026
…points

- Move apijsonpath parameter from request body to query string for list_tools and get_tool endpoints
- Add _parse_apijsonpath() helper to handle both JSON string and JsonPathModifier inputs
- Return ORJSONResponse to bypass FastAPI response_model validation when using JSONPath modifiers
- Add comprehensive error handling with proper HTTPException status codes
- Add test coverage for Query parameter handling and error cases

This change resolves issue #2848 by making GET requests RESTful-compliant (no request body).

Signed-off-by: Rakhi Dutta <rakhibiswas@yahoo.com>
…re in apijsonpath parsing

Address code review feedback with three security and performance improvements:

1. Specific Exception Handling (Issue #1)
   - Catch specific exceptions (json.JSONDecodeError, ValueError, ValidationError)
   - Separate user errors (400) from system errors (500)
   - Log unexpected errors with full context for debugging

2. Sanitize Exception Messages (Issue #2)
   - Return generic error messages in production (non-DEBUG mode)
   - Prevent information disclosure about internal types and stack traces
   - Detailed messages only shown when LOG_LEVEL=DEBUG for troubleshooting

3. Optimize Debug Logging (Issue #3)
   - Check if debug logging is enabled before building log message
   - Avoid string formatting overhead in production
   - Improves performance in high-traffic scenarios

Updated test assertions to verify generic error messages (security improvement).
All tests pass (18 jsonpath tests verified).

Signed-off-by: Rakhi Dutta <rakhibiswas@yahoo.com>
Signed-off-by: Rakhi Dutta <rakhibiswas@yahoo.com>
Signed-off-by: Rakhi Dutta <rakhibiswas@yahoo.com>
Signed-off-by: Rakhi Dutta <rakhibiswas@yahoo.com>
rakdutta and others added 6 commits March 18, 2026 10:59
Signed-off-by: Rakhi Dutta <rakhibiswas@yahoo.com>
Signed-off-by: Rakhi Dutta <rakhibiswas@yahoo.com>
Signed-off-by: Rakhi Dutta <rakhibiswas@yahoo.com>
Signed-off-by: Rakhi Dutta <rakhibiswas@yahoo.com>
- Move _parse_apijsonpath() call before the database query in list_tools
  to fail fast on invalid input without wasting a DB round-trip
- Add tests for the ValidationError path (extra fields rejected by
  extra="forbid" on JsonPathModifier)
- Run black/isort on test file

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>
… e2e tests

- Fix pagination+JSONPath response to use "nextCursor" (camelCase) matching
  the CursorPaginatedToolsResponse alias contract. The hand-built dict
  bypassed Pydantic aliasing via ORJSONResponse, emitting "next_cursor"
  which broke any client relying on the documented field name.
  Confirmed regression against live server at localhost:8080.

- Sanitize user-supplied JSONPath expression in debug log via
  SecurityValidator.sanitize_log_message() to prevent CWE-117 log
  forging (newlines, ANSI escapes in crafted jsonpath values).

- Add end-to-end HTTP tests (TestApijsonpathHTTP) exercising the
  apijsonpath query parameter through FastAPI TestClient, covering
  the full HTTP binding path that __wrapped__() unit tests skip.

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>
@crivetimihai crivetimihai force-pushed the issue_2848_no_req_body_tool branch from 34f3b08 to 1ba2c5b Compare March 18, 2026 12:16
@crivetimihai
Copy link
Copy Markdown
Member Author

Review Complete — Ready to merge

Rebased onto current main (db620e9), no conflicts. Thorough code review + live testing performed.

Changes made during review (2 commits)

0260232a9 — validate apijsonpath before DB query + test coverage

  • Moved _parse_apijsonpath() before the database query in list_tools — fail fast on invalid input without wasting a DB round-trip
  • Added 2 tests for the ValidationError path (extra="forbid" rejecting unknown fields) which had zero coverage

1ba2c5b0e — correct nextCursor wire key, sanitize debug log, add e2e tests

  • Bug fix: Paginated JSONPath response emitted next_cursor (snake_case) instead of nextCursor (camelCase) because the hand-built dict bypassed Pydantic aliasing via ORJSONResponse. Confirmed live: normal pagination returned nextCursor, but JSONPath+pagination returned next_cursor. Fixed.
  • Security fix (CWE-117): Debug log in jsonpath_modifier() recorded raw user-supplied JSONPath without sanitization. Wrapped with SecurityValidator.sanitize_log_message() to prevent log forging.
  • Test gap: All existing tests used __wrapped__(), bypassing FastAPI's HTTP query string parsing. Added 3 end-to-end TestClient tests covering the actual wire path.

Verification

Area Result
Unit tests 539 passed (536 original + 3 new)
curl API tests 15/15 passed (baseline, pagination, JSONPath, JSONPath+pagination, mappings, single tool, 7 error cases, auth, body-on-GET)
Regression endpoints /health, /resources, /prompts, /servers, /gateways — all 200
Playwright UI Login, dashboard, Tools (list + View + Test invocation), Prompts, Resources — all render, zero new console errors
Gateway logs No errors from test window
Pagination wire key Confirmed fixed live at localhost:8080nextCursor in both normal and JSONPath+pagination paths

@crivetimihai crivetimihai merged commit 3c5375e into main Mar 18, 2026
39 checks passed
@crivetimihai crivetimihai deleted the issue_2848_no_req_body_tool branch March 18, 2026 12:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working ica ICA related issues release-fix Critical bugfix required for the release SHOULD P2: Important but not vital; high-value items that are not crucial for the immediate release

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[BUG][API]: GET /tools should not require a request body

4 participants