This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2018-11-13
Channels
- # aleph (2)
- # announcements (1)
- # beginners (133)
- # cider (29)
- # cljdoc (9)
- # cljs-dev (2)
- # cljsjs (3)
- # cljsrn (1)
- # clojure (146)
- # clojure-dev (26)
- # clojure-europe (3)
- # clojure-italy (26)
- # clojure-japan (6)
- # clojure-nl (76)
- # clojure-spec (4)
- # clojure-uk (42)
- # clojurescript (17)
- # cursive (43)
- # datascript (1)
- # datomic (28)
- # emacs (4)
- # figwheel-main (13)
- # fulcro (26)
- # hyperfiddle (2)
- # jobs (9)
- # jobs-discuss (6)
- # leiningen (1)
- # mount (5)
- # onyx (8)
- # pathom (5)
- # pedestal (2)
- # re-frame (52)
- # reagent (21)
- # reitit (58)
- # ring-swagger (24)
- # shadow-cljs (95)
- # sql (14)
- # test-check (10)
- # yada (18)
One option is to push the compojure-routes under the default-handler in reitit-ring. One routes
function less on the way to reitit routing tree. Don't think it shows on criterium...
Hi all, is there an idiomatic way to deal with several paths leading to one match? Use case is supporting legacy paths.
could you use a shared value?
(let [endpoint {:get (constantly {:status 200, :body "legacy"})}]
[["/a" endpoint]
["/b" endpoint]])
@ikitommi unfortunately no, because i am doing client side routing as well. I’m using fulcro, and it has some routing machinery which depends primarily on the [:data :name]
of the reitit match
@ikitommi yeah, i’m aware though, that reitit is opinionated against this 😅
could you add a new key like :namez
and use that instead? Or add :alias
and use it if exists, :name
otherwise?
@ikitommi i never thought of that! Will experiment. Thanks for the ideas 😄
fulcro+reitit is a better match than bidi, tbh.
Might not be a reitit question, really. When I call (app ...)
in my tests, the body comes back as an InputStream which I have to decode/format :body
myself.
Should I not get :body
back already decoded for me thanks to muuntaja/format-response-middleware
in my middleware list?
@phil the format-response-middleware
encodes the body to whatever the user requested. So, in tests, you have to decode it with something like (m/decode m/instance "application/edn" data)
(we use mostly edn in tests).
You could also disable the response formatting mw for tests, but you would not be testing the whole app. Could leave room for serialization bugs.
Setting the Accept header tells the formatter to encode the data into something, it's not about decoding.
There could be a testing helper that reads the request headers and auto-decodes the response body accordingly.
@ikitommi I’m looking at reitit.frontend, and I think the history records should be matching by rf/match-by-path
instead of the vanilla reitit/match-by-path
. This way, it automatically takes advantage of query-params support. https://github.com/metosin/reitit/blob/master/modules/reitit-frontend/src/reitit/frontend/history.cljs#L78
ping @juhoteperi, the frontend-reitit lead.
(ns user
(:require [reitit.ring :as ring]
[reitit.ring.middleware.muuntaja :as muuntaja]
[muuntaja.core :as m]))
(def app
(ring/ring-handler
(ring/router
["/" (constantly {:status 200, :body {:kikka "kukka"}})]
{:data {:muuntaja m/instance
:middleware [muuntaja/format-middleware]}})))
(->> (app {:uri "/", :request-method :get})
:body
(m/decode m/instance "application/json"))
; {:kikka "kukka"}
(defn parse-body [response]
(if-let [ct (some->> (get-in response [:headers "Content-Type"]) (re-find #"^(.*?)(?:;|$)") second)]
(->> response :body (m/decode m/instance ct))))
(-> {:uri "/", :request-method :get} app parse-body)
; {:kikka "kukka"}
and with edn:
(-> {:uri "/"
:request-method :get
:headers {"accept" "application/edn"}}
app
parse-body)
; {:kikka "kukka"}
@levitanong Does this cause any problems? The html5 history impl currently ignores query params when checking if anchor link matches routes, and then appends the original query params to pushState call
Parsing query strings from the anchor href and then reconstructing query string would be unnecessary work
@juhoteperi but the query map contains important information for state transformations. I'm currently trying to port over functionality from pushy, but I'm not sure how to move forward :o
@levitanong The result from that match call is not used anywhere. If the anchor href matches route (this match call) then pushState is called with the href and that will trigger on-navigate event which will properly parse the path, including query string.
and on-navigate will use reitit.frontend match-by-path to get the proper match
@juhoteperi Hmm. I'm not getting the query map with the match on start though.
@ikitommi migrating from compojure to reitit (still in progress) was straightforward but still not painless
1. i wasn't sure why ring-handler took a default-handler when we can just use "routes" to compose things
2. trying to add muuntaja was very confusing since in some docs, you used {:data {:muutaja m/instance ..}} whereas trying to add it to the ring-handler, there's just :middleware
3. reitit doesn't coerce certain responses like compojure does, I later found out this was a design decision after looking through github issues, and this difference isn't documented (i assume everyone comes from compojure)
@levitanong Did you try with examples/frontend
from the repository? You need to change the :use-fragment
to false
but after that it should work with HTML5 history. "Item 2" link contains query string.
OH i didn’t realize :use-fragment defaulted to true. Thanks for the pointer!
yup that fixed it. Thanks man!
4. muuntaja in 0.6 no longer encodes if Content-Type is set, so you're screwed (with little feedback as to why) if you get the middleware order incorrect, especially when using things like ring-defaults which adds content-type by default
@kanwei 1. I think one reason is that composing multiple "top level" handler functions can be confusing if you are using certain middlewares with side-effects, this is common with middleware that read the request body input stream, because the stream can be read only once. With default-handler everything is "inside" single handler function so it can be more obvious which middlewares affect handler.
Or maybe Reitit runs the middleware only if request matches routes, in which case middlewares wouldn't cause side-effects so this wouldn't be a problem. I'm not sure.
the arity of ring-handler is also confusing cause you have to do (ring-handler handler nil {options})
if you accidentally do (ring-handler handler {options}) you don't get a warning either
Maybe ring-handler
should assert default-handler
is fn?
or nil
. Map could be used as function but it wouldn't probably make any sense in this case.
@kanwei thanks for the input. Juho already wrote an issue about the arity. Goal is to be able to put reitit to the topmost handler and everything under it, need to clear that out in the docs. This way, things will happen at a right time (conditional mounting of mw, only after match, file io as a last effort etc). In libs like ring-defaults
, a lot of good things happen, but mostly at a bad time.
@kanwei have a look at this: https://github.com/metosin/ring-http-response