Welcome! Please see the About page for a little more info on how this works.

+1 vote
ago in Spec by

Hi,

I'm pretty new to Clojure and recently got interested in using spec. One use-case I'm interested in, is to use it for validation of API inputs. As far as I understood I have the following possibilities to correctly declare / use specs in that case:

  1. Create specs with unqualified names and use plain keywords in API input. I guess that's prone to error as one can think of overlapping specs with different requirements (e. g. having IDs with different scheme in two entities).

  2. Create specs with qualified names and also use qualified names in API input. That would work as expected but feels like unnecessary extra work on the client side as all clients now need to specify the namespace for all keys while its usually clear which entity is expected (e. g. API endpoint /customer-address is expecting a customer address but still all fields need to be namespaced in the input like :customer-address/street).

  3. Create specs with qualified names but use :req-un instead of :req to specify required keys in specs. Works as expected unless someone tries to validate a map with qualified names (shouldn't usually happen in API requests but might occur within the application where namespaces might not be a bad idea).

  4. Create specs with qualified names and lift all keywords in API inputs into the expected namespace. Would work as expected and has the benefit that namespaced keywords can be used in the application. Drawback is that every API input needs to be transformed before validation can happen.

So, my question is, what is the ideomatic way to validate API input with spec?
And maybe as a bonus question: why is spec using the global "database" for specs? It looks like a lot of problems/confusion arise from that design decision (e. g. name clashes / overrides) and it also doesn't look like a very "functional" way. To clarify, I'm also not an expert in functional programming, so would be great if someone could highlight the benefits that led to that decision.

Best
Ben

1 Answer

0 votes
ago by

For input validation I don't think you should let spec drive your API, and I think you should minimize/avoid transformation for the purposes of validation. So if you want unqualified keys in your API, then I would consider #3 as the preferred way here (doesn't change your API, doesn't transform needlessly).

If you transform the data and validate on the transformed data, then the errors and error data relate to the transformed data, not the originals provided by the user, which seems like it would be confusing.

For the why questions - see https://clojure.org/about/spec which is intended to answer that.

...