Skip to content

Conversation

@zeljkoX
Copy link
Collaborator

@zeljkoX zeljkoX commented Jan 12, 2026

Summary

This PR will fix recently merged change that causes sdk callPlugin breaking change by removing route param from api docs.

SDK PR: OpenZeppelin/openzeppelin-relayer-sdk#240

Testing Process

Checklist

  • Add a reference to related issues in the PR description.
  • Add unit tests if applicable.

Note

If you are using Relayer in your stack, consider adding your team or organization to our list of Relayer Users in the Wild!

Summary by CodeRabbit

Release Notes

  • New Features

    • Added forward_logs configuration field to control plugin log output
    • Plugin endpoints now support custom routes via query parameters as an alternative to URL path routing
  • Changes

    • Route parameters for plugin endpoints are now optional, providing more flexible API usage options

✏️ Tip: You can customize this high-level summary in your review settings.

@zeljkoX zeljkoX requested a review from a team as a code owner January 12, 2026 13:00
@coderabbitai
Copy link

coderabbitai bot commented Jan 12, 2026

Walkthrough

The PR refactors plugin route handling by migrating the route parameter from the URL path to a query parameter while maintaining backwards compatibility. It also adds a new forward_logs field to the PluginModel schema for controlling log forwarding behavior.

Changes

Cohort / File(s) Summary
OpenAPI Schema Updates
openapi.json
Updated GET/POST plugin call endpoints: removed {route} path parameter, added optional route query parameter. Added new forward_logs boolean field to PluginModel schema to control plugin log forwarding into relayer tracing.
Route Documentation
src/api/routes/docs/plugin_docs.rs
Updated utoipa macro attributes for doc_call_plugin and doc_call_plugin_get functions: changed route from Path parameter to optional Query parameter with descriptions explaining routing via query parameter or URL path appending.
Route Resolution Implementation
src/api/routes/plugin.rs
Added resolve_route() helper function to select route from path segment or query parameter (path takes precedence). Updated POST/GET handlers to use resolver. Extended tests to validate route extraction from both path and query sources with precedence rules.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Suggested reviewers

  • collins-w

Poem

🐰 Hops along the query trail,
Routes no longer path-defined and frail,
Query parameters now take the stage,
While logs forward to trace's new page!
Backwards compatible, hopping with grace,

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 inconclusive)
Check name Status Explanation Resolution
Description check ❓ Inconclusive The description includes a summary explaining the purpose and references a related SDK PR, but the Testing Process section is empty and the checklist items remain incomplete. Complete the Testing Process section detailing how the changes were tested, and ensure checklist items are addressed or explicitly marked as not applicable.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately describes the main change: fixing an SDK breaking change related to the plugin calling method by adjusting API documentation and routing parameters.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch plugin-routing-fix

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
openapi.json (1)

927-1073: Clarify “route via URL path” vs what the OpenAPI actually defines (and improve route query-param ergonomics).

Right now the descriptions advertise /api/v1/plugins/{plugin_id}/call/verify, but this spec only defines /api/v1/plugins/{plugin_id}/call. If the path-suffix routing is intentionally supported-but-undocumented to prevent SDK churn, I’d explicitly say so (or remove the /call/verify example entirely). Also consider setting allowReserved: true and adding an example, since route values commonly include /.

