Web Server Compress
1 Unified Compression
compressible-mime-type?
wrap-compress
2 Brotli Compression
wrap-brotli-compress
3 Zstd Compression
level/  c
wrap-zstd-compress
4 Gzip Compression
gzip-level/  c
wrap-gzip-compress
9.1.0.12

Web Server Compress🔗ℹ

Jay Bonthius <jay@jmbmail.com>

 (require web-server-compress) package: web-server-compress

HTTP response compression middleware for the Racket web server. Supports Brotli, zstd, and gzip compression, with priority-based encoding negotiation.

1 Unified Compression🔗ℹ

Predicate that returns #t for MIME types that benefit from compression: all text/* types, plus application/json, application/javascript, application/xml, application/xhtml+xml, application/wasm, application/ld+json, application/graphql+json, application/geo+json, application/manifest+json, application/rss+xml, application/atom+xml, and image/svg+xml. Returns #t when the MIME type is #f (no Content-Type header). Already-compact formats like JPEG, PNG, and ZIP return #f.

procedure

(wrap-compress handler 
  [#:encodings encodings 
  #:compress? compress? 
  #:zstd-level zstd-level 
  #:brotli-quality brotli-quality 
  #:brotli-window brotli-window 
  #:brotli-mode brotli-mode 
  #:gzip-level gzip-level]) 
  (-> request? response?)
  handler : (-> request? response?)
  encodings : (listof (or/c 'zstd 'br 'gzip)) = '(zstd br gzip)
  compress? : (-> response? boolean?) = compressible-mime-type?
  zstd-level : level/c = 3
  brotli-quality : quality/c = 5
  brotli-window : window/c = 22
  brotli-mode : mode/c = BROTLI_MODE_TEXT
  gzip-level : gzip-level/c = 6
Wraps handler to compress responses using the best available encoding. The server iterates through encodings in order and selects the first one the client accepts via Accept-Encoding. If no encoding matches, the response passes through uncompressed.

Supported encoding symbols: 'zstd, 'br, and 'gzip.

Compressed responses include Content-Encoding and Vary: Accept-Encoding headers.

compress? decides whether a given response should be compressed. The default compresses text types and common structured formats (see below).

(require web-server-compress
         web-server/servlet-dispatch
         web-server/web-server)
 
(define (app req)
  (response/xexpr '(html (body "hello"))))
 
; Prefer zstd, fall back to brotli, then gzip
(serve
 #:dispatch (dispatch/servlet
             (wrap-compress app #:encodings '(zstd br gzip)))
 #:port 8080)

To use only one encoding:

(wrap-compress app #:encodings '(br) #:brotli-quality 9)

2 Brotli Compression🔗ℹ

procedure

(wrap-brotli-compress handler 
  [#:quality quality 
  #:window window 
  #:mode mode 
  #:compress? compress?]) 
  (-> request? response?)
  handler : (-> request? response?)
  quality : quality/c = 5
  window : window/c = 22
  mode : mode/c = BROTLI_MODE_TEXT
  compress? : (-> response? boolean?) = compressible-mime-type?
Wraps handler to compress responses with Brotli when the client sends Accept-Encoding: br and the response is compressible. Compressed responses include Content-Encoding: br and Vary: Accept-Encoding headers.

quality, window, and mode control the Brotli encoder. See libbrotli for details.

compress? decides whether a given response should be compressed. The default (compressible-mime-type?) compresses text types (text/*) and common structured formats:

  • application/json, application/javascript, application/xml, application/xhtml+xml

  • application/wasm, application/ld+json, application/graphql+json, application/geo+json

  • application/manifest+json, application/rss+xml, application/atom+xml

  • image/svg+xml

Responses with no Content-Type header are also compressed. Already-compact formats like JPEG, PNG, and ZIP are not compressed.

(require web-server-compress
         web-server/servlet-dispatch
         web-server/web-server)
 
(define (app req)
  (response/xexpr '(html (body "hello"))))
 
(serve
 #:dispatch (dispatch/servlet (wrap-brotli-compress app))
 #:port 8080)

To override the default predicate, pass a custom compress?:

(wrap-brotli-compress app
  #:compress? (lambda (resp)
                (equal? (response-mime resp) #"application/json")))

3 Zstd Compression🔗ℹ

Contract for zstd compression levels. Accepts integers in the range supported by the linked libzstd (typically -131072 to 22).

procedure

(wrap-zstd-compress handler 
  [#:level level 
  #:compress? compress?]) 
  (-> request? response?)
  handler : (-> request? response?)
  level : level/c = 3
  compress? : (-> response? boolean?) = compressible-mime-type?
Wraps handler to compress responses with zstd when the client sends Accept-Encoding: zstd and the response is compressible. Compressed responses include Content-Encoding: zstd and Vary: Accept-Encoding headers.

level controls the zstd compression level. Higher values give better compression at the cost of speed. The default of 3 is a good balance for streaming use cases like Server-Sent Events.

compress? works identically to wrap-brotli-compress’s predicate.

(serve
 #:dispatch (dispatch/servlet (wrap-zstd-compress app #:level 6))
 #:port 8080)

4 Gzip Compression🔗ℹ

Contract for gzip compression levels. Accepts integers from 0 (no compression) to 9 (best compression).

procedure

(wrap-gzip-compress handler 
  [#:level level 
  #:compress? compress?]) 
  (-> request? response?)
  handler : (-> request? response?)
  level : gzip-level/c = 6
  compress? : (-> response? boolean?) = compressible-mime-type?
Wraps handler to compress responses with gzip when the client sends Accept-Encoding: gzip and the response is compressible. Compressed responses include Content-Encoding: gzip and Vary: Accept-Encoding headers.

level controls the gzip compression level (0–9). Higher values give better compression at the cost of speed. The default of 6 matches zlib’s own default and is a good general-purpose setting.

Gzip compression is provided by the libz package, which bundles platform-specific zlib shared libraries.

compress? works identically to wrap-brotli-compress’s predicate.

(serve
 #:dispatch (dispatch/servlet (wrap-gzip-compress app #:level 4))
 #:port 8080)