Merge pull request #554 from just-sultanov/add-support-for-fragment-parameters

Add support for fragment parameters in the reitit-frontend module
This commit is contained in:
Tommi Reiman 2023-01-09 17:33:24 +02:00 committed by GitHub
commit c2c267f4d8
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 54 additions and 12 deletions

View file

@ -39,7 +39,8 @@
:body (->ParameterCoercion :body-params :body false false) :body (->ParameterCoercion :body-params :body false false)
:form (->ParameterCoercion :form-params :string true true) :form (->ParameterCoercion :form-params :string true true)
:header (->ParameterCoercion :headers :string true true) :header (->ParameterCoercion :headers :string true true)
:path (->ParameterCoercion :path-params :string true true)}) :path (->ParameterCoercion :path-params :string true true)
:fragment (->ParameterCoercion :fragment-params :string true true)})
(defn ^:no-doc request-coercion-failed! [result coercion value in request serialize-failed-result] (defn ^:no-doc request-coercion-failed! [result coercion value in request serialize-failed-result]
(throw (throw

View file

@ -1,5 +1,6 @@
(ns reitit.frontend (ns reitit.frontend
(:require [clojure.set :as set] (:require [clojure.set :as set]
[clojure.string :as str]
[reitit.coercion :as coercion] [reitit.coercion :as coercion]
[reitit.core :as r]) [reitit.core :as r])
(:import goog.Uri (:import goog.Uri
@ -20,6 +21,19 @@
(map (juxt keyword #(query-param q %))) (map (juxt keyword #(query-param q %)))
(into {})))) (into {}))))
(defn fragment-params
"Given goog.Uri, read fragment parameters into Clojure map."
[^Uri uri]
(let [fp (.getFragment uri)]
(if-not (seq fp)
{}
(into {}
(comp
(map #(str/split % #"="))
(map (fn [[k v]]
[(keyword k) v])))
(str/split fp #"&")))))
(defn match-by-path (defn match-by-path
"Given routing tree and current path, return match with possibly "Given routing tree and current path, return match with possibly
coerced parameters. Return nil if no match found. coerced parameters. Return nil if no match found.
@ -37,12 +51,14 @@
coercion/coerce!)] coercion/coerce!)]
(if-let [match (r/match-by-path router (.getPath uri))] (if-let [match (r/match-by-path router (.getPath uri))]
(let [q (query-params uri) (let [q (query-params uri)
match (assoc match :query-params q) fp (fragment-params uri)
match (assoc match :query-params q :fragment-params fp)
;; Return uncoerced values if coercion is not enabled - so ;; Return uncoerced values if coercion is not enabled - so
;; that tha parameters are always accessible from same property. ;; that tha parameters are always accessible from same property.
parameters (or (coerce! match) parameters (or (coerce! match)
{:path (:path-params match) {:path (:path-params match)
:query q})] :query q
:fragment fp})]
(assoc match :parameters parameters)))))) (assoc match :parameters parameters))))))
(defn match-by-name (defn match-by-name

View file

@ -21,9 +21,11 @@
:data {:name ::frontpage} :data {:name ::frontpage}
:path-params {} :path-params {}
:query-params {} :query-params {}
:fragment-params {}
:path "/" :path "/"
:parameters {:query {} :parameters {:query {}
:path {}}}) :path {}
:fragment {}}})
(rf/match-by-path router "/"))) (rf/match-by-path router "/")))
(is (= "/" (is (= "/"
@ -34,9 +36,11 @@
:data {:name ::foo} :data {:name ::foo}
:path-params {} :path-params {}
:query-params {} :query-params {}
:fragment-params {}
:path "/foo" :path "/foo"
:parameters {:query {} :parameters {:query {}
:path {}}}) :path {}
:fragment {}}})
(rf/match-by-path router "/foo"))) (rf/match-by-path router "/foo")))
(is (= (r/map->Match (is (= (r/map->Match
@ -44,9 +48,11 @@
:data {:name ::foo} :data {:name ::foo}
:path-params {} :path-params {}
:query-params {:mode ["foo", "bar"]} :query-params {:mode ["foo", "bar"]}
:fragment-params {}
:path "/foo" :path "/foo"
:parameters {:query {:mode ["foo", "bar"]} :parameters {:query {:mode ["foo", "bar"]}
:path {}}}) :path {}
:fragment {}}})
(rf/match-by-path router "/foo?mode=foo&mode=bar"))) (rf/match-by-path router "/foo?mode=foo&mode=bar")))
(is (= "/foo" (is (= "/foo"
@ -64,7 +70,12 @@
(let [router (r/router ["/" (let [router (r/router ["/"
[":id" {:name ::foo [":id" {:name ::foo
:parameters {:path {:id s/Int} :parameters {:path {:id s/Int}
:query {(s/optional-key :mode) s/Keyword}}}]] :query {(s/optional-key :mode) s/Keyword}
:fragment {(s/optional-key :access_token) s/Str
(s/optional-key :refresh_token) s/Str
(s/optional-key :expires_in) s/Int
(s/optional-key :provider_token) s/Str
(s/optional-key :token_type) s/Str}}}]]
{:compile rc/compile-request-coercers {:compile rc/compile-request-coercers
:data {:coercion rsc/coercion}})] :data {:coercion rsc/coercion}})]
@ -72,9 +83,11 @@
{:template "/:id" {:template "/:id"
:path-params {:id "5"} :path-params {:id "5"}
:query-params {} :query-params {}
:fragment-params {}
:path "/5" :path "/5"
:parameters {:query {} :parameters {:query {}
:path {:id 5}}}) :path {:id 5}
:fragment {}}})
(m (rf/match-by-path router "/5")))) (m (rf/match-by-path router "/5"))))
(is (= "/5" (is (= "/5"
@ -98,23 +111,35 @@
{:template "/:id" {:template "/:id"
:path-params {:id "5"} :path-params {:id "5"}
:query-params {:mode "foo"} :query-params {:mode "foo"}
:fragment-params {}
:path "/5" :path "/5"
:parameters {:path {:id 5} :parameters {:path {:id 5}
:query {:mode :foo}}}) :query {:mode :foo}
:fragment {}}})
(m (rf/match-by-path router "/5?mode=foo")))) (m (rf/match-by-path router "/5?mode=foo"))))
(is (= "/5?mode=foo" (is (= "/5?mode=foo"
(r/match->path (rf/match-by-name router ::foo {:id 5}) {:mode :foo})))) (r/match->path (rf/match-by-name router ::foo {:id 5}) {:mode :foo}))))
(testing "fragment is ignored" (testing "fragment is read"
(is (= (r/map->Match (is (= (r/map->Match
{:template "/:id" {:template "/:id"
:path-params {:id "5"} :path-params {:id "5"}
:query-params {:mode "foo"} :query-params {:mode "foo"}
:fragment-params {:access_token "foo"
:refresh_token "bar"
:provider_token "baz"
:token_type "bearer"
:expires_in "3600"}
:path "/5" :path "/5"
:parameters {:path {:id 5} :parameters {:path {:id 5}
:query {:mode :foo}}}) :query {:mode :foo}
(m (rf/match-by-path router "/5?mode=foo#fragment"))))) :fragment {:access_token "foo"
:refresh_token "bar"
:provider_token "baz"
:token_type "bearer"
:expires_in 3600}}})
(m (rf/match-by-path router "/5?mode=foo#access_token=foo&refresh_token=bar&provider_token=baz&token_type=bearer&expires_in=3600")))))
(testing "console warning about missing params" (testing "console warning about missing params"
(is (= [{:type :warn (is (= [{:type :warn