This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2018-06-14
Channels
- # beginners (183)
- # boot (6)
- # cider (106)
- # cljs-dev (17)
- # cljsjs (2)
- # cljsrn (2)
- # clojure (56)
- # clojure-italy (14)
- # clojure-nl (39)
- # clojure-spec (49)
- # clojure-uk (138)
- # clojurescript (197)
- # core-logic (37)
- # cursive (22)
- # datascript (5)
- # datomic (29)
- # devcards (18)
- # emacs (1)
- # events (8)
- # figwheel (1)
- # fulcro (59)
- # lein-figwheel (1)
- # leiningen (1)
- # off-topic (54)
- # onyx (3)
- # pedestal (1)
- # portkey (4)
- # re-frame (18)
- # reagent (5)
- # reitit (43)
- # ring (6)
- # ring-swagger (26)
- # shadow-cljs (42)
- # spacemacs (8)
- # specter (12)
- # sql (3)
- # tools-deps (21)
- # vim (18)
hey guys, I wonder if someone has an example of bidirectional routing?
For instance if I have a GET request returning a list of items and I want that list to have href links
@roklenarcic something like this?:
(require '[reitit.core :as r])
(require '[reitit.ring :as ring])
(def app
(ring/ring-handler
(ring/router
[["/users" {:get (fn [{:keys [::r/router]}]
{:status 200
:body (for [i (range 10)]
{:uri (:path (r/match-by-name router ::user {:id i}))})})}]
["/users/:id" {:name ::user
:get (constantly {:status 200, :body "user..."})}]])))
(app {:request-method :get, :uri "/users"})
;{:status 200,
; :body [{:uri "/users/0"}
; {:uri "/users/1"}
; {:uri "/users/2"}
; {:uri "/users/3"}
; {:uri "/users/4"}
; {:uri "/users/5"}
; {:uri "/users/6"}
; {:uri "/users/7"}
; {:uri "/users/8"}
; {:uri "/users/9"}]}
e.g. the router
(and match
) are injected into request and can be used to reverse route to named endpoints
the default coercion (e.g. used in frontend routing) will coerce in future all parameter types, not just path-params, just define :query
params for the route and inject them into Match
and enjoy:
(def router
(reitit.core/router
["/spec" {:coercion reitit.coercion.spec/coercion}
["/:number/:keyword" {:parameters {:path {:number int?
:keyword keyword?}
:query (ds/maybe {:int int?})}}]]
{:compile reitit.coercion/compile-request-coercers}))
(-> (reitit.core/match-by-path router "/spec/10/kikka")
(assoc :query-params {:int "10"})
(reitit.coercion/coerce!))
; {:path {:number 10, :keyword :kikka}
; :query {:int 10}}
@ikitommi yeah like that but also with query params
not just path params
let's say I request /users?lang=en
, then I want all my links to have that too
(match-by-name [this name] [this name path-params])
=> (match-by-name [this name] [this name path-params] [this name path-params query-params])
there's also a bit of a problem with declaration ordering
hmmm.. actually, I think the query-parameters are not part of the route match, so it could be done on top of the router protocol method.
the frontend routing PR already implements query string logic, but perhaps on the wrong level
so usually my declarations are ordered like this handlers
, used by router
declaration
but now I would use match-by-name
which requires a router in my handlers
handler's emit responses with links, for which they need router, and the router needs to be defined after handlers
@juhoteperi the encoding & decoding query strings is needed also here, yes, maybe move functions into impl
?
the implementation is different between not only jvm/js but also node/browser so not sure how this should be done
@roklenarcic the ring-handler get’s the preconfigured router and emits that into a request. the handler only requires the :name
of the route it’s linked to, so there is loose coupling. I guess you also know the routes names ahead-of-time. I’m not sure I understand the problem yet.
e.g. you don’t need a hard reference to the router instance, you get it injected in.
ah, under :reitit.core/router
@juhoteperi can you find a common base for cljs? I think we only need encode-query-string
and decode-query-string
in the core. And the first should use the IntoString
protocol from the impl.
@juhoteperi @roklenarcic how about: https://github.com/metosin/reitit/pull/104/commits/1923f2d08e2342998e192037d476c12f8b921d3c
(require '[reitit.core :as r])
(-> (r/router ["/:a/:b" ::route])
(r/match-by-name! ::route {:a "olipa", :b "kerran"})
(r/match->path))
; "/olipa/kerran"
(-> (r/router ["/:a/:b" ::route])
(r/match-by-name! ::route {:a "olipa", :b "kerran"})
(r/match->path {:iso "pöriläinen"}))
; "/olipa/kerran?iso=p%C3%B6ril%C3%A4inen"
and as it’s a separate function on top of match, doesn’t pollute the existing router implementations.
idea: we could optionally coerce the parameters in reverse routing too, as the match contains all the needed info. e.g. if the :a
:path
-param would be defined as int?
defined we could fail as the endpoint would not accept a path with :a
as "olipa"
string.
that's works fine for my purposes
is that url-encoded?
oh it is
great