package middleware
import (
"compress/gzip"
"net/http"
"strings"
)
type gzipResponseWriter struct {
http.ResponseWriter
w *gzip.Writer
}
func (g gzipResponseWriter) Write(b []byte) (int, error) {
return g.w.Write(b)
}
func Gzip(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if !strings.Contains(r.Header.Get("Accept-Encoding"), "gzip") {
next.ServeHTTP(w, r)
return
}
w.Header().Set("Vary", "Accept-Encoding")
w.Header().Set("Content-Encoding", "gzip")
gz := gzip.NewWriter(w)
defer gz.Close()
next.ServeHTTP(gzipResponseWriter{ResponseWriter: w, w: gz}, r)
})
}
Compressing responses is an easy bandwidth win for JSON APIs, but only when it's done carefully. I check Accept-Encoding for gzip, set Vary: Accept-Encoding so caches behave correctly, and stream output through gzip.Writer so we don't buffer full responses in memory. The key operational detail is CPU: compression can become expensive under load, so I usually enable it at the edge or for selected endpoints, not blindly everywhere. This pattern is also safe for streaming responses because it writes as data is produced. If you add content-type checks and a size threshold, you can avoid compressing already-compressed formats like image/*. Done right, this is a clean middleware that improves latency and reduces egress costs.
Related snips
package api
import (
"net/http"
"runtime/debug"
)
Expose build metadata for debugging deploys
export interface RetryOptions {
retries: number;
baseMs: number;
maxMs: number;
signal?: AbortSignal;
onRetry?: (attempt: number, delay: number, err: unknown) => void;
Exponential backoff with jitter for retries
package dbutil
import (
"context"
"github.com/jackc/pgconn"
Retry Postgres serialization failures with bounded attempts
require "csv"
class PeopleCsvStream
include Enumerable
HEADERS = %w[id full_name email signed_up_at plan].freeze
Resilient CSV Export as a Streamed Response
Rails.application.configure do
config.after_initialize do
Bullet.enable = true
Bullet.alert = false
Bullet.bullet_logger = true
Bullet.console = true
N+1 query detection with Bullet gem
json.array! @posts do |post|
json.cache! ['v1', post], expires_in: 1.hour do
json.id post.id
json.title post.title
json.excerpt post.excerpt
json.published_at post.published_at
Fragment caching for expensive JSON serialization
Share this code
Here's the card — post it anywhere.