This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2017-03-19
Channels
- # arachne (1)
- # beginners (108)
- # boot (50)
- # cljs-dev (7)
- # clojure (76)
- # clojure-ireland (1)
- # clojure-romania (1)
- # clojure-russia (7)
- # clojure-spec (33)
- # clojure-taiwan (1)
- # clojure-uk (36)
- # clojurescript (46)
- # core-async (13)
- # datomic (146)
- # defnpodcast (1)
- # editors (1)
- # garden (2)
- # hoplon (1)
- # jobs (1)
- # lumo (7)
- # off-topic (21)
- # om (9)
- # pedestal (1)
- # re-frame (25)
- # reagent (5)
- # specter (2)
- # testing (3)
- # unrepl (3)
- # untangled (9)
- # vim (1)
When one uses clojure.spec to validates the body of an API request, how can we returns user-friendly errors in case the body doesn’t conform?
I mean s/explain-str
is nice for developers but not for users!!!
How would you do that @yonatanel ?
Let’s take a simple example of a signup request
http://app.klipse.tech/?eval_only=1&cljs_in.gist=viebel/7edd4252b6f71c9894bc979c550b359d
I guess it's the author responsibility to define higher level predicates that can be later examined more easily than (>= (count %) 8)
Nice idea. How would you manage the mapping between predicates/specs and a string that describe them?
Not sure right now, but I think you are right in that explain is not really meant for public data-oriented apis.
It means that I have to manually conform the data? 😞
I mean that I can write code that checks if the password is long enough and returns an appropriate error message
I’d need to write such a piece of code in addition to the specs definitions - which is quite disappointing
Would you like each predicate to optionally have an explanation string or something like that?
But I am curious to know if spec is designed for that
You kinda have all the building blocks for that, and it might be good to separate error message from spec itself. You could have multiple mappings from a spec to error message, one for public api, another for a kafka consumer etc, all using the same registered (s/def ::long-enough ...)
spec.
I still have to go about trying spec out for myself, but for a similar usecase I made a simple validation function, returning a list with either only true, or false and an end-user friendly error message.
Could you be more specific @gklijs
How would you update this code http://app.klipse.tech/?eval_only=1&cljs_in.gist=viebel/7edd4252b6f71c9894bc979c550b359d ?
Well, I wouldn’t know since I’m not using spec yet, I just did it like this:
(defn valid-registration-map?
[registration-map]
(cond
(not (map? registration-map)) '(false "Input is not a map")
(not (contains? registration-map :username)) '(false "Input is missing the :username key.")
(not (contains? registration-map :password)) '(false "Input is missing the :password key.")
(< (count (:username registration-map)) 8) '(false "Username should have a minimal of 8 characters")
(< (count (:password registration-map)) 8) '(false "Password should have a minimal of 8 characters")
:else '(true)))
With forms, there's also the issue that if you validate the whole map, you can't indicate that there's an error with a particular key in the same way s/keys does (unless that's changed?)
We use explain-data
and a map of symbols or forms to messages -- and a generic function that walks the explanations and finds matching messages. That way you can choose how generic or how specific the message is by how much of the form of the spec it matches. For example, if you just want a generic bad password message, just map 'password
to the message. Otherwise map more pieces of the spec forms to different messages.
@seancorfield could you share a code snippet?
I'm on my phone so, no. I'll try to remember tomorrow when I'm back at work. But this is what the Clojure/core folks have been encouraging us to do with spec: walk the explanation data and map it to messages or error codes or whatever. You have a lot of useful information there.
The path, the predicate, etc.
That looks very cool!
I’ll ping you tomorrow @seancorfield !
@alexmiller any interesting insights of how to generate user-friendly error messages from spec. See ⏫
Advice from Sean above seems right
Or bind a custom explain printer