This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
- # admin-announcements (1)
- # announcements (3)
- # babashka (18)
- # beginners (35)
- # cider (4)
- # clj-kondo (52)
- # cljs-dev (2)
- # clojure (92)
- # clojure-spec (18)
- # clojurescript (17)
- # conjure (11)
- # core-async (1)
- # datomic (11)
- # emacs (5)
- # fulcro (11)
- # graalvm (10)
- # helix (21)
- # kaocha (6)
- # malli (1)
- # membrane (37)
- # off-topic (110)
- # re-frame (1)
- # reagent (12)
- # reitit (5)
- # rewrite-clj (1)
- # sci (1)
- # shadow-cljs (40)
- # vim (21)
- # vrac (17)
How would you go about spec’ing a (http) patch like api using
nil as a sentinel for retraction. Let’s say you have an entity that has an optional attribute, I’d hate to say that this attribute is
s/nilable in its global definition just because there is a patch endpoint using
nil to signal retraction
Like — if I send you this attribute, it will either not be there, or it will have a non-nil value.
I don’t know, it feels asymmetrical: I’ll always promise you either no value at all, or some value satisfying a spec, but you can provide me no value, a value satisfying a spec or nil, but only in this specific case. I guess it doesn’t help me that I can have only one definition for a namespaced keyword (here).
Yes, outgoing I would agree: I’ll (= server) never send you a
nil for a key I have no value for and instead omit it. The problem is in how you (= client) tell me that you don’t want this value anymore: If you omit it in your (partial) update request, do you mean to retract it, or to retain it?
So some rest endpoints allow you to
patch an entity, but with
nil as value, meaning ‘let’s get rid of this value for that attribute’. So now we have a bit of asymmetry: I’ll promise you to never send a
nil value, but you can send me a
nil to indicate retraction on this
I don’t know how to express, in spec, that I as a server make a stronger guarantee than you as a client have to when
patch ’ing entities. If that makes any sense 🙂.
(Or more specifically, I don’t know how to do that when my keys are namespace qualified. If I were to use
:req-un I could maintain two specs.)
That's just two different specs (perhaps with reuse on the common stuff). A spec for the result of a call (where the key is optional but spec'd to be non-nil). A spec for the input value (where the key is nilable).
If it's an API spec, it's going to be for unqualified keys, surely? Since it will be a wire spec, e.g., JSON.
Right, we may have extended this nilability (or the spec, for that matter) too far into our system. We have a JSON handler that accepts this nil and is spec checked, that is unqualified, but then we have an update method shared between this JSON endpoint and other places that is also checked, but has qualified keys. Thats where friction occurs: the keys are qualified, but their semantics differ between what you supply and what you get.
Well, if you have an internal (qualified) name for that attribute, either it should be optional and non-`nil`, or it should be nilable -- in all cases. And if that's not possible, then the two semantics should have different names.
Sorry for the kinda fuzzy description… Right so in the latter of your options you say to extend the notion of valid values for this attribute to be a superset of all values it can take in all contexts. That means that consumers I could have promised no
nils (because they consume the ‘outgoing’ format), have to consider
nils because thats what I could promises them in my spec, right? I find that kinda sad.
I'm saying use different specs as needed and transform the data to match as you cross boundaries.
Another option is to chose a specific, unique, representation for a retraction (and, again, map from the inbound retraction to that representation).
(we had exactly this situation and we tried to blur the lines with nilable and optionality and it was a mess so we mapped it to a different representation altogether)