使用Spec验证已知和未知键值的映射

问题描述 投票:2回答:1

我想创建一个Clojure规范来验证由:multipart中间件创建的http请求的reitit.ring.middleware.multipart参数。

多部分表单数据必须包含可以用s/keys验证的特定参数,以及任意数量的具有任意参数名称的文件。

要验证的地图如下所示:

           {:visualisation "vis"
            :file-xy       {:filename     "foo.png",
                            :content-type "image/png",
                            :tempfile     "C:\\Temp\\ring-multipart-123.tmp",
                            :size         295281}
            :file-abc      {:filename     "bar.png",
                            :content-type "image/png",
                            :tempfile     "C:\\Temp\\ring-multipart-456.tmp",
                            :size         42}}

我可以使用reitit.ring.middleware.multipart/temp-file-part规范来验证文件,如下所示:

    (s/def :multipart/files (s/map-of :multipart/param multipart/temp-file-part))

放在一起,我想出了一个可以通过的规范,但它允许所有未知参数为文件或字符串:

(s/def :multipart/param keyword?)
(s/def :multipart/visualisation string?)
(s/def :multipart/items (s/map-of :multipart/param (s/or :file multipart/temp-file-part :visualisation string?)))
(s/def :visualisation/files (s/and (s/keys :req-un [:multipart/visualisation])
                                   :multipart/items))

如何定义具有特定键的地图规范以及其他键的值验证器?

validation dictionary clojure specifications clojure.spec
1个回答
0
投票

您可以添加谓词函数以确保地图的值中只有一个是字符串:

(s/def :visualisation/files
  (s/and (s/keys :req-un [:multipart/visualisation])
         #(= 1 (count (filter string? (vals %))))
         :multipart/items))

(s/conform :visualisation/files
  {:visualisation "vis"
   :file-xy       {:filename "" :content-type "" :tempfile "" :size 0}})

(s/conform :visualisation/files
  {:visualisation "vis"
   :file-abc      "not valid"
   :file-xy       {:filename "" :content-type "" :tempfile "" :size 0}})

但是如果您使用的是s/or输出,则全部conform规范将产生冗余标签。

另一个选择是使用两次规格检查:

(def data
  {:visualisation "vis"
   :file-xy       {:filename "" :content-type "" :tempfile "" :size 0}})

(s/conform (s/keys :req-un [:multipart/visualisation])
           data)

(s/conform (s/map-of :multipart/param :multipart/temp-file-part)
           (dissoc data :visualisation))

如果您控制数据的形状或可以重新排列它,我会考虑这样的事情,这样更容易说明:

{:visualisation "foo"
 :files {:file-1 {,,,}
         :file-2 {,,,}}}
© www.soinside.com 2019 - 2024. All rights reserved.