fix: omit uris field when HTTPRoute path type is RegularExpression (backport apache/apisix-ingress-controller#2770)#417
Conversation
📝 WalkthroughWalkthroughThe PR adds HTTPRoute RegularExpression path matching support. A translator change assigns a catch-all URI to satisfy APISIX Admin API requirements while using route variables for actual regex filtering. A new end-to-end test validates the behavior for matching and non-matching request paths. ChangesHTTPRoute regex path matching support
Estimated code review effort🎯 2 (Simple) | ⏱️ ~10 minutes 🚥 Pre-merge checks | ✅ 5 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
🧹 Nitpick comments (1)
internal/adc/translator/httproute_test.go (1)
328-336: ⚡ Quick winAssert serialized JSON omits
uristo cover the actual regression.Current assertions prove
route.Urisis nil, but they don’t verify that marshaling excludes theuriskey (the root API breakage path).Proposed test hardening
func TestTranslateGatewayHTTPRouteMatchRegexPath(t *testing.T) { @@ assert.Equal(t, adctypes.StringOrSlice{StrVal: "uri"}, route.Vars[0][0]) assert.Equal(t, adctypes.StringOrSlice{StrVal: "~~"}, route.Vars[0][1]) assert.Equal(t, adctypes.StringOrSlice{StrVal: pathValue}, route.Vars[0][2]) + + b, err := json.Marshal(route) + require.NoError(t, err) + assert.NotContains(t, string(b), `"uris"`) }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@internal/adc/translator/httproute_test.go` around lines 328 - 336, Add a JSON-marshalling assertion to ensure the serialized route omits the "uris" key: after the existing checks on route.Uris and route.Vars, marshal the route (using json.Marshal(route)), assert no error, and assert the resulting JSON string does not contain the literal `"uris"` (or `"uris":`) so the test covers the regression where the key is present even if route.Uris is nil; reference the existing route variable and use json.Marshal and string containment assertion (e.g., assert.NotContains) to validate.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Nitpick comments:
In `@internal/adc/translator/httproute_test.go`:
- Around line 328-336: Add a JSON-marshalling assertion to ensure the serialized
route omits the "uris" key: after the existing checks on route.Uris and
route.Vars, marshal the route (using json.Marshal(route)), assert no error, and
assert the resulting JSON string does not contain the literal `"uris"` (or
`"uris":`) so the test covers the regression where the key is present even if
route.Uris is nil; reference the existing route variable and use json.Marshal
and string containment assertion (e.g., assert.NotContains) to validate.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: f90cd354-3a0c-44c4-b050-7894a6825cfa
📒 Files selected for processing (2)
api/adc/types.gointernal/adc/translator/httproute_test.go
64dc407 to
69bb168
Compare
conformance test report - apisix-standalone modeapiVersion: gateway.networking.k8s.io/v1
date: "2026-05-26T05:56:39Z"
gatewayAPIChannel: experimental
gatewayAPIVersion: v1.3.0
implementation:
contact: null
organization: APISIX
project: apisix-ingress-controller
url: https://github.com/apache/apisix-ingress-controller.git
version: v2.0.0
kind: ConformanceReport
mode: default
profiles:
- core:
result: success
statistics:
Failed: 0
Passed: 12
Skipped: 0
name: GATEWAY-GRPC
summary: Core tests succeeded.
- core:
result: partial
skippedTests:
- HTTPRouteHTTPSListener
statistics:
Failed: 0
Passed: 32
Skipped: 1
extended:
result: partial
skippedTests:
- HTTPRouteRedirectPortAndScheme
statistics:
Failed: 0
Passed: 11
Skipped: 1
supportedFeatures:
- GatewayAddressEmpty
- GatewayPort8080
- HTTPRouteBackendProtocolWebSocket
- HTTPRouteDestinationPortMatching
- HTTPRouteHostRewrite
- HTTPRouteMethodMatching
- HTTPRoutePathRewrite
- HTTPRoutePortRedirect
- HTTPRouteQueryParamMatching
- HTTPRouteRequestMirror
- HTTPRouteResponseHeaderModification
- HTTPRouteSchemeRedirect
unsupportedFeatures:
- GatewayHTTPListenerIsolation
- GatewayInfrastructurePropagation
- GatewayStaticAddresses
- HTTPRouteBackendProtocolH2C
- HTTPRouteBackendRequestHeaderModification
- HTTPRouteBackendTimeout
- HTTPRouteParentRefPort
- HTTPRoutePathRedirect
- HTTPRouteRequestMultipleMirrors
- HTTPRouteRequestPercentageMirror
- HTTPRouteRequestTimeout
name: GATEWAY-HTTP
summary: Core tests partially succeeded with 1 test skips. Extended tests partially
succeeded with 1 test skips.
- core:
result: partial
skippedTests:
- TLSRouteSimpleSameNamespace
statistics:
Failed: 0
Passed: 10
Skipped: 1
name: GATEWAY-TLS
summary: Core tests partially succeeded with 1 test skips. |
conformance test report - apisix modeapiVersion: gateway.networking.k8s.io/v1
date: "2026-05-26T05:57:39Z"
gatewayAPIChannel: experimental
gatewayAPIVersion: v1.3.0
implementation:
contact: null
organization: APISIX
project: apisix-ingress-controller
url: https://github.com/apache/apisix-ingress-controller.git
version: v2.0.0
kind: ConformanceReport
mode: default
profiles:
- core:
result: success
statistics:
Failed: 0
Passed: 12
Skipped: 0
name: GATEWAY-GRPC
summary: Core tests succeeded.
- core:
failedTests:
- HTTPRouteInvalidBackendRefUnknownKind
result: failure
skippedTests:
- HTTPRouteHTTPSListener
statistics:
Failed: 1
Passed: 31
Skipped: 1
extended:
result: partial
skippedTests:
- HTTPRouteRedirectPortAndScheme
statistics:
Failed: 0
Passed: 11
Skipped: 1
supportedFeatures:
- GatewayAddressEmpty
- GatewayPort8080
- HTTPRouteBackendProtocolWebSocket
- HTTPRouteDestinationPortMatching
- HTTPRouteHostRewrite
- HTTPRouteMethodMatching
- HTTPRoutePathRewrite
- HTTPRoutePortRedirect
- HTTPRouteQueryParamMatching
- HTTPRouteRequestMirror
- HTTPRouteResponseHeaderModification
- HTTPRouteSchemeRedirect
unsupportedFeatures:
- GatewayHTTPListenerIsolation
- GatewayInfrastructurePropagation
- GatewayStaticAddresses
- HTTPRouteBackendProtocolH2C
- HTTPRouteBackendRequestHeaderModification
- HTTPRouteBackendTimeout
- HTTPRouteParentRefPort
- HTTPRoutePathRedirect
- HTTPRouteRequestMultipleMirrors
- HTTPRouteRequestPercentageMirror
- HTTPRouteRequestTimeout
name: GATEWAY-HTTP
summary: Core tests failed with 1 test failures. Extended tests partially succeeded
with 1 test skips.
- core:
result: partial
skippedTests:
- TLSRouteSimpleSameNamespace
statistics:
Failed: 0
Passed: 10
Skipped: 1
name: GATEWAY-TLS
summary: Core tests partially succeeded with 1 test skips. |
conformance test reportapiVersion: gateway.networking.k8s.io/v1
date: "2026-05-26T06:13:58Z"
gatewayAPIChannel: experimental
gatewayAPIVersion: v1.3.0
implementation:
contact: null
organization: APISIX
project: apisix-ingress-controller
url: https://github.com/apache/apisix-ingress-controller.git
version: v2.0.0
kind: ConformanceReport
mode: default
profiles:
- core:
failedTests:
- GatewayModifyListeners
result: failure
statistics:
Failed: 1
Passed: 11
Skipped: 0
name: GATEWAY-GRPC
summary: Core tests failed with 1 test failures.
- core:
failedTests:
- GatewayModifyListeners
result: failure
skippedTests:
- HTTPRouteHTTPSListener
statistics:
Failed: 1
Passed: 31
Skipped: 1
extended:
result: partial
skippedTests:
- HTTPRouteRedirectPortAndScheme
statistics:
Failed: 0
Passed: 11
Skipped: 1
supportedFeatures:
- GatewayAddressEmpty
- GatewayPort8080
- HTTPRouteBackendProtocolWebSocket
- HTTPRouteDestinationPortMatching
- HTTPRouteHostRewrite
- HTTPRouteMethodMatching
- HTTPRoutePathRewrite
- HTTPRoutePortRedirect
- HTTPRouteQueryParamMatching
- HTTPRouteRequestMirror
- HTTPRouteResponseHeaderModification
- HTTPRouteSchemeRedirect
unsupportedFeatures:
- GatewayHTTPListenerIsolation
- GatewayInfrastructurePropagation
- GatewayStaticAddresses
- HTTPRouteBackendProtocolH2C
- HTTPRouteBackendRequestHeaderModification
- HTTPRouteBackendTimeout
- HTTPRouteParentRefPort
- HTTPRoutePathRedirect
- HTTPRouteRequestMultipleMirrors
- HTTPRouteRequestPercentageMirror
- HTTPRouteRequestTimeout
name: GATEWAY-HTTP
summary: Core tests failed with 1 test failures. Extended tests partially succeeded
with 1 test skips.
- core:
failedTests:
- GatewayModifyListeners
- TLSRouteSimpleSameNamespace
result: failure
statistics:
Failed: 2
Passed: 9
Skipped: 0
name: GATEWAY-TLS
summary: Core tests failed with 2 test failures. |
When path.type is RegularExpression, the controller sets route.Vars for regex matching but never sets route.Uris, leaving it nil. This serializes as "uris": null, which is rejected by APISIX Admin API v3 with HTTP 400 (expected array, received null). Omitting the field via omitempty also fails with "received undefined". The correct fix is to set uris to ["/*"] as a catch-all passthrough so APISIX accepts the route payload, while the vars entry performs the actual regex filtering against the request URI. Fixes #2764 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
69bb168 to
c7cec75
Compare
Problem
When an
HTTPRouteusespath.type: RegularExpression, the controller correctly generates avarsentry for regex matching, but never setsuris— leaving itnil. Withoutomitempty,nilserializes as"uris": null, which is rejected by the APISIX Admin API v3 with HTTP 400:Because the controller sends all services in a single bulk payload, every route in the cluster fails to sync — not just the offending regex route.
Root Cause
In
translateGatewayHTTPRouteMatch, thePathMatchRegularExpressioncase only appends toroute.Varsand never setsroute.Uris:Fix
Set
route.Uris = []string{"/*"}as a catch-all in theRegularExpressioncase. APISIX routing first matches byuris, then appliesvarsconditions — so"/*"lets every path through, while thevarsregex does the actual filtering:The resulting APISIX route payload for a regex path
/lk.*now looks like:{ "uris": ["/*"], "vars": [["uri", "~~", "/lk.*"]] }Example
Apply an
HTTPRoutewithRegularExpressionpath type:Before the fix: all routes across the cluster fail to sync (HTTP 400).
After the fix: the route syncs correctly and requests to
/status/200or/status/404are forwarded to the backend, while/status/ok(non-numeric) returns 404.Changes
internal/adc/translator/httproute.go: setroute.Uris = ["/*"]in thePathMatchRegularExpressioncasetest/e2e/gatewayapi/httproute.go: addHTTPRoute RegularExpression Matche2e test