rust
46 lines · 6 steps
Response compression in Axum with tower-http
Attach a tower-http CompressionLayer to an Axum router so JSON responses are gzip/brotli/zstd compressed selectively.
Explained by
highlit
1use axum::{
2 routing::get,
3 Json, Router,
4};
5use serde::Serialize;
6use tower_http::compression::{CompressionLayer, CompressionLevel};
7use tower_http::compression::predicate::{NotForContentType, SizeAbove};
8use tower_http::CompressionLevel::*;
9
10#[derive(Serialize)]
11struct Article {
12 id: u64,
13 title: String,
14 body: String,
15}
16
17async fn list_articles() -> Json<Vec<Article>> {
18 let articles = (1..=50)
19 .map(|id| Article {
20 id,
21 title: format!("Article #{id}"),
22 body: "Lorem ipsum dolor sit amet, ".repeat(64),
23 })
24 .collect();
25
26 Json(articles)
27}
28
29pub fn router() -> Router {
30 let predicate = SizeAbove::new(1024)
31 .and(NotForContentType::GRPC)
32 .and(NotForContentType::IMAGES)
33 .and(NotForContentType::const_new("application/wasm"));
34
35 let compression = CompressionLayer::new()
36 .gzip(true)
37 .br(true)
38 .zstd(true)
39 .no_deflate()
40 .quality(CompressionLevel::Precise(6))
41 .compress_when(predicate);
42
43 Router::new()
44 .route("/articles", get(list_articles))
45 .layer(compression)
46}
01 / 01
STEP 01
‹ swipe to step through ›
Walkthrough
Space play
←→ step
click any line
Three takeaways
- 1A tower-http layer wraps every route so cross-cutting concerns like compression live outside handler logic.
- 2Compression predicates let you skip payloads that won't benefit — small bodies, already-compressed images, or gRPC.
- 3Enabling multiple encodings lets the layer negotiate the best one against each client's Accept-Encoding header.
Related explainers
rust
use serde::Deserialize; #[derive(Debug, Deserialize)] #[serde(untagged)]
Parsing flexible JSON shapes with serde
deserialization
enums
json
Intermediate
6 steps
rust
use std::cmp::{Ordering, Reverse}; use std::collections::BinaryHeap; use std::fs::File; use std::io::{self, BufRead, BufReader, BufWriter, Lines, Write};
K-way merge of sorted logs in Rust
binary-heap
k-way-merge
streaming-io
Intermediate
8 steps
python
import time import uuid from django.utils.deprecation import MiddlewareMixin
Attaching per-request context in Django
middleware
request lifecycle
multi-tenancy
Intermediate
7 steps
rust
use axum::{ extract::{Path, State}, response::sse::{Event, KeepAlive, Sse}, };
Streaming import progress with SSE in Axum
server-sent-events
streams
watch-channel
Advanced
7 steps
rust
use std::f64::consts::PI; #[derive(Debug, Clone, Copy)] pub struct LatLng {
Building geographic bounding boxes in Rust
geospatial
value-types
option
Intermediate
7 steps
rust
use chrono::{Duration, NaiveDate}; #[derive(Debug)] pub struct DateRange {
Parsing and iterating date ranges in Rust
error-handling
iterators
parsing
Intermediate
7 steps
Share this explainer
Here's the card — post it anywhere.
Made with highlit — turn any snippet into a walkthrough like this in about a minute.
Explain your code
Embed this explainer
Drop the interactive walkthrough into a blog or docs. Views never cost a credit.
<iframe src="https://highlit.co/explainers/response-compression-in-axum-with-tower-http-explained-rust-da11/embed?autoplay=1" width="100%" height="520" loading="lazy" style="border:0"></iframe>
Autoplay is on by default — add ?autoplay=0 to start paused.