Clojure.spec中类似s/and的or操作:验证两种Web响应结构
简洁处理二选一的响应结构验证
嘿,我太懂你这种不想杀鸡用牛刀的心情了!对于你这种两种简单映射结构的场景,完全没必要动用multi-spec——clojure.spec.alpha/s/or就是最适配的轻量工具,它专门用来定义多个可选的有效结构,语法简洁到恰到好处。
咱们直接上实操代码:
首先分别定义两种响应的独立spec:
(require '[clojure.spec.alpha :as s]) ;; 第一种响应:包含assignment字段的映射 (s/def ::assignment string?) (s/def ::assignment-response (s/keys :req-un [::assignment])) ;; 第二种响应:包含no-more-assignments字段的映射 (s/def ::no-more-assignments boolean?) (s/def ::no-more-response (s/keys :req-un [::no-more-assignments]))
然后用s/or把它们组合成一个统一的响应spec,给每个分支起个短名字,后续验证失败时能快速定位问题:
(s/def ::server-response (s/or :has-assignment ::assignment-response :no-more ::no-more-response))
现在来验证下效果:
;; 验证合法的第一种响应 (s/valid? ::server-response {:assignment "1232123"}) ; => true ;; 验证合法的第二种响应 (s/valid? ::server-response {:no-more-assignments true}) ; => true ;; 验证无效的响应(不符合任何一种结构) (s/valid? ::server-response {:random-key "oops"}) ; => false
如果需要看详细的失败原因,用s/explain-str就能拿到清晰的报错信息:
(s/explain-str ::server-response {:random-key "oops"}) ;; 输出示例: ;; "Spec failed: In: [] val: {:random-key \"oops\"} fails at: [:has-assignment] predicate: (contains? % :assignment), fails at: [:no-more] predicate: (contains? % :no-more-assignments) ;; :clojure.spec.alpha/spec #object[clojure.spec.alpha$regex_spec_impl$reify__2509 0x...], :clojure.spec.alpha/value {:random-key \"oops\"}, :clojure.spec.alpha/failure :multi-spec"
这个方案的优势很明显:
- 代码极简,完全贴合你这种简单二选一的场景
- 报错信息直观,能一眼看出是哪个分支的验证没通过
- 不需要额外写dispatch函数,比multi-spec轻量太多
内容的提问来源于stack exchange,提问作者frank
相关产品推荐
相关产品推荐

