Skip to content

Fix image-search 400s: move image out of URL into POST body#1

Merged
kingwingfly merged 1 commit into
devfrom
fix/image-search-url-length
Jul 1, 2026
Merged

Fix image-search 400s: move image out of URL into POST body#1
kingwingfly merged 1 commit into
devfrom
fix/image-search-url-length

Conversation

@kingwingfly

Copy link
Copy Markdown
Owner

Problem

Image-by-image search encoded the (base64) image into the q query-string
parameter. That rode in both the browser router URL and the EventSource
GET request to /api/search, overflowing the request-line/URL length limit
and 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 existing
server-fn idiom. Server functions POST their args in the request body
(default PostUrl codec), so the image no longer travels in the URL — and
they stay stateless, which is correct for auto-scaled Cloud Run.

  • The image bytes are stashed in a client-side ImageQuery context; navigation
    carries only a short nonce, so no large payload hits the URL.
  • Results calls the REST fns via spawn_local with a req_id guard that
    discards responses from superseded requests (replaces EventSource/ActiveSse).
  • Reloading/sharing an image-search URL now degrades to an empty result instead
    of 400ing (the bytes are client-only and were never URL-reproducible).

Trade-offs

  • Results arrive per page in one response instead of streaming in via SSE
    (inherent to the REST switch; total work unchanged).
  • Deleted the /api/search axum route + search/server/src/api.rs.

Verification

Compiles on both targets: cargo check -p server (SSR) and
cargo check -p frontend --target wasm32-unknown-unknown (wasm hydrate).

🤖 Generated with Claude Code

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>
Copilot AI review requested due to automatic review settings July 1, 2026 12:24
@kingwingfly kingwingfly merged commit bf8349a into dev Jul 1, 2026
1 check passed
@kingwingfly kingwingfly deleted the fix/image-search-url-length branch July 1, 2026 12:26

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

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/search SSE endpoint with Leptos server functions (search_query, search_by_image) that POST arguments in the request body.
  • Introduce a client-side ImageQuery context to store image-search bytes in memory and navigate with a short nonce instead of embedding base64 in the URL.
  • Update Results, SearchBar, and ImageDetails to 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),
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.

2 participants