reitit
reitit copied to clipboard
response-coercer customisation
The spec/spec-tools implementation of the Coercion
protocol calls st/coerce
to transform both requests and responses – the -response-coercer
is essentially the same as -request-coercer
, just called with a different type
argument used to look up :response
transformers. This makes it impossible to have request and response specs share child specs, as well as having the request coercer decode the incoming value, and the response coerce encode the outgoing value.
Take as an example:
(s/def ::amount
(st/spec :spec amount?
:encode/json str
:decode/json bigdec))
(s/def ::request-body (s/keys :req-un [::amount])
(s/def ::response-body (s/keys :req-un [::amount])
I would like decode/json
to be applied by the request coercer, and encode/json
by the response coercer, but this won't work with the above example, nor any request / response specs with shared children.
I find sharing specs in this way is useful because:
- re-use: child specs often appear in request and response bodies;
- validation happens after decoding, and before encoding – in other words, what the application code 'sees';
- and encoder and decoder functions are defined in one place.
I have explored the behaviour and attempted a workaround but to no avail. The response-coercer default transformer is in fact a no-op
, but overriding it with json-transformer
will invoke decode/json
as a result of calling st/coerce
, not encode/json
as I would like. It's possible to define a custom JSON transformer with encode and decode functions switched, but this blows up when the result is validated against the spec.
I know that changing the default behaviour would be a breaking change and therefore out of the question, but it would be useful to have reitit.coercion.spec/create
accept an option that, when provided, encodes the outgoing value in the response coercer. If we did that then the validation cannot happen after the encoding like it does currently; we will instead have to introduce a new conditional before the call to st/coerce
to handle this new behaviour.
If a solution is agreed then I'm more than happy to submit a PR for this.