Codebase list comidi-clojure / d197b44
(SERVER-777) Make use of Bidi schema introduced in 1.20.0 Bidi introduced schema in 1.20.0 and there are some deviations between ours and theirs. This commit modifies Comidi to use the Bidi schema where possible and makes some small updates to the remainder to align a bit better. Scott Walker 8 years ago
3 changed file(s) with 26 addition(s) and 77 deletion(s). Raw diff Collapse all Expand all
77 [org.clojure/tools.reader "0.8.9"]
88 [ring/ring-core "1.3.2"]
99 [commons-io "2.4"]
10 [bidi "1.18.9" :exclusions [org.clojure/clojurescript]]
10 [bidi "1.21.0" :exclusions [org.clojure/clojurescript]]
1111 [compojure "1.3.3"]
12 [prismatic/schema "0.4.0"]
12 [prismatic/schema "0.4.3"]
1313 [puppetlabs/kitchensink "1.1.0"]]
1414
1515 :deploy-repositories [["releases" {:url "https://clojars.org/repo"
00 (ns puppetlabs.comidi
11 (:require [bidi.ring :as bidi-ring]
2 [bidi.schema :as bidi-schema]
23 [bidi.bidi :as bidi]
34 [clojure.zip :as zip]
45 [compojure.core :as compojure]
2021 (schema/pred ks/zipper?))
2122
2223 (def http-methods
23 #{:any :get :post :put :delete :head})
24 #{:any :get :post :put :delete :head :options})
2425
2526 (def RequestMethod
26 (schema/enum :any :get :post :put :delete :head))
27
28 (def RegexPathElement
27 (schema/enum :any :get :post :put :delete :head :options))
28
29 (def RegexPatternSegment
2930 [(schema/one Pattern "regex") (schema/one schema/Keyword "variable")])
3031
31 (def PathElement
32 (schema/conditional
33 string? schema/Str
34 keyword? schema/Keyword
35 vector? RegexPathElement))
36
3732 (def RouteInfo
38 {:path [PathElement]
33 {:path [bidi-schema/PatternSegment]
3934 :request-method RequestMethod})
4035
4136 (def RouteInfoWithId
5146 (def RouteMetadata
5247 {:routes [RouteInfoWithId]
5348 :handlers {Handler RouteInfoWithId}})
54
55 (def BidiPattern
56 (schema/conditional
57 keyword? schema/Keyword
58 string? schema/Str
59 sequential? [PathElement]))
60
61 (def BidiRouteDestination
62 (schema/conditional
63 #(nil? (schema/check Handler %)) Handler
64 :else [[(schema/one BidiPattern "pattern")
65 (schema/one (schema/recursive #'BidiRouteDestination) "destination")]]))
66
67 (def BidiRoute
68 [(schema/one BidiPattern "pattern")
69 (schema/one BidiRouteDestination "destination")])
7049
7150 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
7251 ;;; Private - route id computation
11897 regex-path-element->route-id-element :- schema/Str
11998 "Given a Regex path element from comidi route metadata, convert it into a string
12099 suitable for use in building a route id string."
121 [path-element :- RegexPathElement]
100 [path-element :- RegexPatternSegment]
122101 (-> path-element
123102 first
124103 str
131110 suitable for use in building a route id string. This function is mostly
132111 responsible for determining the type of the path element and dispatching to
133112 the appropriate function."
134 [path-element :- PathElement]
113 [path-element :- bidi-schema/PatternSegment]
135114 (cond
136115 (string? path-element)
137116 (path-element->route-id-element path-element)
139118 (keyword? path-element)
140119 (pr-str path-element)
141120
142 (nil? (schema/check RegexPathElement path-element))
121 (nil? (schema/check RegexPatternSegment path-element))
143122 (regex-path-element->route-id-element path-element)
144123
145124 :else
149128 route-path->route-id :- schema/Str
150129 "Given a route path (from comidi route-metadata), build a route-id string for
151130 the route. This route-id can be used as a unique identifier for a route."
152 [route-path :- BidiPattern]
131 [route-path :- bidi-schema/Pattern]
153132 (->> route-path
154133 (map route-path-element->route-id-element)
155134 (filter #(not (empty? %)))
170149 the current path elements of a route as we traverse the Bidi route tree via
171150 zipper."
172151 [route-info :- RouteInfo
173 pattern :- BidiPattern]
152 pattern :- bidi-schema/Pattern]
174153 (cond
175154 (contains? http-methods pattern)
176155 (assoc-in route-info [:request-method] pattern)
177156
178 (nil? (schema/check RegexPathElement pattern))
157 (nil? (schema/check RegexPatternSegment pattern))
179158 (update-in route-info [:path] concat [pattern])
180159
181160 (sequential? pattern)
235214 "Traverses a Bidi route tree and returns route metadata, which includes a list
236215 of RouteInfo objects (one per route), plus a mechanism to look up the
237216 RouteInfo for a given handler."
238 [routes :- BidiRoute]
217 [routes :- bidi-schema/RoutePair]
239218 (let [route-info {:path []
240219 :request-method :any}
241220 loc (-> [routes] zip/vector-zip zip/down)]
293272 "Build up a map of metadata describing the routes. This metadata map can be
294273 used for introspecting the routes after building the handler, and can also
295274 be used with the `wrap-with-route-metadata` middleware."
296 [routes :- BidiRoute]
275 [routes :- bidi-schema/RoutePair]
297276 (memoized-route-metadata* routes))
298277
299278 (schema/defn ^:always-validate
302281 as a :route-info key that can be used to determine which route a given request
303282 matches."
304283 [app :- (schema/pred fn?)
305 routes :- BidiRoute]
284 routes :- bidi-schema/RoutePair]
306285 (let [compiled-routes (bidi/compile-route routes)
307286 route-meta (route-metadata routes)]
308287 (fn [{:keys [uri path-info] :as req}]
316295 :match-context match-context))))))
317296
318297 (schema/defn ^:always-validate
319 routes :- BidiRoute
298 routes :- bidi-schema/RoutePair
320299 "Combines multiple bidi routes into a single data structure; this is largely
321300 just a convenience function for grouping several routes together as a single
322301 object that can be passed around."
323 [& routes :- [BidiRoute]]
302 [& routes :- [bidi-schema/RoutePair]]
324303 ["" (vec routes)])
325304
326305 (schema/defn ^:always-validate
327 context :- BidiRoute
306 context :- bidi-schema/RoutePair
328307 "Combines multiple bidi routes together into a single data structure, but nests
329308 them all under the given url-prefix. This is similar to compojure's `context`
330309 macro, but does not accept a binding form. You can still destructure variables
331310 by passing a bidi pattern for `url-prefix`, and the variables will be available
332311 to all nested routes."
333 [url-prefix :- BidiPattern
334 & routes :- [BidiRoute]]
312 [url-prefix :- bidi-schema/Pattern
313 & routes :- [bidi-schema/RoutePair]]
335314 [url-prefix (vec routes)])
336315
337316 (schema/defn ^:always-validate
339318 "Given a bidi route tree, converts into a ring request handler function. You
340319 may pass an optional handler function which will be wrapped around the
341320 bidi leaf."
342 ([routes :- BidiRoute
321 ([routes :- bidi-schema/RoutePair
343322 handler-fn :- (schema/maybe (schema/pred fn?))]
344323 (let [compiled-routes (bidi/compile-route routes)]
345324 (make-handler compiled-routes handler-fn)))
2424 (is (nil? (schema/check Handler {:get (fn [] :foo)})))
2525 (is (nil? (schema/check Handler {:post :foo})))))
2626
27 (deftest pattern-schema-test
28 (testing "pattern schema"
29 (is (nil? (schema/check BidiPattern "/foo")))
30 (is (nil? (schema/check BidiPattern :foo)))
31 (is (nil? (schema/check BidiPattern ["/foo/" :foo "/foo"])))
32 (is (nil? (schema/check BidiPattern ["/foo/" [#".*" :rest]])))))
33
34 (deftest destination-schema-test
35 (testing "route destination schema"
36 (is (nil? (schema/check BidiRouteDestination :foo)))
37 (is (nil? (schema/check BidiRouteDestination (fn [] nil))))
38 (is (nil? (schema/check BidiRouteDestination {:get (fn [] nil)})))
39 (is (nil? (schema/check BidiRouteDestination {:get :my-handler})))
40 (is (nil? (schema/check BidiRouteDestination [[["/foo/" :foo "/foo"] :foo]])))
41 (is (not (nil? (schema/check BidiRouteDestination [["/foo/" :foo "/foo"] :foo]))))
42 (is (nil? (schema/check BidiRouteDestination [[["/foo/" :foo]
43 :foo-handler]
44 [["/bar/" :bar]
45 {:get :bar-handler}]])))))
46
47 (deftest route-schema-test
48 (testing "route schema"
49 (is (nil? (schema/check BidiRoute [:foo :foo])))
50 (is (nil? (schema/check BidiRoute ["/foo" [[:foo :foo]]])))
51 (is (not (nil? (schema/check BidiRoute ["/foo" [:foo :foo]]))))
52 (is (nil? (schema/check BidiRoute ["" [[["/foo/" :foo]
53 :foo-handler]
54 [["/bar/" :bar]
55 {:get :bar-handler}]]])))))
56
5727 (deftest update-route-info-test
5828 (let [orig-route-info {:path []
5929 :request-method :any}]
6939 (testing "keyword path elements get added to the path"
7040 (is (= {:path [:foo]
7141 :request-method :any}
72 (update-route-info* orig-route-info :foo))))
42 (update-route-info* orig-route-info [:foo]))))
7343 (testing "vector path elements get flattened and added to the path"
7444 (is (= {:path ["/foo/" :foo]
7545 :request-method :any}
8757 [["/bar/" :bar]
8858 [["/baz" {:get :baz-handler}]
8959 ["/bam" {:put :bam-handler}]
90 ["/bap" {:any :bap-handler}]]]
60 ["/bap" {:options :bap-handler}]]]
9161 ["/buzz" {:post :buzz-handler}]]]
9262 expected-foo-meta {:path ["" "/foo/" :foo]
9363 :route-id "foo-:foo"
10070 :request-method :put}
10171 expected-bap-meta {:path ["" "/bar/" :bar "/bap"]
10272 :route-id "bar-:bar-bap"
103 :request-method :any}
73 :request-method :options}
10474 expected-buzz-meta {:path ["" "/buzz"]
10575 :route-id "buzz"
10676 :request-method :post}]