Fix image-search 400s: move image out of URL into POST body#1
Merged
Conversation
Image-by-image search encoded the (base64) image into the query string, which overflowed the request-line/URL length limit and produced 400s. Replace the SSE search endpoint with Leptos server functions (search_query / search_by_image). Server fns POST their args in the request body, so the image no longer rides in the URL. The bytes are stashed in a client-side ImageQuery context and navigation carries only a short nonce; Results calls the REST fns with a req_id guard for cancellation. Reloading an image-search URL degrades to an empty result instead of 400ing. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
This PR addresses intermittent 400 Bad Request errors during image-by-image search by removing large base64 image payloads from the URL/request line and moving them into POST bodies via Leptos #[server] functions, aligning with the existing server-function pattern and keeping the service stateless for Cloud Run scaling.
Changes:
- Replace the
/api/searchSSE endpoint with Leptos server functions (search_query,search_by_image) that POST arguments in the request body. - Introduce a client-side
ImageQuerycontext to store image-search bytes in memory and navigate with a short nonce instead of embedding base64 in the URL. - Update
Results,SearchBar, andImageDetailsto use the new REST-style server functions and stale-response guarding.
Reviewed changes
Copilot reviewed 8 out of 9 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| search/server/src/main.rs | Removes manual /api/search routing; relies on Leptos server-function registration. |
| search/server/src/api.rs | Deletes the SSE search implementation that previously embedded base64 in query params. |
| search/app/src/types.rs | Adds ImageQuery context type and introduces SearchResponse as the server-fn result payload. |
| search/app/src/lib.rs | Provides ImageQuery at the app root for client-side image-search storage. |
| search/app/src/components/search_bar.rs | Stores image payload in ImageQuery and navigates with a nonce instead of base64 in q. |
| search/app/src/components/results.rs | Replaces SSE client logic with server-fn calls, paging, and request supersession protection. |
| search/app/src/components/image_details.rs | Uses ImageQuery + nonce navigation for cropped image searches. |
| search/app/Cargo.toml | Adds SSR-only deps (futures, base64) needed by server-fn implementations. |
| Cargo.lock | Locks new dependency entries for base64/futures. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Comment on lines
+564
to
+569
| let limit = limit.max(1); | ||
| let offset = offset.max(0); | ||
|
|
||
| let bytes = URL_SAFE_NO_PAD | ||
| .decode(image.as_bytes()) | ||
| .map_err(|e| to_args(format!("invalid image data: {e}")))?; |
| // in client memory and navigate with only a short nonce so the | ||
| // Results component re-runs its search against the stored bytes. | ||
| img_query.0.set(Some(b64)); | ||
| go(format!("{}", js_sys::Date::now() as u64)); |
| let path = pathname.get_untracked(); | ||
| nav_up( | ||
| &format!("{path}?mode=search_image&q={q}"), | ||
| &format!("{path}?mode=search_image&q={}", js_sys::Date::now() as u64), |
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.
Problem
Image-by-image search encoded the (base64) image into the
qquery-stringparameter. That rode in both the browser router URL and the
EventSourceGET request to
/api/search, overflowing the request-line/URL length limitand producing intermittent 400 Bad Request responses.
Fix
Replace the SSE search endpoint with two Leptos
#[server]functions(
search_query/search_by_image), matching the codebase's existingserver-fn idiom. Server functions POST their args in the request body
(default
PostUrlcodec), so the image no longer travels in the URL — andthey stay stateless, which is correct for auto-scaled Cloud Run.
ImageQuerycontext; navigationcarries only a short nonce, so no large payload hits the URL.
Resultscalls the REST fns viaspawn_localwith areq_idguard thatdiscards responses from superseded requests (replaces
EventSource/ActiveSse).of 400ing (the bytes are client-only and were never URL-reproducible).
Trade-offs
(inherent to the REST switch; total work unchanged).
/api/searchaxum route +search/server/src/api.rs.Verification
Compiles on both targets:
cargo check -p server(SSR) andcargo check -p frontend --target wasm32-unknown-unknown(wasm hydrate).🤖 Generated with Claude Code