Skip to content

perf: gzip-compress JSON responses for startup-path API endpoints#550

Closed
sam-saffron-jarvis wants to merge 3 commits intoSamSaffron:mainfrom
sam-saffron-jarvis:feat/webui-json-gzip
Closed

perf: gzip-compress JSON responses for startup-path API endpoints#550
sam-saffron-jarvis wants to merge 3 commits intoSamSaffron:mainfrom
sam-saffron-jarvis:feat/webui-json-gzip

Conversation

@sam-saffron-jarvis
Copy link
Copy Markdown
Contributor

What

Add writeJSONGzip, a helper that transparently gzip-compresses JSON API responses when the client sends Accept-Encoding: gzip and the payload exceeds 512 bytes.

Apply it to the three endpoints the web UI calls on every page load:

Endpoint Typical uncompressed size
GET /v1/sessions ~10–20 KB (up to 100 sessions)
GET /v1/models ~10–50 KB (hundreds of IDs for OpenRouter)
GET /v1/providers ~1–5 KB (provider list with model arrays)

Why

All browsers send Accept-Encoding: gzip by default. JSON is extremely compressible (typically 70–80% ratio). These three requests sit on the critical path of every page load — they block hideStartupSplash. Compressing them reduces startup latency on any connection slower than localhost.

Uses gzip.BestSpeed (level 1) rather than BestCompression — dynamic API responses are not cached, so encode time matters more than ratio.

The 512-byte threshold avoids compressing tiny error responses where gzip header overhead would exceed the savings.

Tests

  • TestWriteJSONGzip_CompressesLargeResponse — large payload is gzip-compressed and round-trips correctly
  • TestWriteJSONGzip_NoCompressionWithoutAcceptEncoding — plain JSON returned when client doesn't advertise gzip
  • TestWriteJSONGzip_SkipsCompressionForSmallPayload — payloads ≤512 B are sent uncompressed
  • TestHandleSessions_GzipCompressed — integration test through the full handleSessions handler

Add writeJSONGzip helper that transparently gzip-compresses JSON
responses when the client sends Accept-Encoding: gzip and the payload
exceeds 512 bytes.

Apply to the three endpoints the web UI calls on every page load:
  - GET /v1/sessions  (up to 100 sessions, ~10-20 KB uncompressed)
  - GET /v1/models    (hundreds of IDs for OpenRouter, ~10-50 KB)
  - GET /v1/providers (provider list with embedded model arrays)

Uses gzip.BestSpeed (level 1) rather than BestCompression — dynamic
API responses aren't cached, so encode time matters more than ratio.
JSON typically achieves 70-80% reduction even at speed level.

Adds four unit tests: large-payload compression, no-Accept-Encoding
passthrough, small-payload bypass, and handleSessions integration.
Same pattern as the startup-path endpoints: compress when the client
sends Accept-Encoding: gzip and the body exceeds 512 bytes.

The status poll already short-circuits with 304 when content is
unchanged, so gzip only applies to the first response (no ETag yet)
and polls after a change — both cases benefit from reduced wire size.
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