如何在Rook中创建参数解析器

时间:2016-01-28 17:36:44

标签: clojure

我想在Rook中创建一个argument resolver,对输入进行简单的转换。假设我有一个简单的REST URL,如/resource/1,以获取标识为1的资源。但是id以"1"形式出现,即一个字符串。我不想在每个端点函数中明确地将id转换为字符串。

似乎我可以用参数解析器做到这一点,例如我试过这个:

(def handler (-> (rook/namespace-handler
                  ["resource" 'my-project.resource {'id #(Integer. %)}])
                 rook/wrap-with-standard-middleware))

然后在资源名称空间中,我已经将id作为整数。

(defn show [id]
  ; id should now be an integer
  (r/response (* id 2)))

但是这不起作用,id仍然是一个字符串,解析器永远不会被调用。

1 个答案:

答案 0 :(得分:3)

这里有两个问题:(1)参数解析器是请求的函数,(2)路径参数接收特殊处理,目前优先于其他适用的解析器。

(1)表示参数解析器最终必须采用

形式
(fn [request]
  …)

- 例如,你可以编写一个解析器来解析路由参数id - 只是那个 - 就像这样:

(fn [request]
  (-> request :io.aviso.rook.dispatcher/route-params :id Integer/parseInt))

参数解析器工厂采用

形式
(fn [sym]
  ;; usually there'll be a let form here wrapping the inner fn
  (fn [request]
    …))

sym是要解析的参数的名称(例如,:request-key query-params已解析为(:query-params request))。

(2)意味着,从0.1.39版开始,将其注册为符号id的解析器将不起作用;注册一个解析器工厂并用它标记你的id参数也不会有效。

目前,您最好的选择可能是在第一行let处理您的路线参数。或者,您可以使用设计为应用于其他符号的解析器工厂来处理默认路径参数处理:

;; ATTN: :io.aviso.rook.dispatcher/route-params is an implementation detail
;; NB. this assumes it will be registered under the keyword :route-param
(fn [sym]
  (fn [request]
    (let [route-param-kw (:route-param (meta sym))]
      (assert (keyword? route-param-kw))
      (-> request :io.aviso.rook.dispatcher/route-params route-param-kw))))

你会这样使用它:

(defn show [^{:route-param :id} foo]
  …)

这只是获取路径片段的原始运行时值,但可以直接修改它以应用任意转换(如果需要这种灵活性,可能是从参数符号的元数据中提取的函数)。请注意,如果输入与预期不符,您将需要确保参数解析器不会抛出。