Json in Clojure

Here’s the translation of the JSON example from Go to Clojure, formatted in Markdown suitable for Hugo:

(ns json-example
  (:require [clojure.data.json :as json]
            [clojure.java.io :as io]))

;; We'll use these two records to demonstrate encoding and
;; decoding of custom types below.
(defrecord Response1 [page fruits])

;; In Clojure, we don't need to explicitly define the structure,
;; but we'll use a map with keys that match the JSON field names.

(defn main []
  ;; First we'll look at encoding basic data types to
  ;; JSON strings. Here are some examples for atomic values.
  (println (json/write-str true))
  (println (json/write-str 1))
  (println (json/write-str 2.34))
  (println (json/write-str "gopher"))

  ;; And here are some for vectors and maps, which encode
  ;; to JSON arrays and objects as you'd expect.
  (println (json/write-str ["apple" "peach" "pear"]))
  (println (json/write-str {"apple" 5 "lettuce" 7}))

  ;; The JSON library can automatically encode your
  ;; custom data types.
  (let [res1 (->Response1 1 ["apple" "peach" "pear"])]
    (println (json/write-str res1)))

  ;; In Clojure, we don't need special tags for customizing
  ;; JSON key names. We can just use a map with the desired keys.
  (let [res2 {:page 1 :fruits ["apple" "peach" "pear"]}]
    (println (json/write-str res2)))

  ;; Now let's look at decoding JSON data into Clojure
  ;; values. Here's an example for a generic data structure.
  (let [byt "{\"num\":6.13,\"strs\":[\"a\",\"b\"]}"
        dat (json/read-str byt)]
    (println dat)
    ;; In Clojure, we can access nested data directly
    (println (get dat "num"))
    (println (first (get dat "strs"))))

  ;; We can also decode JSON into custom data types.
  (let [str "{\"page\": 1, \"fruits\": [\"apple\", \"peach\"]}"
        res (json/read-str str :key-fn keyword)]
    (println res)
    (println (first (:fruits res))))

  ;; In Clojure, we can write JSON directly to output streams.
  (json/write {"apple" 5 "lettuce" 7} *out*))

(main)

This Clojure code demonstrates JSON encoding and decoding, similar to the Go example. Here are some key points:

  1. We use the clojure.data.json library for JSON operations.

  2. Clojure’s data structures (maps and vectors) naturally correspond to JSON objects and arrays.

  3. We define a Response1 record to demonstrate custom type encoding, but for response2, we simply use a map.

  4. Clojure’s json/write-str and json/read-str functions are used for encoding and decoding JSON.

  5. When decoding JSON, we can use the :key-fn keyword option to automatically convert keys to keywords.

  6. Clojure allows direct access to nested data structures without explicit type assertions.

  7. We can write JSON directly to output streams using json/write.

To run this program, you would typically save it in a file (e.g., json_example.clj) and run it using a Clojure runtime environment. The output would be similar to the Go example, showing various JSON encoding and decoding operations.

Remember to add the necessary dependency for clojure.data.json in your project configuration if you’re using a build tool like Leiningen or deps.edn.