映射中单个键的 Clojure 规范

Clojure spec for a single key in a map

我正在指定来自 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

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 的评论更新

您还可以将每个 return 代码定义为单独的规范,并将它们与 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]

使定义个人 return 代码规范更容易的宏:

(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})