Fork me on GitHub
#reitit
<
2020-09-18
>
ikitommi07:09:05

@benny you should declare a :coercion , e.g. :coercion reitit.coercion.spec/coercion into route data. It is used to transform the :parameters and :responses into JSON/Swagger Schema for api-docs.

benny14:09:43

thanks @ikitommi somehow reitit.coercion.spec/coercion is not being found when i have the uber reference, am i supposed to have something else pulled in for it to be recognized?

ikitommi14:09:33

what is an uber reference? you need reitit-spec module at least, or reitit , which contains all other modules

benny15:09:48

i just meant the main reference to reitit (no specific references)

ikitommi07:09:55

@amarjeet do you handle the middleware chain as list/seq at some point? all declarations should be in vectors.

amarjeet07:09:44

Hi @ikitommi, I tested with a small sample:

(ns cljservice.http.temp
  (:require [ring.middleware.json :refer [wrap-json-params wrap-json-response]]
            [ring.middleware.keyword-params :refer [wrap-keyword-params]]
            [reitit.ring :as ring]
            [aleph.http :as http]))

(defn get-handler [req]
  {:status 200
   :headers {"Content-Type" "application/json"}
   :body {:Response "Hello http-get world!"}})

(defn my-middleware [handler v]
  (fn [req]
    (let [response (handler req)]
      (assoc-in response [:body "middleware-val"] v))))

(def router
  (ring/router
   [["/" {:middleware [[wrap-json-response] [my-middleware 3] [my-middleware 2] [wrap-json-params] [wrap-keyword-params]]
          :get get-handler}]]))

(def app (ring/ring-handler
          router
          (ring/create-default-handler)))

(defn start-http-server []
  (http/start-server app {:port 3000}))
Now, if I make a get request, the middleware-val has value 3, not 2.

amarjeet07:09:49

Middlewares are in vec in this case.

ikitommi07:09:11

middleware is a 2-way chain: here it’s json-response -> 3 -> 2 -> json-params -> wrap-keywords. For request, it’s processes in that order. For response it’s reverse (as it’s just a higher order function chain).

ikitommi07:09:31

you are assoccing to response in the response pipeline.

ikitommi07:09:27

there is a middleware chain diff printer which shows the order of things and the effects of each middleware, see examples.

ikitommi07:09:29

hope this helps

amarjeet07:09:21

Aah, my bad - I realize now.

amarjeet07:09:28

Thanks 🙂

ikitommi07:09:43

You’re Welcome

ikitommi07:09:49

@rgm If I understood correctly, you want to filter out routes that don’t have a :handler / :name etc defined. there is a guide for composing routers here: https://cljdoc.org/d/metosin/reitit/0.5.5/doc/advanced/composing-routers - basically: create a router with expanded things, pull out the routes (they are now flattened, filter the data and create a new router.

🙏 3
rgm14:09:53

Oh, that’s great! Thank you… I really like the idea that a router can be treated a coll of routes and all I need is good old (remove nil? ,,,) against the route data at start-up time. Right now I’m just gapping out the ignore-anchor-request? at run-time.

rgm14:09:03

I’ll read the composing routers page more closely … I’ve scanned it a couple of times but I’ve had that thing going on where I just needed a bit of help to recognize that I have a problem that it solves.

ikitommi07:09:33

you might be able to do that within a router using the route compiler, but the solution might be more complex.

ikitommi07:09:38

the route tree merging and flattening utils are in reitit.impl , not part of the public api.

ikitommi07:09:03

This is one of the sweet-spots of data-oriented route tables: you can add data like :dispatcher :nio and collect those routes into separate router, to be run nio the server NIO pool. Also tag routes with cluster info like :service/group "abc", and do multiple server provisioning with partial route tables. Monolithic Design, with micro deployments.

Eyal H09:09:52

