+
+ +
+
+ +
+ +

Route Data Validation

+

Route data can be anything, so it's easy to do mistakes. Accidentally using a :role key instead of :roles might render the whole routing app without any authorization in place.

+

To fail fast, we could use the custom :coerce and :compile hooks to apply data validation and throw exceptions on first sighted problem.

+

But there is a better way. Router also has a :validation hook to validate the whole route tree after it's successfuly compiled. It expects a 2-arity function routes opts => () that can side-effect in case of validation errors.

+

clojure.spec

+

Namespace reitit.spec contains specs for main parts of reitit.core and a helper function validate-spec! that runs spec validation for all route data and throws an exception if any errors are found.

+

A Router with invalid route data:

+
(require '[reitit.core :as r])
+
+(r/router
+  ["/api" {:handler "identity"}])
+; #object[reitit.core$...]
+
+

Fails fast with clojure.spec validation turned on:

+
(require '[reitit.spec :as rs])
+
+(r/router
+  ["/api" {:handler "identity"}]
+  {:validate rs/validate-spec!})
+; CompilerException clojure.lang.ExceptionInfo: Invalid route data:
+;
+; -- On route -----------------------
+;
+; "/api"
+;
+; In: [:handler] val: "identity" fails spec: :reitit.spec/handler at: [:handler] predicate: fn?
+;
+; {:problems (#reitit.spec.Problem{:path "/api", :scope nil, :data {:handler "identity"}, :spec :reitit.spec/default-data, :problems #:clojure.spec.alpha{:problems ({:path [:handler], :pred clojure.core/fn?, :val "identity", :via [:reitit.spec/default-data :reitit.spec/handler], :in [:handler]}), :spec :reitit.spec/default-data, :value {:handler "identity"}}})}, compiling: ...
+
+

Customizing spec validation

+

rs/validate-spec! reads the following router options:

+