reitit icon indicating copy to clipboard operation
reitit copied to clipboard

Example in readme doesn't produce expected (documented) output due to middleware

Open drewverlee opened this issue 4 years ago • 1 comments

The example in the readme puts the reitit.ring.coercion/coerce-response-middleware before muutaja/format-response-middleware which I believe is the reason for the exception thrown below. Simple reversing the order

muuntaja/format-response-middleware rrc/coerce-response-middleware

;; => {:status 200, :body #object[java.io.ByteArrayInputStream 0x64b0079d "java.io.ByteArrayInputStream@64b0079d"], :headers {"Content-Type" "application/json; charset=utf-8"}}

Though not the output in the readme:

;; => {:status 200, :body {:total 3}}

Which I would think would require not having the format-response-middleware.

(def app
  (ring/ring-handler
    (ring/router
      ["/api"
       ["/math" {:get {:parameters {:query {:x int?, :y int?}}
                       :responses  {200 {:body {:total int?}}}
                       :handler    (fn [{{{:keys [x y]} :query} :parameters}]
                                     {:status 200
                                      :body   {:total (+ x y)}})}}]]
      ;; router data affecting all routes
      {:data {:coercion   reitit.coercion.spec/coercion
              :muuntaja   m/instance
              :middleware [parameters/parameters-middleware
                           rrc/coerce-request-middleware
                           rrc/coerce-response-middleware
                           muuntaja/format-response-middleware]}})))


(app {:request-method :get
      :uri            "/api/math"
      :query-params   {:x "1", :y "2"}})
 


Throws:

Execution error (ExceptionInfo) at reitit.coercion/response-coercion-failed! (coercion.cljc:58).
Response coercion failed: #reitit.coercion.CoercionError{:spec #Spec{:form (clojure.spec.alpha/keys :req-un [:spec$15925/total]), :type :map, :leaf? false}, :problems #:clojure.spec.alpha{:problems ({:path [], :pred clojure.core/map?, :val #object[java.io.ByteArrayInputStream 0x468ef8f1 "java.io.ByteArrayInputStream@468ef8f1"], :via [], :in []}), :spec #Spec{:form (clojure.spec.alpha/keys :req-un [:spec$15925/total]), :type :map, :leaf? false}, :value #object[java.io.ByteArrayInputStream 0x468ef8f1 "java.io.ByteArrayInputStream@468ef8f1"]}}

If I understand this problem correctly, ill go ahead about update the README. I would likely leave the format-response-middleware out and mention it as an a necessary addition.

drewverlee avatar May 10 '21 21:05 drewverlee

Reviewing the muuntaja examples, I assume that the muuntaja/format-response-middleware is calling the muuntaja encode function (or something similar) that creates a #object[java.io.ByteArrayInputStream]

So in the README example, either the muuntaja/format-response-middleware could be removed and the response is not encoded (probably not very efficient).

Or the result of the request could be decoded

(->>
  (app {:request-method :get
        :uri "/api/math"
        :query-params {:x "1", :y "2"}})
  :body
  (m/decode (m/create) "application/json"))

Or slurp could be used to read in the ByteArrayInputStream object

(->>
  (app {:request-method :get
        :uri "/api/math"
        :query-params {:x "1", :y "2"}})
  :body
  slurp)

I am unsure if there is a better alternative to these. The slurp approach seems to be the simplest.

practicalli-johnny avatar Aug 22 '21 21:08 practicalli-johnny