What's the best way to define a string format so that it comes through to swagger
(swagger/transform [:map
[:a {:swagger/format "date-time"} string?]])
; => {:type "object", :properties {:a {:type "string", :format "date-time"}}, :required [:a]}
this works, but I'm wondering if there's a better way that also has validation
maybe split it:
(def DateTimeString [:string {:swagger/format "date-time"}])
(swagger/transform [:map [:a DateTimeString]])
; => {:type "object", :properties {:a {:type "string", :format "date-time"}}, :required [:a]}
what do you mean by “also has validation”?
like maybe a [:fn #(java.time.Instant/parse %)]
or something?
that would return an Instant
, not string.
after the date schemas are implemented, it would be:
(swagger/transform [:map [:a :instant]])
; => {:type "object", :properties {:a {:type "string", :format "date-time"}}, :required [:a]}
ah, that would be ideal
but, do you want Instant
as a result or just a string that is formatted like an instant?
haha that's a good question. For consumers of the api, and in the docs etc it should be a string that is formatted like an instant. It would be nice if when we coerce parameters, we could get back a real instant.
Is what :string/decode is used for
@danieleneal if you want a full custom type, here’s a sample:
(ns demo
(:require [malli.core :as m]
[malli.error :as me]
[malli.generator :as mg]
[malli.transform :as mt]
[malli.json-schema :as json-schema]
[clojure.test.check.generators :as gen])
(:import [java.time Instant]
[java.util Date]))
(def instant
(let [string->instant #(if (string? %) (Instant/parse %))]
(m/-simple-schema
{:type 'instant
:pred (partial instance? java.time.Instant)
:type-properties {:error/message "should be instant"
:decode/string string->instant
:decode/json string->instant
:json-schema {:type "string", :format "date-time"}
:gen/gen (gen/fmap #(.toInstant ^Date %) (mg/generator inst?))}})))
(m/form [:map [:x instant]])
; => [:map [:x instant]]
(m/validate instant (Instant/now))
;=> true
(-> [:map [:x instant]]
(m/explain {:x "kikka"})
(me/humanize))
; => {:x ["should be instant"]}
(json-schema/transform [:map [:x instant]])
;{:type "object"
; :properties {:x {:type "string"
; :format "date-time"}}
; :required [:x]}
(m/decode
[:map [:x instant]]
{:x "2021-02-09T13:49:44.419Z"}
(mt/json-transformer))
; => {:x #object[java.time.Instant 0x5aed36d3 "2021-02-09T13:49:44.419Z"]}
(mg/generate [:map [:x instant]])
; => {:x #object[java.time.Instant 0x4878fa62 "1970-01-01T00:00:00.295Z"]}
e.g. m/-simple-type
allows to (easily?) build custom schemas that cover all the aspect: transforming, humanized errors, generators, json-schema, etc.
much of the core itself is built on top of that.
:type-properties
allow one to hide implementation details. one could do the same fully using normal schema properties, but all the details would be in your face when you look at the schema form.
thanks @ikitommi, that looks great