Как вернуть данные JSON из поста! Обработчик в clojure освободителя?
Как вернуть json-данные с помощью Clojure Liberator? Этот код не работает:
(defresource poster []
:allowed-methods [:post :options]
:available-media-types ["application/json"]
:post! (fn [ctx] (println "posting..."))
:handle-created (fn [ctx] {:created "ok"}))
Должен ли быть обработан дескриптор после записи?
3 ответа
Функция, связанная с :post!
ключ не является функцией обработчика Документация Liberator называет это функцией действия.
Функции действий Клавиши: пост!,: положить! и: удалить! обеспечить точки, которые хорошо подходят для принятия побочных эффектов. Хотя они оцениваются как функции принятия решения, логическое значение не имеет никакого эффекта, и следующий шаг принятия решения является постоянным. Обновление контекста работает точно так же, как для функций принятия решений.
Таким образом, вы не можете сгенерировать http-ответ непосредственно из функции, связанной с :post!
,
Функция, связанная с :post!
ключ может вернуть что-то и что-то будет слито в контекст.
Обновление контекста работает точно так же, как для функций принятия решений.
Затем функция-обработчик может позже извлечь это из контекста и использовать его для формирования http-ответа. Вполне возможно, что любая из функций-обработчиков, связанных с этими ключами, могла бы выполняться впоследствии: :handle-ok
, :handle-created
, :handle-no-content
, :handle-see-other
, :handle-multiple-representations
Этот граф решений определяет, какой обработчик будет выполняться.
Вероятно, лучше всего просто ответить заголовком местоположения, указывающим на только что созданный ресурс, но без тела, но вот один из примеров создания ответа с телом JSON и состоянием 201.
(POST "/foo" [] (resource :allowed-methods [:post]
:available-media-types ["application/json"]
:handle-created {:created "ok"}))
Опробовать это:
curl -X POST "localhost/foo"
{"created":"ok"}
Вы можете увидеть, какую библиотеку JSON использует Liberator в своем файле project.clj. Если вы хотите создать строки JSON самостоятельно, вы можете сделать это следующим образом:
:handle-created (fn [ctx] (liberator.representation/ring-response
{:status 201 :body "{created:\"ok\"}"}))
Здесь упоминается
Я так и делаю - похоже, это работает, но я только начал использовать Liberator, так что, возможно, есть лучшие или более правильные способы сделать это!
Я думаю, что вам нужен обработчик, созданный дескриптором. Например -
(defresource shopping-calc
:allowed-methods [:post]
:available-media-types ["application/json"]
:malformed? (fn [context]
(let [params (get-in context [:request :params])]
(or (empty? params)
(is-malformed? params))))
:handle-malformed (fn [context]
(let [params (get-in context [:request :params])]
(generate-string (handle-malformed-calc params))))
:handle-created (fn [context]
(let [params (get-in context [:request :params])]
(generate-string (calculate-total params)))))
и у меня есть обработчик, созданный обработчиком, как это
(defn calculate-total [params]
{:total (calc params)})
Я также использую промежуточное программное обеспечение ring/json и в своей среде разработки добавляю средство трассировки освобождения. Средство трассировки Liberator очень удобно, поскольку оно добавляет заголовки к ответу, которые показывают точки принятия решения для Liberator. Таким образом, для вашей проблемы это, вероятно, показало бы, что Liberator использовал обработчик, созданный по умолчанию для дескриптора, который просто возвращает заголовки. Чтобы вернуть свой собственный json, вам нужно определить обработчик.
Обратите внимание, что я не использую этот пост! метод. Это потому, что в этом примере я на самом деле не создаю какой-то новый объект / элемент, такой как добавление записи в какое-то хранилище. Если бы вы делали это, то вы могли бы использовать пост! добавить запись и определить созданный дескриптором, чтобы затем получить новую запись (возможно, с другими новыми полями, такими как идентификатор записи или метка времени и т. д.) и вернуть ее.
Я использую: неправильно сформирован? и handle-malformed, чтобы выполнить базовую проверку ошибок. Если: неправильно сформирован? возвращает true, вызывается некорректно сформированный заголовок, который возвращает состояние ошибки и сообщение об ошибке в теле json. Я считаю, что очень помогает возвращать ваши ошибки также в json, чтобы вы могли последовательно обрабатывать все на стороне клиента.
Мои определения обработчиков и промежуточного программного обеспечения приведены ниже. Обратите внимание, что, поскольку я обслуживаю как приложения, так и маршруты API, они немного сложнее, потому что я хочу, чтобы какое-то промежуточное программное обеспечение применялось к некоторым маршрутам, а другое промежуточное ПО применялось к другим. Есть также небольшая ошибка в ring / ring-defaults, которая, однажды исправленная, изменит вещи, так как в настоящее время я не могу использовать промежуточное ПО site-api wrap-defaults. Обратите внимание на промежуточное ПО wrap-trace.
(def app
(if (env :dev)
(routes (-> api-routes
(wrap-reload)
(wrap-routes wrap-json-params)
(wrap-routes wrap-defaults api-defaults)
(wrap-routes wrap-trace :header :ui))
(-> app-routes
(wrap-routes wrap-error-page)
(wrap-routes wrap-exceptions)))
(routes (-> api-routes
(wrap-routes wrap-json-params)
(wrap-routes wrap-defaults api-defaults))
app-routes)))
Код 201 created
используется для возврата ссылок на вновь созданный ресурс в теле вместе с заголовком Location. Если вы хотите вернуть вновь созданный ресурс в тело, вы должны использовать 200 ok
, По умолчанию Liberator в конечном итоге 204 no-content
после ПОСТ. Вам нужно будет установить :respond-with-entity? true
,
Ваше определение ресурса будет выглядеть так:
(defresource poster []
:allowed-methods [:post :options]
:available-media-types ["application/json"]
:malformed? (fn [ctx]
[false {::resource (parse-json (get-in ctx [:request :body]))}])
:post! (fn [ctx]
(persist (::resource ctx)))
:handle-ok (fn [ctx]
(generate-json (::resource ctx))))
Я рекомендую Ceshire проанализировать и сгенерировать JSON.