Skip to content

feat: add custom query parameter rules for proxy requests#409

Open
maodeyu180 wants to merge 2 commits intotbphp:mainfrom
maodeyu180:main
Open

feat: add custom query parameter rules for proxy requests#409
maodeyu180 wants to merge 2 commits intotbphp:mainfrom
maodeyu180:main

Conversation

@maodeyu180
Copy link
Copy Markdown

@maodeyu180 maodeyu180 commented Apr 9, 2026

Allow per-group URL query parameter manipulation (set/remove) before forwarding to upstream, mirroring the existing custom header rules. This solves the issue where clients append unsupported query params (e.g. ?beta=true) that upstream providers reject.

关联 Issue / Related Issue

Closes #

变更内容 / Change Content

  • Bug 修复 / Bug fix
  • 新功能 / New feature
  • 其他改动 / Other changes

新增"自定义 URL 查询参数"功能,支持在代理请求转发至上游前,对 URL 查询参数进行添加、覆盖或移除操作。设计上完全参照现有的"自定义请求头"功能。

背景: 部分客户端 SDK(如 Anthropic)会在请求 URL 上拼接 ?beta=true 等参数,但某些上游服务不支持这类参数,导致请求失败。

改动范围:

后端

  • internal/models/types.go — 新增 QueryParamRule 模型,Group 增加 QueryParamRules / QueryParamRuleList 字段
  • internal/utils/query_param_utils.go — 新增 ApplyQueryParamRules() 工具函数
  • internal/services/group_service.go — 新增 normalizeQueryParamRules() 校验与去重
  • internal/handler/group_handler.go — 创建/更新/响应结构体中增加 query_param_rules
  • internal/services/group_manager.go — 缓存加载时解析 QueryParamRuleList
  • internal/proxy/server.go — 在 ModifyRequest 之后应用查询参数规则
  • internal/i18n/locales/{en-US,zh-CN,ja-JP}.go — 新增校验/错误提示国际化文案

前端

  • web/src/types/models.ts — 新增 QueryParamRule 类型
  • web/src/locales/{en-US,zh-CN,ja-JP}.ts — 新增 UI 国际化文案
  • web/src/components/keys/GroupFormModal.vue — 高级配置中新增查询参数规则编辑 UI

数据库: 新增 query_param_rules JSON 列,由 GORM AutoMigrate 自动创建,无需手动迁移。

自查清单 / Checklist

  • 我已在本地测试过我的变更。 / I have tested my changes locally.
  • 我已更新了必要的文档。 / I have updated the necessary documentation.

Summary by CodeRabbit

  • New Features

    • Custom query-parameter rules for groups: add/override/remove query params on forwarded requests; UI to create/edit rules with per-row toggles and validation; rules are applied when forwarding.
  • Localization

    • Added English, Japanese, and Chinese strings for the feature, including validation and internal error messages.

Allow per-group URL query parameter manipulation (set/remove) before
forwarding to upstream, mirroring the existing custom header rules.
This solves the issue where clients append unsupported query params
(e.g. ?beta=true) that upstream providers reject.
@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Apr 9, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 80cf9ae5-9adb-43da-aedf-15303eb85919

📥 Commits

Reviewing files that changed from the base of the PR and between 4bb5568 and 2471ea8.

📒 Files selected for processing (4)
  • internal/i18n/locales/en-US.go
  • internal/i18n/locales/ja-JP.go
  • internal/i18n/locales/zh-CN.go
  • internal/services/group_service.go
✅ Files skipped from review due to trivial changes (1)
  • internal/i18n/locales/en-US.go
🚧 Files skipped from review as they are similar to previous changes (2)
  • internal/i18n/locales/zh-CN.go
  • internal/i18n/locales/ja-JP.go

Walkthrough

Adds query-parameter rule support across the stack: model, service, handler, proxy execution, utilities, frontend form and i18n, enabling per-group rules to set or remove URL query parameters during request forwarding.

Changes

