This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2016-12-13
Channels
- # bangalore-clj (5)
- # beginners (94)
- # boot (145)
- # cljs-dev (4)
- # cljsjs (79)
- # cljsrn (18)
- # clojure (343)
- # clojure-dev (21)
- # clojure-dusseldorf (6)
- # clojure-india (1)
- # clojure-italy (2)
- # clojure-nl (4)
- # clojure-russia (62)
- # clojure-sanfrancisco (1)
- # clojure-spec (109)
- # clojure-taiwan (1)
- # clojure-uk (103)
- # clojurescript (102)
- # code-reviews (30)
- # component (1)
- # cursive (39)
- # datascript (7)
- # datomic (68)
- # emacs (11)
- # figwheel (1)
- # gorilla (1)
- # hoplon (234)
- # off-topic (46)
- # om (52)
- # onyx (32)
- # planck (9)
- # proton (4)
- # protorepl (5)
- # random (1)
- # re-frame (36)
- # ring (18)
- # ring-swagger (1)
- # specter (6)
- # untangled (3)
- # vim (56)
One thing that has always been a bit of a sore point for me in Clojure web development is how to handle parameter validation and sequential execution in general. For example, in Rails it’s trivial to terminate control flow early if parameters are invalid, if the current user is not authorised to perform the operation she attempts, etc. In Clojure this can be done using nested conditionals but that gets convoluted quite quickly.
I’ve used a technique similar to monads/ring handlers in which a handler is wrapped with the steps that we go through such that we can terminate at any given point. For example wrap-check-params
returns a handler that will check if the needed parameters are there and on the right format before calling the next handler in the stack. If they are not, it will return an appropriate HTTP status code.
This works but I can’t help but feel there might be a better solution out there somewhere. Is there something I’m missing? Some amazing technique that I just haven’t stumbled upon?
@tgk take a look at clojure.spec
-- that's what we're using now for parameter validation in web apps.
@seancorfield: thanks, we’re already using clojure.spec
. It’s a great tool but it doesn’t solve the control flow problem.
(let [params (s/conform ::my-arg-spec (:params req))]
(if (s/invalid? params)
...explain-data and report error...
(do-stuff-with params)))
You don't like that?Ah, because you need to check more than just the shape of the params? You need to check their values too, such as unique username or valid password or such?
Sure, or I need to look up data based on the parameters and check that the current user has the right to manipulate the data
I generally find a simple cond
works in most cases so it doesn't get very nested...
...but, sure, sometimes your control logic is inherently complex.
That should be fairly rare tho' really...?
I hadn’t though about that being a sequential execution but I guess you could use it as such in many cases. I’ll give that a try!
The other thing to consider is a variant of cond->
that threads the value (the req
) through the predicates as well. We call that condp->
(and we have a condp->>
macro as well).