Fork me on GitHub

I have a situation where I am ingesting json which is base64 encoded, I have a middleware that decodes it and sets the body to the decoded json, this how ever stops my body coercion, any suggestions how I can use :parameters :body on the decoded body, or will I need to manually do the validation in this instance ?


What does your middleware stack look like? Are you using muuntaja for content negotiation?


I think it can be made to work so that both decoding and coercion will work but things need to happen in certain order :thinking_face:


For example, if you’re using muuntaja you could just make it aware of your b64 encoded json format and plug in the decoding and then the rest would probably work as with normal JSON


so currently, I have decode-pubsub-body-json-middleware set as a middleware in a post route, it basically does this

(defn decode-pubsub-body-json-middleware
  (fn [request]
     (update-in request [:parameters :body]  #(-> % process-message-json :message :data)))))


I had not considered I may be able to do this in the muuntaja stage, how would muntaja known when to apply the decoding as most of the time it will not be encoded, only when it comes from a queue is it encoded


Muuntaja uses content-type header (in case of HTTP) to decide how to decode the request body


One option is to use a custom content-type e.g. application/b64json


okay good to know, I had not considered that the content type may be different


although I have a hunch its json, as its a json body with queue data with a message key which has the actual json body encoded


Yep, if you can control the content-type in the pubsub thing that could be one relatively clean way to do it


its looking like its just reported as json unfortunately, so this may stop me doing it with muuntaja


Then you could try to change route middleware to first decode b64 and coerce only after that


yeah that's what I am doing now but it seems to coerce then decode, so unless I can make the middleware run before coercion I will likely have to do it manually


Hmmm could the issue be that the coercer is actually looking from :body-params and not from [:parameters :body] :thinking_face:


Default coercers expect to find the unmarshalled body there


Did a quick test and this seems to work.. Doing b64 and json decoding in the same middleware but json decoding could happen elsewhere


(def app
       {:coercion reitit.coercion.spec/coercion
        :parameters {:body ::decoded-body}
        :middleware [(fn [handler]
                       (fn [req]
                         (handler (assoc-in req [:body-params] (-> req
        :post       (fn [req]
                      {:status 200
                       :debug  {:body-params (:body-params req)
                                :params      (:params req)}})}]]]
     {:data {}})


☝️ this works


Here’s the whole file if you want to have a look


oh awesome thanks for that, that would certainly explain it I will give it a try, when I next get a chance


I also figured out how to do the same thing with Muuntaja. Here’s an example:


You can apply the special muuntaja instance for certain routes. Others can use the default one


got around to trying this out, for me however the coercion kicks in before it even gets to the decode middleware which is a bit strange yours seems to work, main difference is your using spec not malli can't see much else that's different still digging though


It's probably the order of the middleware


Also you can try custom muuntaja for that particular route. See the example ☝️


yeah I did see that I may give that a try, I guess coercion is auto applied to all routes so maybe that makes it first


I need to break it down into a more simple example and give it another try I recon using the same libraries as the main project