Cohort / File(s) Summary
Models
internal/models/types.go
Add QueryParamRule type; add persisted QueryParamRules datatypes.JSON and non-persisted QueryParamRuleList []QueryParamRule to Group.
Handlers
internal/handler/group_handler.go
Add QueryParamRules to GroupCreateRequest, GroupUpdateRequest, and GroupResponse; pass rules into service params and unmarshal rules for responses.
Services
internal/services/group_service.go, internal/services/group_manager.go
Add QueryParamRules to create/update params; implement normalizeQueryParamRules (trim, validate actions, dedupe check, JSON encode); manager unmarshals JSON into cache list and logs errors; include rule counts in debug logs.
Proxy & Utils
internal/proxy/server.go, internal/utils/query_param_utils.go
Apply QueryParamRuleList during request execution (after header rules) via new ApplyQueryParamRules which supports set (with variable resolution) and remove.
i18n Backend
internal/i18n/locales/en-US.go, internal/i18n/locales/ja-JP.go, internal/i18n/locales/zh-CN.go
Add validation/error message keys: validation.duplicate_query_param, validation.invalid_query_param_action, and error.process_query_param_rules.
Frontend Types & UI
web/src/types/models.ts, web/src/components/keys/GroupFormModal.vue
Add QueryParamRule interface and optional query_param_rules on Group; extend group form modal with UI for add/remove, action toggle, key/value inputs, per-form uniqueness validation, and submit integration.
Frontend i18n
web/src/locales/en-US.ts, web/src/locales/ja-JP.ts, web/src/locales/zh-CN.ts
Add UI translation keys for custom query parameters, tooltips, labels, duplicate warnings, and add-action text.

Sequence Diagram(s)

sequenceDiagram
    actor User
    participant Frontend as Frontend<br/>(Vue)
    participant Handler as HTTP Handler<br/>(group_handler.go)
    participant Service as Service<br/>(group_service.go)
    participant Manager as Manager<br/>(group_manager.go)
    participant Proxy as Proxy<br/>(server.go)
    participant Upstream as Upstream<br/>Server

    User->>Frontend: Fill group form with query_param_rules
    Frontend->>Frontend: Validate keys (trim, uniqueness)
    Frontend->>Handler: POST/PUT with query_param_rules
    Handler->>Service: CreateGroup/UpdateGroup with QueryParamRules
    Service->>Service: normalizeQueryParamRules() (trim, validate action, dedupe)
    Service->>Manager: Persist Group with QueryParamRules JSON
    Manager->>Manager: Unmarshal JSON -> QueryParamRuleList
    Handler->>Frontend: Return GroupResponse (query_param_rules)
    User->>Proxy: Send proxied request
    Proxy->>Proxy: Build HeaderVariableContext
    Proxy->>Proxy: ApplyQueryParamRules(req, QueryParamRuleList, ctx)
    Proxy->>Upstream: Forward request with modified query params
    Upstream-->>Proxy: Response
    Proxy-->>User: Return response
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Suggested labels

enhancement

Suggested reviewers

  • tbphp

Poem

🐰 Hop, hop — query params in line,
Set or remove, one rule at a time.
Frontend paints the form so neat,
Backend stores and proxy applies the feat.
A tiny hop for smoother routes!

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title 'feat: add custom query parameter rules for proxy requests' clearly and concisely describes the main feature being added—custom query parameter manipulation for proxy requests, mirroring the header rules functionality.
Description check ✅ Passed The PR description comprehensively covers the change content, background, detailed scope of backend and frontend modifications, database considerations, and a complete self-checklist. It meets the template requirements despite the issue number field remaining blank.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@coderabbitai coderabbitai bot requested a review from tbphp April 9, 2026 12:00
Copy link
Copy Markdown

@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: 3

🧹 Nitpick comments (1)
internal/proxy/server.go (1)

185-194: Reuse a single variable context for both rule applications.

This avoids duplicate context construction and keeps both rule phases using the exact same captured context instance.

