If you’re a ClojureScript user transit-cljs offers nearly all the benefits of EDN while delivering performance comparable to native JSON. And since the Transit JSON encoding is truly just JSON, transit-cljs also provides a better story when communicating with existing JSON services.
ClojureScript launched more than 3 years ago with
cljs.reader/read-string
. This allowed Clojure and ClojureScript programs to comfortably communicate
with each other. However, even after seeing several rounds of optimizations
cljs.reader/read-string
still delivers poor performance compared to
JSON.parse
.
Worse, most services speak JSON not EDN. You can JSON.parse
and convert to
ClojureScript data structures via
cljs.core/js->clj
but performance is even worse than cljs.reader/read-string
.
transit-cljs addresses all of these issues at once.
You can consume any existing JSON service in ClojureScript with transit-cljs and
you will get ClojureScript data structures. The performance is 20-30X faster
than combining JSON.parse
with cljs.core/js->clj
.
(def r (transit/reader :json))
(println (transit/read r "{\"foo\":\"bar\"}"))
The only caveat is that map keys will be strings - a small price to pay for the performance gain.
You can send JSON to any service simply by using a verbose writer:
(def w (transit/writer :json-verbose))
(println (transit/write w {"foo" "bar"}))
Again your map keys must be strings but encoding is often more than a magnitude
faster than cljs.core/pr-str
.
transit-cljs offers benefits above and beyond those provided by
transit-js. transit-js is consumed by JavaScript applications developers as a
Google Closure Compiler advanced compiled artifact. But because Google Closure
Compiler is already a part of the ClojureScript compilation pipeline,
transit-cljs depends directly on the original unoptimized and unminified
transit-js source code. This means far more of the transit-js implementation
can be leveraged - for example transit-js 64 bit
integers are goog.math.Long
instances and you can treat them as such with
no issues:
(ns transit-fun.core
(:require [cognitect.transit :as t])
(:import [goog.math Long]))
(def r (t/reader :json))
(.add (t/read r "{\"~#':\":\"~i9007199254740993\"\"}") (Long.fromInt 1))
Of course the most ideal scenario is to just expose your API optionally as a Transit service alongside the plain JSON service as this delivers the best read performance for clients.
If you are a ClojureScript user building an application that accepts or marshals either EDN or JSON I strongly recommend switching to transit-cljs for both tasks.