Compress /api/v1 responses with gzip - #95
Merged
Merged
Conversation
History/metrics payloads are repetitive JSON that can reach several hundred KB per poll (720 points per series across all series on a Pi with disks/interfaces). Add a withGzip middleware that compresses responses for clients sending Accept-Encoding: gzip, using a pooled gzip.Writer at BestSpeed to keep the CPU cost low on constrained Pi hardware. Clients without that header keep receiving identity responses, so no existing /api/v1 consumer breaks. Closes #23
|
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.



📖 Description
GET /api/v1/metrics/historyreturns highly repetitive JSON (a fixed set oftime series, each point ~50 bytes) that can reach several hundred KB per poll
on a Pi with multiple disks/interfaces at the default 60-minute/5-second
history window.
writeJSONnever compressed responses, so this payload wasre-sent in full, uncompressed, on every poll — noticeable on a Pi Zero over
Wi-Fi both in transfer time and CPU.
This adds a
withGzipmiddleware (internal/httpapi/middleware.go) usingonly the standard library:
Accept-Encodingdoesn't containgzip, the requestpasses through unchanged (identity response, unmodified for existing
clients).
Content-Encoding: gzipandVary: Accept-Encoding,drops any
Content-Length, and wraps theResponseWritersoWritegoesthrough a pooled
*gzip.Writeratgzip.BestSpeed(async.Poolavoidsper-request writer allocation;
WriteHeaderis forwarded automatically viathe embedded
http.ResponseWriter).withGzipwraps the four/api/v1/...routes inserver.go(
/api/v1/metrics,/api/v1/metrics/history,/api/v1/alerts,/api/v1/config)./healthzis left uncompressed (2-byte body, not worthit).
🎫 Issues
Closes #23
👩💻 Reviewer Notes
Smoke-tested locally:
(compression ratio grows with history size — the fixture above only had a
handful of history points; a full 60-minute window compresses closer to the
~10x mentioned in the issue, since it's far more repetitive.)
📑 Test Plan
TestHandleHistory_GzipWhenAcceptedinmiddleware_test.go:builds a 500-point history fixture, requests it both without and with
Accept-Encoding: gzip, and asserts the gzip response carriesContent-Encoding: gzip/Vary: Accept-Encoding, is smaller than theidentity response, and gunzips to byte-equivalent JSON.
go build ./...,go vet ./...,go test ./... -race -cover, andgolangci-lint runall pass locally.✅ Checklist
General
go test ./... -race -coverpasses locally).go vet ./...andgolangci-lint runare clean.ARCHITECTURE.mdif this changes a documented design decision. (not applicable — this is an internal HTTP-layer optimization, not a documented architectural decision)REST API / configuration / packaging
docs/API.mdto reflect a REST API change. (new "Compression" section)/api/v1/...response shapes, or a new API version (/api/v2/...) was introduced instead. (response bodies are byte-identical after decompression — only the wire encoding changes, and only for clients that opt in viaAccept-Encoding: gzip)⏭ Next Steps
None.