♻️ Proposed refactor
-	// Apply custom header rules
-	if len(group.HeaderRuleList) > 0 {
-		headerCtx := utils.NewHeaderVariableContextFromGin(c, group, apiKey)
-		utils.ApplyHeaderRules(req, group.HeaderRuleList, headerCtx)
-	}
-
-	// Apply custom query parameter rules
-	if len(group.QueryParamRuleList) > 0 {
-		queryCtx := utils.NewHeaderVariableContextFromGin(c, group, apiKey)
-		utils.ApplyQueryParamRules(req, group.QueryParamRuleList, queryCtx)
-	}
+	// Apply custom header/query rules
+	if len(group.HeaderRuleList) > 0 || len(group.QueryParamRuleList) > 0 {
+		ruleCtx := utils.NewHeaderVariableContextFromGin(c, group, apiKey)
+		if len(group.HeaderRuleList) > 0 {
+			utils.ApplyHeaderRules(req, group.HeaderRuleList, ruleCtx)
+		}
+		if len(group.QueryParamRuleList) > 0 {
+			utils.ApplyQueryParamRules(req, group.QueryParamRuleList, ruleCtx)
+		}
+	}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@internal/proxy/server.go` around lines 185 - 194, Both rule phases create
separate contexts; instead, create one variable context once and reuse it for
both header and query rule applications: call
utils.NewHeaderVariableContextFromGin(c, group, apiKey) into a single local
(e.g., headerCtx or varCtx) and pass that same instance to
utils.ApplyHeaderRules(req, group.HeaderRuleList, varCtx) and
utils.ApplyQueryParamRules(req, group.QueryParamRuleList, varCtx) so both
HeaderRuleList and QueryParamRuleList use the exact same captured context.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@internal/services/group_service.go`:
- Around line 967-976: Validate each rule.Action inside the loop that builds
normalized query-param rules: after trimming and skipping empty keys but before
appending to normalized, check that rule.Action is one of the supported values
used by ApplyQueryParamRules() (e.g., "set" or "remove"); if not, return a
validation error (use NewI18nError with app_errors.ErrValidation and an
appropriate message key like "validation.invalid_query_param_action" and include
the offending key/action in the details) so unsupported actions are rejected
instead of persisted.

In `@internal/utils/query_param_utils.go`:
- Around line 20-22: The query-param handling currently calls
ResolveHeaderVariables(rule.Value, ctx) and can expand secret header variables
(e.g. ${API_KEY}) into the URL via q.Set, exposing secrets; change this to use a
query-specific resolver that does not resolve header secrets or explicitly
detect and reject header-secret tokens in rule.Value for query params (i.e.,
replace the ResolveHeaderVariables call in the "set" case with a non-secret
resolver or validation that scans rule.Value for HeaderVariableContext tokens
like ${API_KEY} and returns an error), and ensure q.Set only receives resolved
values that cannot include header secrets.

In `@web/src/components/keys/GroupFormModal.vue`:
- Around line 432-438: addQueryParamRule currently pushes a rule with action
"remove", causing the value field to be hidden and new rows to behave like
deletions; update the push in addQueryParamRule to set action: "set" (matching
header-rule behavior) so new query_param_rules entries default to
adding/overriding and the value field is shown (refer to addQueryParamRule and
formData.query_param_rules).

---

Nitpick comments:
In `@internal/proxy/server.go`:
- Around line 185-194: Both rule phases create separate contexts; instead,
create one variable context once and reuse it for both header and query rule
applications: call utils.NewHeaderVariableContextFromGin(c, group, apiKey) into
a single local (e.g., headerCtx or varCtx) and pass that same instance to
utils.ApplyHeaderRules(req, group.HeaderRuleList, varCtx) and
utils.ApplyQueryParamRules(req, group.QueryParamRuleList, varCtx) so both
HeaderRuleList and QueryParamRuleList use the exact same captured context.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: e4e325f8-6eb9-4f2a-89c3-e620908a24d3

📥 Commits

Reviewing files that changed from the base of the PR and between 578b3d6 and 4bb5568.

📒 Files selected for processing (14)
  • internal/handler/group_handler.go
  • internal/i18n/locales/en-US.go
  • internal/i18n/locales/ja-JP.go
  • internal/i18n/locales/zh-CN.go
  • internal/models/types.go
  • internal/proxy/server.go
  • internal/services/group_manager.go
  • internal/services/group_service.go
  • internal/utils/query_param_utils.go
  • web/src/components/keys/GroupFormModal.vue
  • web/src/locales/en-US.ts
  • web/src/locales/ja-JP.ts
  • web/src/locales/zh-CN.ts
  • web/src/types/models.ts

Comment thread internal/services/group_service.go Outdated
Comment thread internal/utils/query_param_utils.go
Comment thread web/src/components/keys/GroupFormModal.vue
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant