This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2021-07-07
Channels
- # announcements (1)
- # babashka (31)
- # beginners (54)
- # biff (3)
- # calva (22)
- # cider (13)
- # circleci (1)
- # clj-kondo (6)
- # cljsrn (2)
- # clojure (113)
- # clojure-europe (58)
- # clojure-mexico (5)
- # clojure-nl (3)
- # clojure-uk (7)
- # clojurescript (81)
- # cursive (20)
- # datomic (33)
- # events (3)
- # fulcro (29)
- # introduce-yourself (1)
- # meander (78)
- # off-topic (60)
- # om-next (2)
- # podcasts-discuss (1)
- # re-frame (8)
- # reagent (5)
- # reitit (20)
- # remote-jobs (1)
- # shadow-cljs (24)
- # spacemacs (10)
- # sql (8)
- # tools-deps (22)
- # xtdb (16)
How much attention has been given to middleware performance in reitit? When using the full stack as in the examples it seems like plenty of CPU is burning there, especially on ring/params doing lots of merges. I don't know if this should be solved in reitit or in the ring libraries. Weavejester is pretty conservative and might reject wacky performance enhancement PRs. Would you rather I take it with him or offer an alternative?
@ben.sless most mw that are included in reitir are partially optimized, most wrapped or direct 3rd party mws are slow. Fast versions welcome!
also, there is a keywordize-keys step in coercion, which might not be needed. Some perf todos around in the code
In particular, ring.middleware.params/params-request
is a big offender, using both merge
and a heavy regex. I'll need to recreate the flame graphs (that's how I caught that muuntaja bug previously).
Wondering where to start, though. Would you rather I PRed it to the ring project and take the updated version from there, or have an in-house version?
For keywordize-keys, a compromise could be porting https://clojure.atlassian.net/browse/CLJ-1239
you can pull the mw into reitit-middleware
module. For perf, the current ring convention is that all params are merged into :params
. To be compliant with that, it will be slow. Not adding those by default will be a big source of confusion for beginners.
Doesn't have to be, even merging the maps using reduce-kv
rather than using merge-with merge
will be better
also, inlined lots of ring helpers, ring doesn't have a performance target, which is totally ok (and a good call looking at the history!), so most request/response helpers are not optimized
Still, looking at this, even without breaking compatibility we can both see how it can be trivially sped up
(defn assoc-query-params
"Parse and assoc parameters from the query string with the request."
{:added "1.3"}
[request encoding]
(merge-with merge request
(if-let [query-string (:query-string request)]
(let [params (parse-params query-string encoding)]
{:query-params params, :params params})
{:query-params {}, :params {}})))
Hi, I have a question regarding optional parameters in a request. Let’s take one of your examples and focus on it:
["/:company/users/:user-id" {:name ::user-view
:coercion reitit.coercion.schema/coercion
:parameters {:path {:company s/Str
:user-id s/Int}}}]
That’s from your readme. How can I annotate, e.g., company
as optional parameter? Is this possible?In our case we have multiple parameters, which can optionally be set, e.g. booleans. If they are not sent, they are assumed to be false.
Actually, I have more cases where a parameter is just optional. So, again, I am looking for a way to mark it as optional 🙂
(s/optional-key :company) s/Str
Though I empty path params probably cause problems, but you could also at least share the handler & params data even if you have multiple routes.
(let [data {:parameters ... :handler}]
[["/users/:user-id" data]
["/:company/users/:user-id" data]]
Or maybe query params are better fit for params that are optional?
Yes, in these cases that’s true. I currently share the parameters and split the routes to be more expressive. but in some cases that’s still not enough. For example I have a Feedback-Route in my webapp, and contact-name is optional. But I don’t want to have two routes for it to have a proper documentation. The spec for it would be:
(s/def ::feedback-dto (s/keys :req [:feedback/description]
:opt [:feedback/contact-name :feedback/contact-mail]))
But when I use this spec in the :parameters
-Section in the route definition, all fields are shown as required
in the resulting swagger document