This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2020-02-14
Channels
- # announcements (4)
- # aws (7)
- # babashka (44)
- # beginners (178)
- # calva (15)
- # cider (3)
- # clj-kondo (15)
- # clojure (139)
- # clojure-dev (8)
- # clojure-europe (2)
- # clojure-italy (2)
- # clojure-losangeles (9)
- # clojure-nl (32)
- # clojure-spec (6)
- # clojure-sweden (1)
- # clojure-uk (27)
- # clojurescript (17)
- # core-typed (116)
- # cursive (26)
- # data-science (1)
- # datomic (14)
- # duct (16)
- # emacs (9)
- # events (1)
- # fulcro (47)
- # jobs (3)
- # juxt (6)
- # keechma (2)
- # malli (59)
- # mid-cities-meetup (8)
- # off-topic (32)
- # pathom (5)
- # reagent (2)
- # remote-jobs (4)
- # rewrite-clj (16)
- # shadow-cljs (14)
- # spacemacs (9)
- # sql (27)
- # tools-deps (37)
- # vscode (7)
I'm trying to use malli to coerce reitit query arguments, but not quite getting the results I'm expecting.
route:
["/paginated/:table"
{:get {:coercion reitit.coercion.malli/coercion
:parameters {:path {:table string?}
:query {:page int?
:page-size int?}}
:responses {200 {:body any?}}
:handler (fn [{:keys [path-params params] :as req}]
{:status 200
:body "OK"})}}]
(http/router routes {:data {:middleware [rrc/coerce-exceptions-middleware
rrc/coerce-request-middleware
rrc/coerce-response-middleware]}})
is it reasonable to expect that this way a ?page=1
parameter will come in as {:query-params {"page" 1}}
?
yes, but the coerced params are under :parameters
, so_
{:parameters {:query {{:page 1}}}
didn’t add any sugar for the top-level maps in the malli coercion, so, all parameters need to be defined in the malli syntax.
crossed my mind to do that, would be 1:1 to switch the simple cases from data-specs to malli…
still getting string...
:parameters {:path [:map
[:table string?]]
:query [:map
[:page int?]
[:page-size int?]]}
there is an example app in https://github.com/metosin/reitit/tree/master/examples/ring-malli-swagger
["/math"
{:swagger {:tags ["math"]}}
["/plus"
{:get {:summary "plus with malli query parameters"
:parameters {:query [:map [:x int?] [:y int?]]}
:responses {200 {:body [:map [:total int?]]}}
:handler (fn [{{{:keys [x y]} :query} :parameters}]
{:status 200
:body {:total (+ x y)}})}
:post {:summary "plus with malli body parameters"
:parameters {:body [:map [:x int?] [:y int?]]}
:responses {200 {:body [:map [:total int?]]}}
:handler (fn [{{{:keys [x y]} :body} :parameters}]
{:status 200
:body {:total (+ x y)}})}}]]]
there are useful middeware there, but for example the site
is really heavy and many things are solved alread (like fallback to look up file resources)
ok, progress. changed reitit.http/router to reitit.ring/router, and now I'm getting a 406 Not Acceptable
there is a bug somewhere in the malli-coercion, bumped into it few days ago, if the response is not valid, gives really weird error. will fix that soon.
I have a minimal shadow-cljs + deps + reitit + malli example project, will good defaults, try to push that out before ClojureD
was hoping not to manually have to parse those integers but maybe the trouble isn't worth it right now
default reitit has no opinions, lot’s of things that need to decided, not the friendliest for new users
@U07FP7QJ0 this is great news. when using Shadow-cljs and Cursive, there’s basically no easy visual diff tooling that I can find. cljs support in deep-diff will fill this gap perfectly
It looks like malli need support for sequence schemas. I just need the simplest “varargs” case, why not do the whole thing while at it.
I’m thinking of re-using the map/multi syntax:
(m/valid?
[:cat
[:x int?]
[:y int?]
[:rest [:* string?]]]
[1 2 "kikka" "kukka"])
; => true
if https://github.com/cgrand/seqexp would be ported to cljs, could use that behind the scenes.
like clojure.spec.alpha/conform
, there could be something for that?
(m/destructure
[:cat
[:x int?]
[:y int?]
[:rest [:* string?]]]
[1 2 "kikka" "kukka"])
; {:x 1
; :y 2
; :rest ("kikka "kukka")}
without that, this would be just enough:
(m/valid?
[:cat int? int? [:* string?]]
[1 2 "kikka" "kukka"])
; => true
(require '[net.cgrand.seqexp :as se])
(se/exec
(se/cat
(se/as :x int?)
(se/as :y int?)
(se/as :restz (se/* :string?)))
[1 2 "kikka" "kukka"])
;{:x (1)
; :y (2)
; :restz ("kikka" "kukka")
; :rest ()}
@ikitommi fwiw, I ported clojure spec to a graalvm compatible subset here: https://github.com/borkdude/spartan.spec
What if explainer
would also report succesfully validated values in same format as errors? At top level, the m/explain
it would return either errors or succefull values.
now, only errors are pushed to the accumulator. It could be swapped Into a protocol, which has -explain-error
and -explain-success
functions. Schemas write to those and internally, in case of first error, it just tosses away the successes and collects only errors. In case of no errors, it would return the successes in the same explain -format!!
as it contains both the paths to schemas and in data, one can "unexplain" in a generic way
Spec has conform
, unform
and explain
, malli could only have explain
for all these, but has validate
for perf reasons. Still, less for more.
in spec the bulk of the work is done in conform. this result is fed into explain which transforms that result to something readable, but even valid? uses conform
I don’t think result of s/conform
is fed into explain. It either returns the conformed value of ::s/invalid
. In case of latter, s/explain
is called again with the original data. Which is fine, as it’s the failure path as you said.
;; 40ns
(let [spec (s/and int? (s/or :pos-int pos-int? :neg-int neg-int?))
valid? (partial s/valid? spec)]
(cc/quick-bench
(valid? 0)))
;; 5ns
(let [valid? (m/validator [:and int? [:or pos-int? neg-int?]])]
(cc/quick-bench
(valid? 0)))