Fork me on GitHub
#reitit
<
2020-02-24
>
markbastian23:02:55

I'm running into a very interesting coercion issue and I'm wondering if anyone here can help me see what I'm doing wrong or if there's a workaround. Here's my basic router:

(def handler
  (ring/ring-handler
    (ring/router
      ["/api"
       {:coercion   spec-coercion/coercion
        :middleware [parameters/parameters-middleware           ;; query-params & form-params
                     coercion/coerce-request-middleware         ;; coercing request parameters
                 ]}
       ["/foo"
        {:post {:parameters {:consumes "application/x-www-form-urlencoded"
                             :form     {:ids [int?]}}
                :handler    (fn [{{{:keys [ids]} :form} :parameters}]
                              (ok (str ids)))}}]
       ])))
There's one endpoint, "/api/foo" that expects a collection of ints. When I call it with various params I get the following results:
(comment
  (require '[ring.mock.request :as mock])
  ;I expect this to fail
  (handler (mock/request :post "/api/foo" {:ids 1}))
  ;Why does this fail?
  (handler (mock/request :post "/api/foo" {:ids [1]}))
  ;These two pass
  (handler (mock/request :post "/api/foo" {:ids [1 3]}))
  (handler (mock/request :post "/api/foo" {:ids [1 2 3]}))
  )
The odd case that I can't understand is the second one. When I call the endpoint with a sequence of one element something in the handler appears to be converting the [1] into a 1. Is this a known or expected behavior? Any workarounds? I've tried adding a spec like (s/or :int int? :ints (s/+ int?)) but that didn't work. If it would be helpful to list the requires vector I can provide that, too. Thanks!

bartuka23:02:28

I manage to reproduce your error, it seems odd indeed. Which is interesting is that when you use swagger support, the way it handles x-www-form-urlencoded input type is by separating each value in a newline, therefore I cannot be sure if I express in a swagger interface your second case correctly. I manage to workaround the problem with the following spec: (s/or :int int? :ints (s/coll-of int?)) but your first two cases will be handled equally.

👍 4