How do I receive edn using a POST handler in Clojure? (and how do I send it)

717 views Asked by At

I am sending a map via a POST using cljs-http and I want to receive it with a Compojure POST handler and store it in a database. I'm totally confused as what I am supposed to do with the map in transit... there are a lot of options... pr-str, prn, read-string and on and on. On the sending side, it seems cljs-http might coerce my map into edn on it's own. I have no way of knowing without a working Compojure handler. Actually, to be honest, I'm still a bit unclear on what edn is. It's Clojure's data format, that I gather. As far as I can tell, what I am dealing with is actually just converting edn into a string format for shipping and back out. However, the :data value on the request is an object, not a string. A working example of a cljs-http POST and a Compojure POST handler that allows me to work with the original map sent by the client would be awesome. I don't know the purpose of :edn-params in my

(http/post "/test" (:edn-params (prn-str {:hey "there"})))

or if I should be using something else. I am used to JSON and am wondering if I should just be converting the data to JSON and back out on the receiving side. I'm unsure of the advantages of using edn.

On the receiving side I have:

(defroutes handler
  (GET "/about" [] "<h1>Hello World</h1>")
  (POST "/test" req (prn (read (:body req))))
  (route/not-found "<h1>Page not found</h1>"))

I know this likely wrong... but I thought I'd share where I am at.

UPDATE: After some thought, the title should have been 'What is the best way to send maps between a Reagent app and a server?". I just need to be able to send a map to a server, and make requests to that server and get a map back.

1

There are 1 answers

2
Steffan Westcott On BEST ANSWER

It is typical to encode EDN using Transit for HTTP transfer. Support for content (HTTP body) encoding and decoding is commonplace in clients and servers.

According to the documentation for cljs-http, to POST a request using Transit+JSON i.e. content-type is application/transit+json:

(http/post "http://example.com" {:transit-params {:key1 "value1" :key2 "value2"}})

In a Ring-compliant server, you would typically use middleware to deal with content format negotiation, content encoding and decoding. You could use metosin/muuntaja which supports JSON, EDN and Transit. There's a code sample which shows how to use it in the context of a Ring-compliant server.

EDN is a subset of Clojure, typically used when conveying values between Clojure(Script) programs. It is possible to use application/edn as a HTTP content type, but to do so would miss out on the huge support and processing optimisation that JSON content has.

A naïve translation from EDN to JSON leads to questions around how things like Clojure keywords, sets, etc. are handled. Transit resolves these issues by defining an open format (and libraries) where any values can be encoded. In particular, it enables EDN to be encoded to a JSON (or MessagePack) format. Put another way, the conveyed EDN piggybacks on JSON while in transit.