【问题标题】:Validate map of known and unknown key-values with Spec使用 Spec 验证已知和未知键值的映射
【发布时间】:2019-11-20 17:54:32
【问题描述】:

我想创建一个 clojure 规范来验证由 reitit.ring.middleware.multipart 中间件创建的 http 请求的 :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】:

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

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

    但如果您使用conform'd 输出,包罗万象的s/or 规范会产生冗余标签。

    另一种选择是使用两个规范检查:

    (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 {,,,}}}
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-12-13
      • 2022-06-28
      • 2021-10-10
      • 1970-01-01
      • 1970-01-01
      • 2022-12-17
      • 2015-10-19
      相关资源
      最近更新 更多