【问题标题】:Clojure spec for a single key in a map地图中单个键的 Clojure 规范
【发布时间】:2021-03-18 10:01:19
【问题描述】:

我正在寻找来自 Google Calendar API 的 http 响应 我希望每种响应类型都有不同的规格。

我已将 HTTP 响应规范定义为

(s/def ::http-resp
  (s/keys :req-un [:status] :opt-un [:body]))

但是如何为每个 HTTP 状态定义一个规范? 我知道我可以做到:s.http-error-401/status,但我更喜欢类似

(s/and ::http-response 
       (key-in-a-map :status :s.http-statuses.error/gone))

也许有一个很好的 HTTP 响应规范示例? 到目前为止,我只找到了ring-spec

【问题讨论】:

    标签: clojure clojure.spec


    【解决方案1】:

    IMO ring-spec 已经为您服务。您可以在此处找到 HTTP 状态的规范:

    (s/def :ring.response/status (s/int-in 100 600))
    

    请注意,HTTP 状态码是一个数字。如果您需要微调规范,您可以随时执行以下操作:

    (def ^:const OK 200)
    (def ^:const UNAUTHORIZED 401)
    
    (s/def ::status #{OK UNAUTHORIZED})
    
    (s/def ::body string?)
    
    (s/def ::response (s/keys :req-un [::status] :opt [::body]))
    
    (s/valid? ::response {:status 200
                          :body   "Hello"})
    ;; => true
    
    
    (s/valid? ::response {:status 1000
                          :body   "Hello"})
    ;; => false
    
    

    根据 2021.09.26 的评论更新

    您还可以将每个返回代码定义为单独的规范,并将它们与or 结合使用。然后就可以使用conform获取代码了:

    
    
    (s/def ::status (status-spec [200 OK
                                  400 BAD_REUEST
                                  404 NOT_FOUND]))
    
    (s/def ::response (s/keys :req-un [::status] :opt [::body]))
    
    (s/conform ::response {:status 200
                           :body "Hello"})
    ;; => {:status [:user/OK 200], :body "Hello"}
    
    (s/conform ::status 200)
    ;; => [:user/OK 200]
    
    

    使定义单个返回码规范更容易的宏:

    (defn- destructure-kv [kvs]
      (let [xs (partition 2 kvs)]
        (interleave (map (comp (partial keyword (str *ns*))
                               str
                               last)
                         xs)
                    (map (comp set vector first) xs))))
    
    (defmacro status-spec [kvs]
      `(s/or ~@(destructure-kv kvs)))
    

    基本上会生成一个or:

    (status-spec [200 OK
                  400 BAD_REUEST
                  404 NOT_FOUND])
    
    =>
    
    (s/or :user/OK #{200} 
          :user/BAD_REUEST #{400} 
          :user/NOT_FOUND #{404})
    

    【讨论】:

    • 感谢您的意见!但在某些情况下,我希望这个 http-response 有一个确切的状态。假设我正在为 http POST 编写测试。在某些情况下,我希望响应具有 :status 403 在其他情况下为 :status 200。我理解规范的方式是我必须检查 2 个规范,或者定义另一个具有 ::req-un [:my.http.s400/status] 的 s/keys 规范
    • 请参阅更新部分
    猜你喜欢
    • 2017-03-27
    • 1970-01-01
    • 2020-01-08
    • 1970-01-01
    • 2017-09-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多