reitit

Filipe Silva 2025-01-17T11:50:23.669599Z

Is it intended that when using coercion (-> req :body :parameters) and (-> req :body-params) differ? I was a bit surprised that the coerced data was only in (-> req :body :parameters) .

(ns user)

(comment
  (add-lib 'metosin/reitit)
  (require '[muuntaja.core :as muu]
           '[reitit.ring :as ring]
           '[reitit.coercion.malli :as rcm]
           '[reitit.ring.coercion :as rrc]
           '[reitit.ring.middleware.muuntaja :as rrmm]
           '[jsonista.core :as j])


    (def app
      (ring/ring-handler
       (ring/router
        [["/set"
          {:post {:parameters {:body {:x [:set [:int]]}}
                  :responses {200 {:body {:total int?}}}
                  :handler (fn [{{{:keys [x]} :body} :parameters :as req}]
                             (println ":parameters :body" (-> req :parameters :body))
                             (println ":body-params" (-> req :body-params))
                             {:status 200
                              :body {:total (apply + x)}})}}]]
        {:data {:muuntaja muu/instance
                :coercion rcm/coercion
                :middleware [rrmm/format-middleware
                             rrc/coerce-exceptions-middleware
                             rrc/coerce-request-middleware
                             rrc/coerce-response-middleware]}})))

  (-> {:request-method :post
       :uri "/set"
       :headers {"content-type" "application/json"
                 "accept" "application/json"}
       :body (java.io.ByteArrayInputStream. (j/write-value-as-bytes {:x #{1 2 3}}))}
      app :body slurp j/read-value)
  ;; :parameters :body {:x #{1 3 2}}
  ;; :body-params {:x [1 3 2]}
  ;; => {"total" 6}

  ,)

juhoteperi 2025-01-17T13:02:35.919219Z

Yes, it is intended and coercion documentation says the coerced values will be available under :parameters. I don't know if the decision itself has been documented somewhere.

πŸ‘ 1
juhoteperi 2025-01-17T13:04:18.842779Z

One part is that :parameters matches the path where the schemas are defined for routes. Another part is to be safe, as other mw might already be presuming what the body-params etc. look like. There could even be cases where you need to be able to access the non-coerced values so using different path allows keeping both avavailable.

juhoteperi 2025-01-17T13:04:40.453359Z

https://github.com/metosin/reitit/blob/master/doc/ring/coercion.md > Handlers can access the coerced parameters via the :parameters key in the request.

Filipe Silva 2025-01-17T13:06:22.665269Z

I missed that bit in the docs, thank you πŸ™

lispyclouds 2025-01-17T14:18:29.911379Z

πŸ‘ 2
Panel 2025-01-18T09:32:41.189099Z

Naive question, why it’s using a Java parser when the open api spec is json / yaml and can be read as such ?

lispyclouds 2025-01-18T09:42:05.582339Z

Not a naive one at all! The main reasons are: β€’ OpenAPI though being just YAML/JSON has the complexity of https://swagger.io/docs/specification/v3_0/using-ref/ which has all sorts of things like remote refs, partial refs, jsonpath resolution etc. This is quite non-trivial to implement and can have arbitrary nesting, recursive self refs etc. β€’ Following the openapi spec with all its https://swagger.io/docs/specification/v3_0/data-models/data-types/ and their permutations is also non-trivial All of the above is doable by me and projects like https://github.com/oliyh/martian does it to some extent but has issues like https://github.com/oliyh/martian/issues/190. All in all the devil is in the details and keeping up with the changes in the spec is quite hard and using the official parser made sense for me. But I do plan to do that myself someday.

πŸ”₯ 1