6

如何使用 Clojure Liberator 返回 json-data?此代码不起作用:

(defresource poster []
         :allowed-methods [:post :options]
         :available-media-types ["application/json"]
         :post!      (fn [ctx] (println "posting..."))
         :handle-created (fn [ctx] {:created "ok"}))

应该在 post 之后调用 handle-created 吗?

4

3 回答 3

3

与键关联的函数:post!不是处理函数。Liberator 文档将其称为操作函数。

动作功能 键:post!, :put! 和:删除!提供非常适合产生副作用的点。虽然它们像决策函数一样被评估,但布尔值没有影响,下一个决策步骤是恒定的。上下文更新的工作方式与决策函数完全相同。

所以你不能直接从与: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"}

您可以在其project.clj文件中查看 Liberator 使用的 JSON 库。如果你想自己生成 JSON 字符串,你可以这样做:

:handle-created (fn [ctx] (liberator.representation/ring-response 
                          {:status 201 :body "{created:\"ok\"}"}))

这里提到

于 2016-07-20T23:36:52.277 回答
1

这就是我这样做的方式 - 它似乎工作,但我才刚刚开始使用 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 的决策点。因此,对于您的问题,它可能表明 Liberator 正在使用默认的句柄创建的处理程序,它只返回标头。要返回您自己的 json,您需要定义处理程序。

请注意,我没有使用帖子!方法。这是因为在此示例中,我实际上并没有创建某种新对象/项目,例如将记录添加到某种商店。如果你这样做,你可能会做的是使用 post!添加记录并定义句柄创建然后获取新记录(可能带有其他新字段,例如记录ID或时间戳等)并返回它。

我使用 :malformed? 并且句柄格式错误以进行基本的错误检查。如果:格式错误?返回true,则调用handle-malformed header,在json body中返回错误状态和错误信息。我发现在 json 中返回错误很有帮助,这样您就可以在客户端一致地处理所有内容。

我的处理程序和中间件定义如下。请注意,当我同时提供应用程序和 api 路由时,它们会稍微复杂一些,因为我希望将一些中间件应用于某些路由,而将其他中间件应用于其他路由。ring/ring-defaults 中还有一个小错误,一旦修复,它将修改内容,因为目前我无法使用 wrap-defaults site-api 中间件。注意 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)))
于 2015-01-23T23:26:16.660 回答
1

该代码201 created用于返回指向正文中新创建资源的链接以及 Location 标头。如果您想在正文中返回新创建的资源,您应该使用200 ok. 默认情况下,Liberator 将204 no-contentPOST 之后结束。你需要设置: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。

于 2015-01-24T15:44:12.107 回答