Skip to content

Commit

Permalink
Touch up reference pages for terse and verbose formats
Browse files Browse the repository at this point in the history
  • Loading branch information
hlship committed Mar 22, 2024
1 parent b53736b commit 8369b5d
Show file tree
Hide file tree
Showing 3 changed files with 68 additions and 14 deletions.
9 changes: 6 additions & 3 deletions docs/modules/reference/pages/terse-syntax.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -58,15 +58,18 @@ footnote:current-and-child[Applies to the current route and any child routes.]
(def routes
[[:hello-world :http
["/order" {:get `list-orders
:post [:post-without-id `create-order]}
["/:id"
["/order" {:get `list-orders <1>
:post [:post-without-id `create-order]} <2>
["/:id" <3>
^:interceptors [load-order-from-db]
^:constraints {:id #"[0-9]+"}
{:get `view-order
:put `update-order
:post [:post-by-id `create-order]}]]]])
----
<1> Pedestal will convert the symbol `myapp.service/list-orders` to a keyword and use that as the route name
<2> The route name will be :post-without-id
<3> Nested routes inherit a path prefix from the containing route; this will match on `/order/:id`.

== Detailed Reference

Expand Down
49 changes: 47 additions & 2 deletions docs/modules/reference/pages/verbose-syntax.adoc
Original file line number Diff line number Diff line change
@@ -1,5 +1,50 @@
= Verbose Syntax

== Placeholder
The verbose syntax is the oldest routing specification format used in Pedestal and should not generally be used,
though it may be of use when generating a route specification from code. It is very close in format
to the expanded routing table.

Verbose syntax is composed of a sequence of maps; each map defines a single route.

[source,clojure]
----
{:app-name <string> <1>
:scheme <:http or :https>
:host <string>
:port <number>
:constraints <map> <2>
:interceptors <vector> <3>
:path <string> <4>
:verbs <map> <5>
:children <vector> <6>
}
----
<1> :app-name, :schema, :host, and :port are optional. They define the values for this route and any children.
<2> :constraints is a map of keyword (matching a path or query parameter) to a regular expression; this is merged into the containing routes constraints
<3> :interceptors is a vector ???; this is appended to the containing route's interceptors
<4> :path is required, and must start with a slash; this is appended to the containing routes path
<5> :verbs is a mapping from keyword (:get, :post, etc.) to handler
<6> :children is an optional list of routes nested within this route

Handlers, the values in the :verbs map, can be a symbol or a map.

A symbol will be resolved to a Var; the value in the Var will be converted to an Interceptor record.
In cases where the interceptor is anonymous (has no :name), the symbol is converted to a keyword and used as the :name.

The :name of the interceptor becomes the name of the route.

When a handler is a map, it has the following keys:

[source,clojure]
----
{:route-name <string> <1>
:handler <...> <2>
:interceptors <vector> <3>
}
----
<1> :route-name is optional and will be derived from the handler.
<2> The handler may be either a symbol or an interceptor.
<3> :interceptors is optional and identifies interceptors appended to the containing route's interceptors

Ultimately, the handler (converted to an interceptor) is appended to the list of interceptors.

*Pull requests welcomed!*
24 changes: 15 additions & 9 deletions route/src/io/pedestal/http/route/definition/verbose.clj
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@
; You must not remove this notice, or any other, from this software.

(ns io.pedestal.http.route.definition.verbose
"Implementation of the verbose routing syntax.
Note that functions marked with ^:no-doc are internal, and may be converted to private
in a future release."
(:require [io.pedestal.http.route.definition :as definition]
[io.pedestal.http.route.path :as path]
[io.pedestal.interceptor :refer [interceptor?] :as i]
Expand All @@ -25,20 +29,20 @@
:enter (fn [context]
(assoc context :response (-> context :request request-fn)))}))

(defn handler-interceptor
(defn ^:no-doc handler-interceptor
[handler name]
(cond
(interceptor? handler) (let [{interceptor-name :name :as interceptor} handler]
(assoc interceptor :name (or interceptor-name name)))
(fn? handler) (handler->interceptor name handler)))


(defn resolve-interceptor [interceptor name]
(defn ^:no-doc resolve-interceptor [interceptor name]
(if (interceptor? interceptor)
(handler-interceptor interceptor name)
(handler-interceptor (io.pedestal.interceptor/interceptor interceptor) name)))

(defn handler-map [m]
(defn ^:no-doc handler-map [m]
(cond
(symbol? m)
(let [handler-name (definition/symbol->keyword m)]
Expand All @@ -50,7 +54,8 @@
handler-name (cond
(symbol? handler) (definition/symbol->keyword handler)
(interceptor? handler) (:name handler))
interceptor (resolve-interceptor handler (or route-name handler-name))
interceptor (resolve-interceptor
handler (or route-name handler-name))
interceptor-name (:name interceptor)]
{:route-name (if route-name
route-name
Expand Down Expand Up @@ -89,18 +94,19 @@
constraint's key identifies a path-param."
[{path-params :path-params :as dna} constraints verbs]
(if (empty? verbs)
(update dna :path-constraints merge (map definition/capture-constraint constraints))
(update dna :path-constra
ints merge (map definition/capture-constraint constraints))
(let [path-param? (fn [[k _]] (some #{k} path-params))
[path-constraints query-constraints] ((juxt filter remove) path-param? constraints)]
(-> dna
(update :path-constraints merge (into {} (map definition/capture-constraint path-constraints)))
(update :query-constraints merge query-constraints)))))

(defn undoubleslash
(defn ^:no-doc undoubleslash
[^String s]
(string/replace s #"/+" "/"))

(defn path-join
(defn ^:no-doc path-join
[parent-path path]
(str parent-path "/" path))

Expand All @@ -112,7 +118,7 @@
(cond-> parent-dna
true (merge (select-keys current-node [:app-name :scheme :host :port]))
path (path/parse-path path)
;; special case case where parent-path is "/" so we don't have double "//"
;; special case where parent-path is "/" so we don't have double "//"
path (assoc :path (undoubleslash (path-join parent-path path)))
constraints (update-constraints constraints verbs)
interceptors (update :interceptors
Expand All @@ -127,7 +133,7 @@
(concat (map #(generate-verb-terminal current-dna %) verbs)
(mapcat #(generate-route-entries current-dna %) children))))

(def default-dna
(def ^:no-doc default-dna
{:path-parts []
:path-params []
:interceptors []})
Expand Down

0 comments on commit 8369b5d

Please sign in to comment.