feat: add a per-route test-request drawer with a copyable curl - #3456
Merged
Merged
Conversation
This was referenced Jul 30, 2026
lxbme
marked this pull request as draft
July 30, 2026 09:39
Configuration happens on the admin port; verification happens on the data plane port. The dashboard covered the first and said nothing about the second, so confirming that a route you had just created actually serves traffic meant leaving the UI and hand-writing a curl. A route's detail page now has a Test button opening a request drawer. It prefills from the route's own config — the method, the path, and a Host header when the route matches on host — and always shows the equivalent curl, recomputed as you edit and ready to copy. Sending is best-effort and degrades honestly. Two constraints rule out the obvious approach: the data plane is a different origin and sends no CORS headers by default, so the browser usually cannot read the response, and fetch may not set the Host header, so a host-matched route cannot be reproduced from the browser even when it is reachable. The generated command is therefore the dependable path, and a send the browser cannot read resolves to one explicit message rather than a misleading failure. Showing the equivalent curl also makes the Admin API legible and gives users a path from clicking to scripting. Part of apache#3453
lxbme
force-pushed
the
feat/route-test-request
branch
from
August 3, 2026 01:51
5e69e17 to
78cfc49
Compare
lxbme
marked this pull request as ready for review
August 3, 2026 01:57
guoqqqi
approved these changes
Aug 3, 2026
LiteSun
approved these changes
Aug 3, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Please answer these questions before submitting a pull request, or your PR will get closed.
Why submit this pull request?
What changes will this PR take into?
Configuration happens on the admin port; verification happens on the data plane port. The dashboard covered the first and said nothing about the second, so confirming that a route you had just created actually serves traffic meant leaving the UI and hand-writing a
curl.A route's detail page now has a Test button opening a request drawer.
It prefills from the route's own config — the method (constrained to the methods the route declares), the path, and a
Hostheader when the route matches on host. A wildcard or regex uri comes through verbatim with a hint to replace it with a concrete path.The equivalent
curlis always visible and recomputes as you edit any field, with a copy button. Until a gateway URL is entered the base renders ashttp://<gateway-host>:<port>so the command is still copyable and completable by hand. The gateway URL is remembered inlocalStorage, drawer-local — no new app-wide setting.Sending is best-effort and degrades honestly. Two constraints shape this and are worth stating, because they rule out the obvious approach: the data plane is a different origin and sends no CORS headers by default, so the browser usually cannot read the response; and
fetchis not permitted to set theHostheader, so a host-matched route cannot be reproduced from the browser even when it is reachable. The generated command is therefore the dependable path. A send that the browser cannot read resolves to one explicit message — "the browser couldn't read a response (likely cross-origin or unreachable), copy the command above and run it in a terminal" — rather than a misleading failure. When the response is readable, the drawer shows the status coloured by class, the elapsed time, a collapsible header list, and a pretty-printed body.Showing the equivalent
curlalso has value beyond testing: it makes the Admin API legible and gives users a path from clicking to scripting.Scope is HTTP routes. A superseded in-flight send cannot paint over a newer request: each send carries a token that is checked before any state is written, and closing the drawer invalidates whatever is in flight.
Rebased onto the merged sibling PRs
This branch now sits on
masterwith #3454, #3457, #3458 and #3459 merged. The only conflict was insrc/routes/routes/detail.$id.tsx, where #3458 rewrote the samePageHeaderblock this PR adds the Test button to. Resolved by keeping both:extrarenders unconditionally so Test is available in either mode, Edit and Delete stay inside the read-only branch, and the title keeps #3458's id-bearinginfo.detail.titleWithIdrather than the older string this branch was written against. All five locale files merged automatically.Related issues
Part of #3453
Checklist:
Tests:
util.test.tscovers the prefill rules and thecurlrendering, with the shell-escaping of single quotes in URLs, header values and bodies as its focus.sendLive.test.tscovers both outcomes against a mockedfetch.e2e/tests/regression/routes.test-request-drawer.spec.tsseeds a route with themockingplugin, then asserts the prefilledcurl, that editing the path updates it live, that Copy reports success, and that an unreachable gateway produces the honest fallback — the deterministic branch, since cross-origin has a predictable outcome.Verified:
pnpm test,pnpm lint,pnpm exec tsc -band a productionpnpm buildall clean; the fullpnpm e2esuite green apart from pre-existing environment flakes that pass on isolated rerun. Checked by hand in Chrome on both paths — with thecorsplugin on the route the drawer renders a real200 OKwith timing and body; without it, the fallback message.