Muuntaja has been built with performance in mind, while still doing mostly everything in Clojure:
- single middleware/interceptor for all formats (instead of stacked middleware)
- avoid run-time regexps
- avoid dynamic bindings
- avoid Clojure (map) destructuring
- (Java-backed) memoized content negotiation
- Protocols over Multimethods
- Records over Maps
- use field access instead of lookups
- keep all core functions small enough to enable JVM Inlining
- unroll generic functions (like
get-in
) - use streaming when possible
The codebase contains the performance test, done using Criterium under the perf
Leiningen profile with a 2013 Mackbook pro.
NOTE: Tests are not scientific proof and may contain errors. If you have idea how to test things better, please poke us.
Muuntaja is tested against the current common ring-based formatters. It's fastest in all tests.
- ok performance by default, but only provide a single format - Stacking these separate middleware makes the pipeline slower.
- has really bad defaults:
- with 1K JSON, Muuntaja is 10-30x faster (depending on the JSON encoder used)
- with 100k JSON, Muuntaja is still 2-4x faster
- with tuned r-m-f options
- with <1K messages, Muuntaja is still much faster
- similar perf on large messages
Pedestal:
io.pedestal.http.content-negotiation/negotiate-content
for content negotiationio.pedestal.http.body-params/body-params
for decoding the request bodyio.pedestal.http/json-body
,io.pedestal.http/transit-json-body
etc. to encode responses
Muuntaja:
muuntaja.interceptor/format-negotiate
for content negotiationmuuntaja.interceptor/format-request
for decoding request bodymuuntaja.interceptor/format-response
to encode responsesmuuntaja.interceptor/format
all on one step