映射中单个键的 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})
我正在指定来自 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})