12

I'm trying to use ring-json's wrap-json-response middleware within my compojure app. I have a simple GET handler that returns a map, like {:foo 1}, and when I hit the URL, ring responds with text/plain and an empty response body. I can't seem to get it to respond with the JSON version of the map.

Here's my handler code:

(ns localshop.handler
  (:use compojure.core)
  (:require [localshop.routes.api.items :as routes-api-items]
            [ring.middleware.json :as middleware]
            [compojure.handler :as handler]
            [compojure.route :as route]))

;; map the route handlers
(defroutes app-routes
  (context "/api/item" [] routes-api-items/routes))

;; define the ring application
(def app
  (-> (handler/api app-routes)
      (middleware/wrap-json-body)
      (middleware/wrap-json-params)
      (middleware/wrap-json-response)))

The route handler function literally just returns a map, so the code for that is simple enough that I think I could leave out. If returning a map from a compojure route handler is the problem, then perhaps that's it?

halfer
  • 19,824
  • 17
  • 99
  • 186
Ryan
  • 7,733
  • 10
  • 61
  • 106

2 Answers2

16

Check out this. Basically if you return {:body {:my-map "hello"}} then it will work fine.

Ankur
  • 33,367
  • 2
  • 46
  • 72
  • 3
    Thanks for this anwser, I was pulling my hair out. This really should have been better documented. – jd. Mar 18 '13 at 05:28
  • Any idea why it must be wrap within :body? – Teo Choong Ping Jul 18 '13 at 06:44
  • 2
    My best guess would be because the method could allow more options other than a response's body, so it demands you implicitly specify `{:body {}}`. – film42 Sep 26 '13 at 03:03
  • The reason why this is needed is that Compojure and Ring are (implicitly) expecting an HTTP response. The fact that they handle simple types automagically is the source of the confusion. See [my answer](http://stackoverflow.com/a/24212869/173497) to [a somewhat-related question](http://stackoverflow.com/q/22798004/173497). – Kenny Evitt Jul 12 '14 at 18:45
  • Which commit hash did you mean? – opyate May 31 '15 at 19:36
  • by default, a string is converted to a response {:status 200, :body string}. but your handler might want to explicitly return a response with other interesting properties, eg status codes different from 200 (400, 301, etc), interesting headers, and so on. Since a response is also just a map, this would be impossible if all maps were treated as the body of an OK json response – ealfonso Aug 17 '16 at 00:01
1

Stumbe similar issue, when writing REST API.

When handler return vector, i get exception that no implementation of method render for PersistentVector in Renderable protocol in compojure.

When return map, headers is empty.

When return sequence, i get 'text/html'. So, i think it's good to be extend Renderable in our code: really nice gift from clojure.

But, as hack, for fast solution, i use next middleware:

(defn wrap-content-json [h]
  (fn [req] (assoc-in (h req) [:headers "Content-Type"] "application/json")))
Intey
  • 71
  • 6