【问题标题】:Request map passed to my anonymous function inside a Compojure handler在 Compojure 处理程序中传递给我的匿名函数的请求映射
【发布时间】:2016-08-08 10:38:51
【问题描述】:

通过使用ring-clojureCompojurering-jsonwrap-json-body 中间件编写一个简单的REST 服务器,我花了两天时间学习Clojure。

到目前为止,我有:

包含用户的向量users(带有几个默认用户):

(def users [{:id 0 :username "aname"}
            {:id 1 :username "anothername"}])

一个函数(表单?)save-user,它接受一个映射(用户)并查找具有相同用户名的现有用户。如果用户名可用,我会在返回 HTTP 201 之前覆盖 users 向量以包含新用户。如果用户名被使用,我只需返回 HTTP 400:

(defn save-user [user]
  (prn users)
  (if
    (not-any? #(= (:username %) (:username user)) users)
    (fn [request]
      (def users (conj users user))
      (status
        (response (str "Saved user with username: " (:username user)))
        201))
    (status
      (response (str "User with username '" (:username user) "' already exists"))
      400)))

POST /users 的路线使用接收到的地图调用 save-user

(defroutes app-routes
       (POST "/users" request (save-user (:body request))))

我觉得没关系,但是中间件是这样应用的:

(def app
  (-> app-routes
      (wrap-cors :access-control-allow-origin "*" :access-control-allow-methods "*")
      (wrap-json-response)
      (wrap-keyword-params)
      (wrap-json-body {:keywords? true :bigdecimals? true})
      (wrap-defaults (assoc site-defaults :security false))))

我的问题:

无论出于何种原因,整个request 映射都会传递给我在if 中作为then 传递的函数。打印它:

  (if
    (not-any? #(= (:username %) (:username user)) users)
    (fn [request]
      (prn request))
    ...

...给我这个:

{:ssl-client-cert nil, :cookies {}, :remote-addr "0:0:0:0:0:0:0:1", :params {}, :flash nil, :route-params {}, :headers {"host" "localhost:3000", "accept" "*/*", "content-length" "42", "content-type" "application/json", "user-agent" "curl/7.43.0"}, :server-port 3000, :content-length 42, :form-params {}, :compojure/route [:post "/users"], :session/key nil, :query-params {}, :content-type "application/json", :character-encoding nil, :uri "/users", :server-name "localhost", :query-string nil, :body {:username "testusername", :password "testpassword"}, :multipart-params {}, :scheme :http, :request-method :post, :session {}}

如果我将匿名函数作为 if 的 else 传递,也会发生同样的情况。但是,当我只传递(status ...) 时,没有任何问题发生,就像上面的代码一样。

据我了解,request 映射根本不应该在 save-user 中可用,因为它没有作为参数传递。为什么它会传递给我的匿名函数,有什么办法可以简单地忽略它?

【问题讨论】:

  • 不确定问题是什么。你为什么要从 save-user 函数返回一个 function 呢?您可以直接返回响应(将(fn [request] 替换为(do)。
  • 顺便说一句,您应该将users 向量包装在atom 中,然后对原子进行操作。从函数内部重新定义全局变量是 Clojure 的一大禁忌。
  • @glts 我没有从save-user 返回函数,但我将一个函数传递给if,因为我需要both 保存用户and 返回 HTTP 响应对象(从 status 函数返回)。至于用atom 包装列表:谢谢!那是因为我是这方面的新手。
  • 嗨,马丁,我已将我的评论转换为答案。您正在if 返回一个函数:在 Clojure 中,每个条件分支都是一个返回值的表达式。

标签: clojure compojure ring


【解决方案1】:

save-user 中,您将返回一个函数,该函数接受请求并返回响应(处理程序)。

我想您应该直接返回响应。只需将 (fn [request] 替换为 (do 即可将多个表达式包装在一个表单中。

(def users (atom [{:id 0 :username "aname"}
                  {:id 1 :username "anothername"}]))

(defn save-user [user]
  (if (not-any? #(= (:username %) (:username user)) @users)
    (do
      (swap! users conj user)
      (status
        (response (str "Saved user with username: " (:username user)))
        201))
    (status
      (response (str "User with username '" (:username user) "' already exists"))
      400)))

我还将全局用户 var 更改为原子。从函数内部重新定义全局变量在 Clojure 中是一个很大的禁忌。

【讨论】:

  • 你是冠军。 do 绝对是我想要的。非常感谢!
猜你喜欢
  • 1970-01-01
  • 2023-01-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-07-07
  • 1970-01-01
  • 1970-01-01
  • 2020-08-29
相关资源
最近更新 更多