Compojure-api: запрос приведения для карты, предоставленной через multipart-params

Я пытаюсь интегрировать compojure-api (версия 1.1.12) в существующее приложение, основанное на compojure. Хотя большинство вещей работает, у меня возникла проблема с приведениями запросов к существующему вызову REST, использование которого было бы трудно изменить на данном этапе.

  • Это ПОСТ
  • Ожидает параметры через multipart/form-data
  • Большинство параметров не являются обязательными.
  • Большинство параметров просты: строка или массив строк.
  • Предполагается, что одним необязательным параметром будет JSON-кодированная карта.

Я определяю маршрут так:

(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} {}}]
    ...)

Это работает, если я не пытаюсь пройти other-parameters в запросе. Например, через curl:

curl -F "required-strings=[\"Hello\"]" -F "others={\"a\":1.0}" ...

Это приводит к ошибке недопустимого запроса (т.е. статус 400) с содержимым:

{"errors":{"others":"(not (map? a-clojure.lang.PersistentVector))"}}

Я использую кольцо по умолчанию site-defaults, и я не изменил принуждения по умолчанию для API compojure. Я проследил ошибку compojure.api.coerce/coerce, Я вижу значение, над которым работает coercer, и это выглядит так:

{:required-strings "[\"Hello\"]"
 :others "{\"a\":1.0}"}

В строке 59 coerce.clj, (coerce value) возвращает ошибку (за schema.utils/error?).

Итак, нельзя ли принудительно включить JSON-закодированный многокомпонентный параметр в карту Clojure? Я могу определить параметр как строку вместо карты и выполнить синтаксический анализ самостоятельно, но это противоречит цели использования compojure-api и ring-swagger.

1 ответ

Привязка для others ожидает карту замыкания, а не строку. Чтобы это работало, у вас есть варианты.

Первый вариант: добавить промежуточное ПО wrap-json-params и сделать application/json запрос вместо multipart/form-data:

curl ... -H 'Content-Type: application/json' \
     -d $'{
  "required-strings": ["Hello"],
  "others": {"a": 1.0}
}'

Второй вариант: добавить промежуточное ПО wrap-nested-params и multipart/form-data запрос с использованием вложенных имен параметров:

curl ... -H 'Content-Type: multipart/form-data' \
     -F "required-strings[]=Hello" \
     -F "others[a]=1.0" 
Другие вопросы по тегам