Skip to content
Tommi Reiman edited this page Jun 25, 2018 · 1 revision

Compojure is a dynamic routing library: one can generate easily new routes at request-time. Good example of this is the context macro. With normal Compojure, the body of the context is re-evaluated with each request. This is good as it enables new routes to be added on fly, based on request. This is (bit) bad for performance as the child route trees are re-evaluated per each request.

Compojure-api does things bit differently. context is static by default and automatically transformed into dynamic version if the child routes close over any request-bound data in the parent contexts. For example, adding a :query-params [q :- s/Str annotation into a context dynamic as the q is request-bound and is visible to the child routes. One can also mark routes with :dynamic true to force the request-based child trees.

Let's play in the repl.

Static routes

Marked in the compiled routes with {:static-context? true}.

(require '[compojure.api.sweet :refer :all])
(require '[ring.util.http-response :refer :all])

(api
  (context "/api" []
    (context "/ipa" []
      (GET "/drink" []
        (ok {:was "good"})))))
;#Route{:info {:coercion :schema},
;       :childs [#Route{:childs [#Route{:path "/api",
;                                       :info {:static-context? true},
;                                       :childs [#Route{:path "/ipa",
;                                                       :info {:static-context? true},
;                                                       :childs [#Route{:path "/drink", :method :get}]}]}]}]}

Dynamic routes

q is request-bound and makes the whole subtree dynamic.

(api
  (context "/api" []
    :query-params [q :- String]
    (context "/ipa" []
      (GET "/drink" []
        (ok {:was "good"})))))
;#Route{:info {:coercion :schema},
;       :childs [#Route{:childs [#Route{:path "/api",
;                                       :info {:public {:parameters {:query {Keyword Any, :q java.lang.String}}}},
;                                       :childs [#Route{:path "/ipa",
;                                                       :info {:static-context? true},
;                                                       :childs [#Route{:path "/drink", :method :get}]}]}]}]}

Why bother with the static contexts?

Performance.

Mostly it doesn't matter, but sometimes it does.