Transit format: An interactive tutorial - better than JSON (part 1)
source link: https://blog.klipse.tech/clojure/2016/09/22/transit-clojure.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
Transit format: An interactive tutorial - better than JSON (part 1)
Sep 22, 2016 • Yehonathan Sharvit
What is Transit?
Transit is a format and set of libraries for conveying values between applications written in different programming languages.
Transit provides:
- a set of basic elements
- a set of extension elements for representing typed values.
The extension mechanism is open, allowing programs using Transit
to add new elements specific to their needs. It constrats with traditional formats where usually users of data formats must rely on one of the following:
- schemas
- convention
- context
to convey elements not included in the base set, making application code much more complex.
Transit
is designed to be implemented as an encoding on top of formats for which high performance processors already exist, specifically JSON
and MessagePack
. Transit uses these formats’ native representations for built-in elements, e.g., strings and arrays, wherever possible. Extension elements which have no native representation in these formats, e.g., dates, are represented using a tag-based encoding scheme. It makes Transit
a self-describing and extensible format.
Read more about Transit.
Code examples please
All the above is very very abstract. Let’s code some examples.
In this article, we are going to use transit-cljs to illustrate Transit
format.
As usual, the code snippets are interactive - powered by the KLIPSE plugin. Feel free to modify the code in order to get a better feeling of the concepts.
First, let’s require transit
:
xxxxxxxxxx
(ns my.transit
(:require [cognitect.transit :as t]))
the evaluation will appear here (soon)...
Now, we can play with transit
…
Let’s create a JSON
reader and writer:
xxxxxxxxxx
(def r (t/reader :json))
(def w (t/writer :json))
xxxxxxxxxx
the evaluation will appear here (soon)...
And let’s see them in action:
Reader - basics
The reader receives a string in json
format, and returns a clojure object:
Any type supported in json
can go in…
Arrays, numbers, unicode strings, booleans, null
:
xxxxxxxxxx
(t/read r "[1, \"2\", null, true, \"\u03BB\"]")
xxxxxxxxxx
the evaluation will appear here (soon)...
and obviously objects:
xxxxxxxxxx
(t/read r "{\"a\": 1, \"b\": [1, 2.2, 2e5, null]}")
xxxxxxxxxx
the evaluation will appear here (soon)...
Writer - basics
The writer is the opposite of the writer: it receives a clojure
object and returns a string in json
format:
Let’s write a clojure
array:
xxxxxxxxxx
(t/write w [1 1.2e4 "2" nil true])
xxxxxxxxxx
the evaluation will appear here (soon)...
And a clojure
object:
xxxxxxxxxx
(t/write w {"a" 1, "b" [1 2.2 200000 nil]})
xxxxxxxxxx
the evaluation will appear here (soon)...
Additional types
The interest of transit
is that it supports additional types that are not supported in JSON
like: keywords, symbols, dates, sets, lists:
Let’s see how keywords are encoded:
xxxxxxxxxx
(t/write w [:aaa :bbb :my.ns/bbb ::aaa])
xxxxxxxxxx
the evaluation will appear here (soon)...
Symbols:
xxxxxxxxxx
(t/write w ['aa 'bb])
xxxxxxxxxx
the evaluation will appear here (soon)...
Dates:
xxxxxxxxxx
(t/write w [(js/Date) #inst "2016-09-22T18:27:18.001-00:00"])
xxxxxxxxxx
the evaluation will appear here (soon)...
Sets:
xxxxxxxxxx
(t/write w #{1 2 3})
xxxxxxxxxx
the evaluation will appear here (soon)...
UUIDs:
xxxxxxxxxx
(t/write w (random-uuid))
xxxxxxxxxx
the evaluation will appear here (soon)...
Each of the above strings can be decoded back into a clojure
object with the writer:
xxxxxxxxxx
(t/read r (t/write w [(js/Date) #inst "2016-09-22T18:27:18.001-00:00"]))
xxxxxxxxxx
the evaluation will appear here (soon)...
xxxxxxxxxx
(t/read r (t/write w #{1 2 3}))
xxxxxxxxxx
the evaluation will appear here (soon)...
Any keys in an object
JSON suports only strings in keys. However in clojure
, any type can be a key in a map
. It means that we cannot truly serialize a clojure
map. Usually, the trick is to convert types into strings. Like this:
xxxxxxxxxx
(def array-key-map {[1 2] "cool"})
(-> array-key-map
clj->js
js/JSON.stringify)
xxxxxxxxxx
the evaluation will appear here (soon)...
But when we read the string back, we don’t get the original object:
xxxxxxxxxx
(-> array-key-map
clj->js
js/JSON.stringify
js/JSON.parse
js->clj)
xxxxxxxxxx
the evaluation will appear here (soon)...
Transit
solves this problem by encoding the types:
xxxxxxxxxx
(t/write w array-key-map)
xxxxxxxxxx
the evaluation will appear here (soon)...
And the roundtrip is safe:
xxxxxxxxxx
(t/read r (t/write w array-key-map))
xxxxxxxxxx
the evaluation will appear here (soon)...
In our next article , we are going to show how Transit
deals with custom handlers and caching. You will see that in some cases, Transit
is more efficient that JSON
!
to stay up-to-date with the coolest interactive articles around the world.
Discover more cool interactive articles about javascript, clojure[script], python, ruby, scheme, c++ and even brainfuck!
Give Klipse a Github star to express how much you appreciate Code Interactivity.
Subscribe to the Klipse newsletter:Feel free to email me [email protected] for getting practical tips and tricks in writing your first interactive blog post.
Recommend
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK