reitit

https://cljdoc.org/d/metosin/reitit/ https://github.com/metosin/reitit/
Eric Ihli 2020-10-31T00:05:59.231600Z

Ok, I've pinpointed a good example of the issue I'm facing. Is the expected behavior that it's not possible to mix coerced routes with non-coerced routes?

(ns reitit.coercion-test
  (:require [clojure.test :refer [deftest testing is]]
            [schema.core :as s]
            [spec-tools.data-spec :as ds]
            [reitit.core :as r]
            [reitit.coercion :as coercion]
            [reitit.coercion.spec]
            [reitit.coercion.malli]
            [reitit.coercion.schema])
  #?(:clj
     (:import (clojure.lang ExceptionInfo))))

(deftest basic-path-test
  (let [handler (fn [_])
        r (r/router
           [["/foo" {:handler handler}]])]
    (testing "non-coercion path"
      (let [m (r/match-by-path r "/foo")]
        ;;
        ;; This passes. The result of the match is equal to the handler.
        (is (= (:result m) handler))))))

(basic-path-test)

(deftest mixed-coercion-with-non-coercion-test
  (let [handler (fn [])
        r (r/router
           [["/foo" {:handler handler}]
            ["/schema" {:coercion reitit.coercion.schema/coercion}
             ["/:number" {:parameters {:path {:number s/Int}}}]]]
           {:compile coercion/compile-request-coercers})]

    (testing "coercion path"
      (let [m (r/match-by-path r "/schema/1")]
        (is (= {:path {:number 1}}
               (coercion/coerce! m)))))

    (testing "non-coercion path"
      (let [m (r/match-by-path r "/foo")]
        ;;
        ;; This fails. The result of the match is nil.
        (is (= (:result m) handler))))))

(mixed-coercion-with-non-coercion-test)

Dave Russell 2020-10-31T13:08:14.246900Z

Hey folks! We're beginning our compojure -> reitit conversion and have an interesting challenge with converting some of our routes that use compojure's dynamism. Basically, we have a bunch of API endpoints that delegate some of their routes to a set of "common" methods. For example:

(context "/foo/"
  ....
  custom routes
  ....
  (generic-routes foo-specific args))

(context "/bar/"
  ....
  custom routes
  ....
  (generic-routes bar-specific args))
Where generic-routes generates a set of endpoints under both of these contexts, and passes some args to the generic handlers so that they can be specialized:
(generic-routes [args]
  (routes
    GET "/baz" [] (do-something args)))
The above would generate both /foo/baz/ and /bar/baz/, but with specialized handlers for each of these endpoints. I've read the docs on composing routers, and I think https://cljdoc.org/d/metosin/reitit/0.5.10/doc/advanced/composing-routers#nesting-routers is mostly the behavior that we want -- we don't need dynamic routers -- but I don't see an immediate way how nested routers could perform the "specialization" of the generic routes. To this end -- I have been successful in writing a macro that basically copies the reitit hiccup routes representing generic behaviour into each of the API endpoints, and creates the "specialized" handlers in doing so, but it seems kinda... unidiomatic? So -- is there a better way to do this? 😛