November 24, 2020
Extending transit in action
Figuring out how to extend transit with cljs-ajax and reitit was a bit of a challenge. So I’m writing it here for future reference, and hopefully others can benefit from it as well.
For this example we will use tick for our extension.
cljs-ajax
(ns example
(:require [ajax.core :as ajax]
[ajax.interceptors :as ajax-interceptors]
[ajax.transit :as ajax-transit]
[clojure.string :as str]
[cognitect.transit :as transit]
[java.time]
[tick.alpha.api :as t]))
(defn time-fn [obj]
(str obj))
(defn rep [text]
(fn [& _]
text))
(def write-handlers {java.time/Instant (transit/write-handler (rep "tick/instant") time-fn)
java.time/Month (transit/write-handler (rep "tick/month") time-fn)
java.time/DayOfWeek (transit/write-handler (rep "tick/day-of-week") time-fn)
java.time/Year (transit/write-handler (rep "tick/year") time-fn)})
(def writer (transit/writer :json {:handlers write-handlers}))
(def read-handlers {"tick/instant" (transit/read-handler (fn [obj] (t/instant obj)))
"tick/month" (transit/read-handler (fn [obj] (t/month obj)))
"tick/day-of-week" (transit/read-handler (fn [obj] (t/day-of-week obj)))
"tick/year" (transit/read-handler (fn [obj] (t/year obj)))})
(def response-format (ajax-interceptors/map->ResponseFormat
{:content-type ["application/transit+json"]
:description "Transit response"
:read (ajax-transit/transit-read-fn {:handlers read-handlers})}))
(ajax/GET "your-url-here"
{:writer writer
:response-format response-format
:params {:q "somevalue"}
:handler (fn [response]
(println response))}
reitit
(ns example
(:require [cognitect.transit :as transit]
[muuntaja.core :as m]
[tick.alpha.api :as t])
(defn time-fn [o]
(str o))
(def transit-encoder-handlers {java.time.Instant (transit/write-handler "tick/instant" time-fn)
java.time.Month (transit/write-handler "tick/month" time-fn)
java.time.DayOfWeek (transit/write-handler "tick/day-of-week" time-fn)
java.time.Year (transit/write-handler "tick/year" time-fn)})
(def transit-decoder-handlers {"tick/instant" (transit/read-handler (fn [x] (t/instant x)))
"tick/month" (transit/read-handler (fn [x] (t/month x)))
"tick/day-of-week" (transit/read-handler (fn [x] (t/day-of-week x)))
"tick/year" (transit/read-handler (fn [x] (t/year x)))})
;; use muuntaja-instance in the muuntaja ring router instead of the default one
;; used in the examples given in the reitit documenation
(def muuntaja-instance
(-> m/default-options
(update-in [:formats] dissoc "application/transit+msgpack" "application/edn")
(assoc :charsets #{"utf-8"} )
(update-in [:formats "application/transit+json"] assoc
:encoder-opts {:handlers transit-encoder-handlers}
:decoder-opts {:handlers transit-decoder-handlers})
(m/create)))
That’s it. Happy hacking.