How to write instants for transit responses?

My front-end requests transit for its format. My back end attempt to sent something including a field :created #time/instant "2020-04-26T07:29:58.413Z". Upon attempting to send the data, JVM cries out:

java.lang.RuntimeException: java.lang.Exception: Not supported: class java.time.Instant
	at com.cognitect.transit.impl.WriterFactory$1.write(WriterFactory.java:65)

I’m using ring.middleware.format/wrap-restful-format so I would think the answer would somehow be in connection with that… how can I get over this error to successfully send my data with transit?

Think you just need transit encodings? See the gist linked in this issue https://github.com/henryw374/time-literals/issues/2

2 Likes

I think your answer is probably correct, but it was unclear to me how to implement it into my middleware. Unfortunately, given time constraints, the simplest answer was simply “don’t use transit.” I changed the request format to JSON and everything simply worked.

I struggled with the same and came up with the following simplified solution:

Backend, using muuntaja for encoding-decoding:

(ns example.backend
  (:require
   [muuntaja.middleware :as mw]
   [muuntaja.core :as m])
  (:import [java.time Instant]))

(def format-options
  (-> m/default-options
      (update-in [:formats "application/transit+json" :encoder-opts]
                 (partial merge {:handlers
                                 {Instant (transit/write-handler (constantly "Instant")
                                                                 #(.toString %))}}))
      (update-in [:formats "application/transit+json" :decoder-opts]
                 (partial merge {:handlers
                                 {"Instant" (transit/read-handler #(Instant/parse %))}}))))

;; Then in the middleware chain:
(mw/wrap-format-response format-options)

Frontend, using cljs-http:

(ns example.frontend
  (:require [cognitect.transit :as transit]
            [cljs-http.client :as http]))

(def transit-opts
  {:encoding-opts
   {:handlers
    {js/Date (transit/write-handler (constantly "Instant") #(.toISOString %))}}

   :decoding-opts
   {:handlers
    {"Instant" (transit/read-handler #(js/Date. %))}}})

;; Then to perform a request:
(http/request {:method :get
               :url "/api/something/"
               :transit-opts transit-opts
               :accept "application/transit+json"}))

That’s beautiful. Thank you! One more reason to learn and whip out Muuntaja now.

1 Like