I am trying to integrate compojure-api (version 1.1.12) into an existing compojure-based application. While most things work, I am having an issue with request coercions on an existing REST call whose usage would be difficult to change at this point.
- It's a POST
- It expects parameters via multipart/form-data
- Most parameters are optional.
- Most parameters are simple: string or array of string.
- One optional parameter is expected to be a JSON-encoded map.
I define the route like this:
(POST "/endpoint" request
:multipart-params
[required-strings :- (describe [s/Str] "Required, an array of strings"),
{optional-string :- (describe s/Str "An optional string") ""},
{others :- {s/Keyword s/Any} {}}]
...)
This works, unless I try to pass other-parameters
in a request. For example, via curl:
curl -F "required-strings=[\"Hello\"]" -F "others={\"a\":1.0}" ...
This results in an invalid request (i.e. status 400) error with the content:
{"errors":{"others":"(not (map? a-clojure.lang.PersistentVector))"}}
I'm using ring-default's site-defaults
, and I haven't modified the default coercions for the compojure api. I've traced the error to compojure.api.coerce/coerce
. I can see the value that the coercer is working on, and it looks like:
{:required-strings "[\"Hello\"]"
:others "{\"a\":1.0}"}
On line 59 of coerce.clj, (coerce value)
returns an error (per schema.utils/error?
).
So, is it not possible to coerce a JSON-encoded multipart parameter to a Clojure map? I can define the parameter to be a string instead of a map, and do the parsing myself, but this defeats the purpose of using compojure-api and ring-swagger.