Proposed diff
     "/api/v1/plugins/{plugin_id}/call": {
       "get": {
@@
-        "description": "This endpoint is disabled by default. To enable it for a given plugin, set\n`allow_get_invocation: true` in the plugin configuration.\n\nWhen invoked via GET:\n- `params` is an empty object (`{}`)\n- query parameters are passed to the plugin handler via `context.query`\n- wildcard route routing is supported the same way as POST (see `doc_call_plugin`)\n- Use the `route` query parameter or append the route to the URL path",
+        "description": "This endpoint is disabled by default. To enable it for a given plugin, set\n`allow_get_invocation: true` in the plugin configuration.\n\nWhen invoked via GET:\n- `params` is an empty object (`{}`)\n- query parameters are passed to the plugin handler via `context.query`\n- wildcard route routing is supported the same way as POST (see `doc_call_plugin`)\n- Use the `route` query parameter for custom routing (recommended; this OpenAPI spec documents query-based routing only).",
@@
           {
             "name": "route",
             "in": "query",
             "description": "Optional route suffix for custom routing (e.g., '/verify'). Alternative to appending the route to the URL path.",
             "required": false,
+            "allowReserved": true,
             "schema": {
-              "type": "string"
+              "type": "string",
+              "example": "/verify"
             }
           }
         ],
@@
       "post": {
@@
-        "description": "Logs and traces are only returned when the plugin is configured with `emit_logs` / `emit_traces`.\nPlugin-provided errors are normalized into a consistent payload (`code`, `details`) and a derived\nmessage so downstream clients receive a stable shape regardless of how the handler threw.\n\nThe endpoint supports wildcard route routing, allowing plugins to implement custom routing logic:\n- `/api/v1/plugins/{plugin_id}/call` - Default endpoint (route = \"\")\n- `/api/v1/plugins/{plugin_id}/call?route=/verify` - Custom route via query parameter\n- `/api/v1/plugins/{plugin_id}/call/verify` - Custom route via URL path (route = \"/verify\")\n\nThe route is passed to the plugin handler via the `context.route` field.\nYou can specify a custom route either by appending it to the URL path or by using the `route` query parameter.",
+        "description": "Logs and traces are only returned when the plugin is configured with `emit_logs` / `emit_traces`.\nPlugin-provided errors are normalized into a consistent payload (`code`, `details`) and a derived\nmessage so downstream clients receive a stable shape regardless of how the handler threw.\n\nThe endpoint supports wildcard route routing, allowing plugins to implement custom routing logic:\n- `/api/v1/plugins/{plugin_id}/call` - Default endpoint (route = \"\")\n- `/api/v1/plugins/{plugin_id}/call?route=/verify` - Custom route via query parameter\n\nThe route is passed to the plugin handler via the `context.route` field.",
@@
           {
             "name": "route",
             "in": "query",
             "description": "Optional route suffix for custom routing (e.g., '/verify'). Alternative to appending the route to the URL path.",
             "required": false,
+            "allowReserved": true,
             "schema": {
-              "type": "string"
+              "type": "string",
+              "example": "/verify"
             }
           }
         ],
🧹 Nitpick comments (2)
src/api/routes/plugin.rs (1)

60-74: Logic is correct; consider filtering route from forwarded query params.

The precedence logic (path route > query param) is sound. However, when route is specified via query parameter, it will also appear in the query field passed to plugins (since extract_query_params is called separately in the handlers). This could be redundant or confusing for plugin authors.

Consider filtering out the route key from the query params before passing to plugins, or document this behavior as intentional.

openapi.json (1)

4500-4503: forward_logs: document default / presence in responses (and consider sensitivity note).

forward_logs is added as a boolean, but the schema doesn’t indicate whether it’s always present and what the default is. If it’s defaulted server-side, adding a default (and optionally an explicit “may contain sensitive data; don’t log secrets” note) makes the contract clearer.

Proposed diff
                     "forward_logs": {
                       "type": "boolean",
-                      "description": "Whether to forward plugin logs into the relayer's tracing output"
+                      "description": "Whether to forward plugin logs into the relayer's tracing output",
+                      "default": false
                     },
           "forward_logs": {
             "type": "boolean",
-            "description": "Whether to forward plugin logs into the relayer's tracing output"
+            "description": "Whether to forward plugin logs into the relayer's tracing output",
+            "default": false
           },

Please confirm whether forward_logs is always returned in PluginModel responses; if yes, consider adding it to the relevant required lists to match runtime behavior.

Also applies to: 6991-6994

📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 7ad8bee and 0e235cb.

📒 Files selected for processing (3)
  • openapi.json
  • src/api/routes/docs/plugin_docs.rs
  • src/api/routes/plugin.rs
🧰 Additional context used
📓 Path-based instructions (1)
**/*.rs

📄 CodeRabbit inference engine (.cursor/rules/rust_standards.mdc)

**/*.rs: Follow official Rust style guidelines using rustfmt (edition = 2021, max_width = 100)
Follow Rust naming conventions: snake_case for functions/variables, PascalCase for types, SCREAMING_SNAKE_CASE for constants and statics
Order imports alphabetically and group by: std, external crates, local crates
Include relevant doc comments (///) on public functions, structs, and modules. Use comments for 'why', not 'what'. Avoid redundant doc comments
Document lifetime parameters when they're not obvious
Avoid unsafe code unless absolutely necessary; justify its use in comments
Write idiomatic Rust: Prefer Result over panic, use ? operator for error propagation
Avoid unwrap; handle errors explicitly with Result and custom Error types for all async operations
Prefer header imports over function-level imports of dependencies
Prefer borrowing over cloning when possible
Use &str instead of &String for function parameters
Use &[T] instead of &Vec for function parameters
Avoid unnecessary .clone() calls
Use Vec::with_capacity() when size is known in advance
Use explicit lifetimes only when necessary; infer where possible
Always use Tokio runtime for async code. Await futures eagerly; avoid blocking calls in async contexts
Streams: Use futures::StreamExt for processing streams efficiently
Always use serde for JSON serialization/deserialization with #[derive(Serialize, Deserialize)]
Use type aliases for complex types to improve readability
Implement common traits (Debug, Clone, PartialEq) where appropriate, using derive macros when possible
Implement Display for user-facing types
Prefer defining traits when implementing services to make mocking and testing easier
For tests, prefer existing utils for creating mocks instead of duplicating code
Use assert_eq! and assert! macros appropriately
Keep tests minimal, deterministic, and fast
Use tracing for structured logging, e.g., tracing::info! for request and error logs
When optimizing, prefer clarity first, then performance
M...

Files:

  • src/api/routes/plugin.rs
  • src/api/routes/docs/plugin_docs.rs
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (10)
  • GitHub Check: boostsecurity - boostsecurityio/semgrep-pro
  • GitHub Check: Unit Tests
  • GitHub Check: clippy
  • GitHub Check: Properties Tests
  • GitHub Check: msrv
  • GitHub Check: Redirect rules - openzeppelin-relayer
  • GitHub Check: Header rules - openzeppelin-relayer
  • GitHub Check: Pages changed - openzeppelin-relayer
  • GitHub Check: Analyze (rust)
  • GitHub Check: semgrep/ci
🔇 Additional comments (6)
src/api/routes/plugin.rs (4)

129-130: LGTM!

The handler correctly uses resolve_route to determine the effective route from path or query parameter.


150-151: LGTM!

Consistent with the POST handler implementation.


225-227: LGTM!

Test helpers correctly updated to mirror the production route resolution logic.


931-993: Good test coverage for route resolution.

These tests effectively validate:

  1. Route extraction from query parameter when path route is empty
  2. Path route takes precedence over query parameter

This covers the key behaviors of the new resolve_route function.

src/api/routes/docs/plugin_docs.rs (2)

14-31: Documentation accurately reflects the new routing behavior.

The documentation clearly explains both methods:

  1. Query parameter: ?route=/verify
  2. URL path suffix: /call/verify

The path change from wildcard to base path with optional query param is cleaner for OpenAPI consumers while maintaining full backwards compatibility in the implementation.


132-144: LGTM!

GET endpoint documentation is consistent with the POST endpoint, correctly documenting both routing methods.

@codecov
Copy link

codecov bot commented Jan 12, 2026

Codecov Report

❌ Patch coverage is 0% with 16 lines in your changes missing coverage. Please review.
✅ Project coverage is 91.30%. Comparing base (7ad8bee) to head (0e235cb).

Files with missing lines Patch % Lines
src/api/routes/plugin.rs 0.00% 16 Missing ⚠️
Additional details and impacted files
Flag Coverage Δ
properties 0.02% <0.00%> (-0.01%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

@@            Coverage Diff             @@
##             main     #607      +/-   ##
==========================================
- Coverage   91.31%   91.30%   -0.02%     
==========================================
  Files         257      257              
  Lines       91015    91028      +13     
==========================================
- Hits        83111    83110       -1     
- Misses       7904     7918      +14     
Files with missing lines Coverage Δ
src/api/routes/plugin.rs 25.51% <0.00%> (-3.28%) ⬇️
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Copy link
Contributor

@tirumerla tirumerla left a comment

Choose a reason for hiding this comment

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

Thanks for the fix

@zeljkoX zeljkoX merged commit 82117e1 into main Jan 13, 2026
25 of 27 checks passed
@zeljkoX zeljkoX deleted the plugin-routing-fix branch January 13, 2026 09:43
@github-actions github-actions bot locked and limited conversation to collaborators Jan 13, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants