Fork me on GitHub
#reitit
<
2023-09-04
>
Liliane Assous11:09:36

Hi, I’m trying to add a middleware to an existing router and struggling to understand the order of execution

(defn- create-router
  "creates a reitit router and validates its structure"
  [routes]
  (reitit-ring/router
    routes
    {:data {:muuntaja   (-> muuntaja/default-options
                            (update :formats select-keys ["application/json"])
                            muuntaja/create)
            :middleware [some-middlewares-that-do-stuff-on-headers-and-such
                    	 middleware-I-want-to-add-that-does-stuff-on-body-of-request]}}))
Right now it seems to me that muuntaja is executed after all of the middleware the I pass to middleware. Am I correct? How is the order of execution of the middleware determined (`:middleware` and :muujata)? The middleware I want to add should take place after muuntaja. How can I do that?

Ben Sless12:09:53

Currently I don't see any middleware related to muuntaja at all, but iirc in reitit the order of middlewares in the vector is top down, e.g. if both mws do something before a handler is invoked, the order of execution will be the same as the order of the vector

Ben Sless12:09:12

When do you want your middleware to fire?

Liliane Assous12:09:32

So muuntaja isn’t a middleware because it doesn’t take a handler, it’s just a transformer? I want to to add a middleware that assocs a field to the body, so I need it to be executed after muuntaja. Should I take muuntaja and turn it into a middleware?

Ben Sless12:09:07

Your format negotiation middleware should be using the muuntaja instance

Ben Sless12:09:00

Let's take the example from reitit's repo:

;; query-params & form-params
parameters/parameters-middleware ;; happens before everything, parses query and form params 1
;; content-negotiation
muuntaja/format-negotiate-middleware ;; format negotiation, adds metadata to the request regarding formats 2
;; encoding response body
muuntaja/format-response-middleware ;; happens after handler, formats response according to format negotiation from before 7
;; exception handling
exception/exception-middleware ;; handle exceptions 3 (wraps everything after it)
;; decoding request body
muuntaja/format-request-middleware ;; apply format negotiation from before to request 4 
;; coercing response bodys
coercion/coerce-response-middleware ;; apply coercion to parameters - query, body, form, headers 5
;; coercing request parameters
coercion/coerce-request-middleware ;; apply coercion to response - body, headers 6 
I added comments and the order in which these mw's happen

Liliane Assous13:09:27

So how did it work without any of these before?

Ben Sless13:09:56

I don't know what else your code was doing, you elided some details and other middlewares which might have been applied

timo11:09:20

Anyone ever attempted to create proper error-messages from coercion-errors? Is there a lib somewhere? The returned error-spec when using clojure-spec is pretty terrible to parse. Does anyone have a hint?

lispyclouds14:09:38

using malli and the exception interceptor like https://github.com/bob-cd/bob/blob/main/apiserver/src/apiserver/server.clj#L45 before the coercion interceptors gets me pretty far with decent "humanised" errors

👍 2
timo14:09:46

unfortunately I am using middleware and clojure-spec 😅

dharrigan15:09:18

I do something like this:

dharrigan15:09:32

I have a create-coercion-handler which is wired into the create-exception-handlers

dharrigan15:09:06

then I use resolve-message to pick an i18n (and templated) message from my resources

dharrigan15:09:30

Maybe that may be useful for you?

timo15:09:08

Thanks @U11EL3P9U, looking into it. encode-error seems an interesting little helper.