Ring route validation works [just like with core router](../basics/route_data_validation.md), with few differences:
*`reitit.ring.spec/validate-spec!` should be used instead of `reitit.spec/validate-spec!` - to support validating all endpoints (`:get`, `:post` etc.)
* With `clojure.spec` validation, Middleware can contribute to route spec via `:specs` key. The effective route data spec is router spec merged with middleware specs.
## Example
A simple app with spec-validation turned on:
```clj
(require '[clojure.spec.alpha :as s])
(require '[reitit.ring :as ring])
(require '[reitit.ring.spec :as rrs])
(require '[reitit.spec :as rs])
(require '[expound.alpha :as e])
(defn handler [_]
{:status 200, :body "ok"})
(def app
(ring/ring-handler
(ring/router
["/api"
["/public"
["/ping" {:get handler}]]
["/internal"
["/users" {:get {:handler handler}
:delete {:handler handler}}]]]
{:validate rrs/validate-spec!
::rs/explain e/expound-str})))
```
All good:
```clj
(app {:request-method :get
:uri "/api/internal/users"})
; {:status 200, :body "ok"}
```
### Explicit specs via middleware
Middleware that requires `:zone` to be present in route data:
Adding the `:zone` to route data fixes the problem:
```clj
(def app
(ring/ring-handler
(ring/router
["/api" {:middleware [zone-middleware]}
["/public" {:zone :public} ;; <---added
["/ping" {:get handler}]]
["/internal" {:zone :internal} ;; <---added
["/users" {:get {:handler handler}
:delete {:handler handler}}]]]
{:validate rrs/validate-spec!
::rs/explain e/expound-str})))
(app {:request-method :get
:uri "/api/internal/users"})
; in zone :internal
; => {:status 200, :body "ok"}
```
### Implicit specs
By design, clojure.spec validates all fully-qualified keys with `s/keys` specs even if they are not defined in that keyset. Validation in implicit but powerful.
Let's reuse the `wrap-enforce-roles` from [Dynamic extensions](dynamic_extensions.md) and define specs for the data:
Ability to define (and reuse) route-data in mid-paths is a powerful feature, but having data defined all around might be harder to reason about. There is always an option to define all data at the endpoints.