Hey, I'm using the reitit.coercion.spec/coercion in reitit to validate the route, path and body of the request. I'm doing some benchmarking with non-valid requests (body params) and I noticed that the CPU is working very hard (4 CPU machine - 100% utilization when I fire 6000 req/sec). When the request is valid, CPU utilization is quite low (30-40%). Any idea what's causing the CPU to reach 100%?

Eyal H09:09:06

{:exception pretty/exception
                 :data      {:coercion   rcs/coercion
                             :muuntaja   muuntaja/instance
                             :middleware [swagger/swagger-feature
                                          reitit-middleware-parameters/parameters-middleware
                                          muuntaja-middleware/format-negotiate-middleware
                                          muuntaja-middleware/format-response-middleware
                                          rrc/coerce-exceptions-middleware
                                          exception-middleware
                                          rrc/coerce-response-middleware
                                          muuntaja-middleware/format-request-middleware
                                          rrc/coerce-request-middleware
                                          app-data-middleware/add-app-data-middleware
                                          s2s-auth-middleware/auth-middleware]}}
Middlware configuration

Eyal H09:09:16

The validation I'm doing is a simple one - validating strings

Eyal H09:09:59

Snapshot of falmegraph of one thread

ikitommi09:09:32

@eyaldocs could you run the same benchmark with malli coercion? On my tests, it's 1-3 orders of magnitude faster than spec

ikitommi09:09:53

on a side-note: doing a spike on running the json->malli transformations within Jackson, removes one step (doing garbage) in the pipeline, should make things faster.

Eyal H10:09:40

Thanks, @ikitommi I"ll give malli a try. Can you please elaborate on your side note, what exactly should I do

ikitommi10:09:13

different :coercion , different way to describe the parameters and reaponses

Eyal H10:09:02

Yes, thanks, I understood this part

Eyal H10:09:22

I was talking about the second part of your answer

ikitommi12:09:38

not implemented and don’t know how to integrate that in yet. I think we need to add a new protocols for muuntaja & reitit-coercion to negotiate that the coercion happens within json-decoding and the separate coercion is not needed. At code level, would like:

(require '[jsonista.malli :as jm])
(require '[malli.core :as m])

(def decode
  (m/decoder [:map [:x keyword?]] (jm/json-transformer {:strip-extra-keys true})))

(decode "{\"x\": \"kikka\", \"y\": 123}")
; => {:x :kikka}

ikitommi12:09:15

basically what the statically typed langs have had already for ages.

👍 3
Michaël Salihi13:09:57

Hi Reitit luvers! I want to share this GIT repository that might be useful. This is the useful usermanager example of @seancorfield (https://github.com/seancorfield/usermanager-example/) but for which for learning purposes, I started again from scratch by replacing the Compojure librarie by Reitit and Component by Integrant : https://github.com/PrestanceDesign/usermanager-reitit-integrant-example Cheers!

ikitommi13:09:33

@admin055 thanks! could you do a PR and add it to reitit README so it’s found? there are some links there already.

Michaël Salihi13:09:04

Yes, for sure @ikitommi. Which section? "More examples" part?

ikitommi14:09:48

sure, or a new section of external resources, or whatever feels good

Michaël Salihi14:09:14

OK, another section is what I think is best since "More examples" are examples from the Reitit repo only. :thumbsup:

ikitommi15:09:38

Merged, thanks!

Michaël Salihi16:09:11

You're welcolme, thx to you!

dharrigan14:09:48

I should add my one, which is a simple startrek one + frontend/backend reitit with juxt clip

dharrigan14:09:52

I'll do a PR soon

👍 6
dharrigan09:09:39

PR now available 🙂

Felipe Marques15:09:58

Hello! I'm having problems with using Reitit in the Front-end. The coercion of path params works in dev but when I compile and serve the JS, it doesn't. Did anyone have a similar problem?

Felipe Marques14:09:53

The problem disappears when I change the optmization from :simple to :advanced