Updated docs

This commit is contained in:
Tommi Reiman 2017-12-10 17:46:29 +02:00
parent 715968a5d2
commit 39e2e1b11e
6 changed files with 143 additions and 104 deletions

View file

@ -10,6 +10,9 @@
* [Route Conflicts](basics/route_conflicts.md)
* [Coercion](coercion/README.md)
* [Coercion Explained](coercion/coercion.md)
* [Plumatic Schema](coercion/schema_coercion.md)
* [Clojure.spec](coercion/clojure_spec_coercion.md)
* [Data-specs](coercion/data_spec_coercion.md)
* [Advanced](advanced/README.md)
* [Configuring Routers](advanced/configuring_routers.md)
* [Different Routers](advanced/different_routers.md)

View file

@ -1,3 +1,6 @@
# Coercion
* [Coercion Explained](coercion.md)
* [Plumatic Schema](schema_coercion.md)
* [Clojure.spec](clojure_spec_coercion.md)
* [Data-specs](data_spec_coercion.md)

View file

@ -0,0 +1,50 @@
# Clojure.spec Coercion
The [clojure.spec](https://clojure.org/guides/spec) library specifies the structure of data, validates or destructures it, and can generate data based on the spec.
**NOTE**: Currently, `clojure.spec` [doesn't support runtime transformations via conforming](https://dev.clojure.org/jira/browse/CLJ-2116), so one needs to wrap all specs into [Spec Records](https://github.com/metosin/spec-tools/blob/master/README.md#spec-records) to get the coercion working.
```clj
(require '[reitit.coercion.spec])
(require '[reitit.coercion :as coercion])
(require '[spec-tools.spec :as spec])
(require '[clojure.spec.alpha :as s])
(require '[reitit.core :as r])
;; need to wrap the primitives!
(s/def ::company spec/string?)
(s/def ::user-id spec/int?)
(s/def ::path-params (s/keys :req-un [::company ::user-id]))
(def router
(r/router
["/:company/users/:user-id" {:name ::user-view
:coercion reitit.coercion.spec/coercion
:parameters {:path ::path-params}}]
{:compile coercion/compile-request-coercers}))
(defn route-and-coerce! [path]
(if-let [match (r/match-by-path router path)]
(assoc match :parameters (coercion/coerce! match))))
```
Successful coercion:
```clj
(route-and-coerce! "/metosin/users/123")
; #Match{:template "/:company/users/:user-id",
; :data {:name :user/user-view,
; :coercion #SpecCoercion{...}
; :parameters {:path ::path-params}},
; :result {:path #object[reitit.coercion$request_coercer$]},
; :params {:company "metosin", :user-id "123"},
; :parameters {:path {:company "metosin", :user-id 123}}
; :path "/metosin/users/123"}
```
Failing coercion:
```clj
(route-and-coerce! "/metosin/users/ikitommi")
; => ExceptionInfo Request coercion failed...
```

View file

@ -1,104 +0,0 @@
# Coercion
Coercion is a process of transforming parameters from one format into another.
By default, all wildcard and catch-all parameters are parsed as Strings:
```clj
(require '[reitit.core :as r])
(def router
(r/router
["/:company/users/:user-id" ::user-view]))
```
Here's a match:
```clj
(r/match-by-path r "/metosin/users/123")
; #Match{:template "/:company/users/:user-id",
; :data {:name :user/user-view},
; :result nil,
; :params {:company "metosin", :user-id "123"},
; :path "/metosin/users/123"}
```
To enable parameter coercion, we need to do few things:
1. Choose a `Coercion` for the routes
2. Defined types for the parameters
3. Compile coercers for the types
4. Apply the coercion
## Coercion
`Coercion` is a protocol defining how types can be defined, coerced and inventoried.
Reitit ships with the following coercion modules:
* `reitit.coercion.schema/coercion` for [plumatic schema](https://github.com/plumatic/schema).
* `reitit.coercion.spec/coercion` for both [clojure.spec](https://clojure.org/about/spec) and [data-specs](https://github.com/metosin/spec-tools#data-specs).
Coercion can be attached to routes using a `:coercion` key in the route data. There can be multiple `Coercion` implementation into a single router, normal [scoping rules](../basics/route_data.html#nested-route-data) apply here too.
## Defining types for parameters
Route parameters can be defined via route data `:parameters`. It can be submaps to define different types of parameters: `:query`, `:body`, `:form`, `:header` and `:path`. Syntax for the actual parameters is defined by the `Coercion` being used.
#### Schema
```clj
(require '[reitit.coercion.schema])
(require '[schema.core :as schema])
(def router
(r/router
["/:company/users/:user-id" {:name ::user-view
:coercion reitit.coercion.schema/coercion
:parameters {:path {:company schema/Str
:user-id schema/Int}]))
```
#### Clojure.spec
Currently, `clojure.spec` [doesn't support runtime transformations via conforming](https://dev.clojure.org/jira/browse/CLJ-2116), so one needs to wrap all specs with `spec-tools.core/spec` to get this working.
```clj
(require '[reitit.coercion.spec])
(require '[spec-tools.spec :as spec])
(require '[clojure.spec :as s])
(s/def ::company spec/string?
(s/def ::user-id spec/int?
(s/def ::path-params (s/keys :req-un [::company ::user-id]))
(def router
(r/router
["/:company/users/:user-id" {:name ::user-view
:coercion reitit.coercion.spec/coercion
:parameters {:path ::path-params]))
```
#### Data-specs
```clj
(require '[reitit.coercion.spec])
(def router
(r/router
["/:company/users/:user-id" {:name ::user-view
:coercion reitit.coercion.spec/coercion
:parameters {:path {:company str?
:user-id int?}]))
```
So, now we have our
### Thanks to
Most of the thing are just redefined version of the original implementation. Big thanks to:
* [compojure-api](https://clojars.org/metosin/compojure-api) for the initial `Coercion` protocol
* [ring-swagger](https://github.com/metosin/ring-swagger#more-complete-example) for the syntax for the `:paramters` (and `:responses`).

View file

@ -0,0 +1,43 @@
# Data-spec Coercion
[Data-specs](https://github.com/metosin/spec-tools#data-specs) is alternative, macro-free syntax to define `clojure.spec`s. As a bonus, supports the [runtime transformations via conforming](https://dev.clojure.org/jira/browse/CLJ-2116) out-of-the-box.
```clj
(require '[reitit.coercion.spec])
(require '[reitit.coercion :as coercion])
(require '[reitit.core :as r])
(def router
(r/router
["/:company/users/:user-id" {:name ::user-view
:coercion reitit.coercion.spec/coercion
:parameters {:path {:company string?
:user-id int?}}}]
{:compile coercion/compile-request-coercers}))
(defn route-and-coerce! [path]
(if-let [match (r/match-by-path router path)]
(assoc match :parameters (coercion/coerce! match))))
```
Successful coercion:
```clj
(route-and-coerce! "/metosin/users/123")
; #Match{:template "/:company/users/:user-id",
; :data {:name :user/user-view,
; :coercion #SpecCoercion{...}
; :parameters {:path {:company string?,
; :user-id int?}}},
; :result {:path #object[reitit.coercion$request_coercer$]},
; :params {:company "metosin", :user-id "123"},
; :parameters {:path {:company "metosin", :user-id 123}}
; :path "/metosin/users/123"}
```
Failing coercion:
```clj
(route-and-coerce! "/metosin/users/ikitommi")
; => ExceptionInfo Request coercion failed...
```

View file

@ -0,0 +1,44 @@
# Plumatic Schema Coercion
[Plumatic Schema](https://github.com/plumatic/schema) is a Clojure(Script) library for declarative data description and validation.
```clj
(require '[reitit.coercion.schema])
(require '[reitit.coercion :as coercion])
(require '[schema.core :as s])
(require '[reitit.core :as r])
(def router
(r/router
["/:company/users/:user-id" {:name ::user-view
:coercion reitit.coercion.schema/coercion
:parameters {:path {:company s/Str
:user-id s/Int}}}]
{:compile coercion/compile-request-coercers}))
(defn route-and-coerce! [path]
(if-let [match (r/match-by-path router path)]
(assoc match :parameters (coercion/coerce! match))))
```
Successful coercion:
```clj
(route-and-coerce! "/metosin/users/123")
; #Match{:template "/:company/users/:user-id",
; :data {:name :user/user-view,
; :coercion #SchemaCoercion{...}
; :parameters {:path {:company java.lang.String,
; :user-id Int}}},
; :result {:path #object[reitit.coercion$request_coercer$]},
; :params {:company "metosin", :user-id "123"},
; :parameters {:path {:company "metosin", :user-id 123}}
; :path "/metosin/users/123"}
```
Failing coercion:
```clj
(route-and-coerce! "/metosin/users/ikitommi")
; => ExceptionInfo Request coercion failed...
```