Fork me on GitHub
#reitit
<
2022-06-22
>
oly08:06:04

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 ?

valtteri10:06:42

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

valtteri10:06:36

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:

valtteri10:06:10

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

oly10:06:13

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
  [handler]
  (fn [request]
    (handler
     (update-in request [:parameters :body]  #(-> % process-message-json :message :data)))))

oly10:06:04

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

valtteri10:06:06

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

valtteri10:06:50

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

oly10:06:31

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

oly10:06:25

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

valtteri10:06:01

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

oly13:06:43

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

valtteri14:06:16

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

oly15:06:56

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

valtteri15:06:51

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

valtteri15:06:54

Default coercers expect to find the unmarshalled body there

valtteri15:06:41

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

valtteri15:06:51

(def app
  (ring/ring-handler
   (ring/router
    [["/b64"
      ["/test"
       {:coercion reitit.coercion.spec/coercion
        :parameters {:body ::decoded-body}
        :middleware [(fn [handler]
                       (fn [req]
                         (handler (assoc-in req [:body-params] (-> req
                                                                   :body
                                                                   slurp
                                                                   <-base64
                                                                   <-json)))))
                     coercion/coerce-request-middleware]
        :post       (fn [req]
                      {:status 200
                       :debug  {:body-params (:body-params req)
                                :params      (:params req)}})}]]]
     {:data {}})
    (ring/create-default-handler)))

valtteri15:06:03

☝️ this works

valtteri16:06:33

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

oly16:06:49

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

valtteri09:06:26

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

valtteri09:06:19

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

oly15:07:39

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

valtteri16:07:37

It's probably the order of the middleware

valtteri16:07:44

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

oly12:07:54

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

oly12:07:24

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