better docs

This commit is contained in:
Tommi Reiman 2018-08-22 21:51:02 +03:00
parent cef7de58d3
commit 7b3aa5e631
7 changed files with 106 additions and 94 deletions

View file

@ -27,6 +27,7 @@
* [Static Resources](ring/static.md)
* [Dynamic Extensions](ring/dynamic_extensions.md)
* [Data-driven Middleware](ring/data_driven_middleware.md)
* [Transformations Middleware Chain](ring/transformating_middleware_chain.md)
* [Middleware Registry](ring/middleware_registry.md)
* [Default Middleware](ring/default_middleware.md)
* [Pluggable Coercion](ring/coercion.md)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 203 KiB

After

Width:  |  Height:  |  Size: 228 KiB

View file

@ -6,6 +6,7 @@
* [Static Resources](static.md)
* [Dynamic Extensions](dynamic_extensions.md)
* [Data-driven Middleware](data_driven_middleware.md)
* [Transformations Middleware Chain](transformating_middleware_chain.md)
* [Middleware Registry](middleware_registry.md)
* [Default Middleware](default_middleware.md)
* [Pluggable Coercion](coercion.md)

View file

@ -88,49 +88,8 @@ All the middleware are applied correctly:
Middleware can be optimized against an endpoint using [middleware compilation](compiling_middleware.md).
## Transforming the middleware chain
There is an extra option in ring-router (actually, in the undelaying middleware-router): `:reitit.middleware/transform` to transform the middleware chain per endpoint. It sees the vector of compiled middleware and should return a new vector of middleware.
#### Adding debug middleware between all other middleware
```clj
(def app
(ring/ring-handler
(ring/router
["/api" {:middleware [[wrap 1] [wrap2 2]]}
["/ping" {:get {:middleware [[wrap3 3]]
:handler handler}}]]
{::middleware/transform #(interleave % (repeat [wrap :debug]))})))
```
```clj
(app {:request-method :get, :uri "/api/ping"})
; {:status 200, :body [1 :debug 2 :debug 3 :debug :handler]}
```
#### Reversing the middleware chain
```clj
(def app
(ring/ring-handler
(ring/router
["/api" {:middleware [[wrap 1] [wrap2 2]]}
["/ping" {:get {:middleware [[wrap3 3]]
:handler handler}}]]
{::middleware/transform reverse)})))
```
```clj
(app {:request-method :get, :uri "/api/ping"})
; {:status 200, :body [3 2 1 :handler]}
```
## Ideas for the future
* Re-package all useful middleware into (optimized) data-driven Middleware
* just package or a new community-repo with rehosting stuff?
* Support `Keyword` expansion into Middleware, enabling external Middleware Registries (duct/integrant/macchiato -style)
* Support Middleware dependency resolution with new keys `:requires` and `:provides`. Values are set of top-level keys of the request. e.g.
* `InjectUserIntoRequestMiddleware` requires `#{:session}` and provides `#{:user}`
* `AuthorizationMiddleware` requires `#{:user}`

View file

@ -108,80 +108,95 @@ Swagger-ui:
### More complete example
* `clojure.spec` and `Schema` coercion
* swagger data (`:tags`, `:produces`, `:consumes`)
* swagger-spec served from `"/api/swagger.json"`
* `clojure.spec` coercion
* swagger data (`:tags`, `:produces`, `:summary`)
* swagger-spec served from `"/swagger.json"`
* swagger-ui mounted to `"/"`
* [Muuntaja](https://github.com/metosin/muuntaja) for request & response formatting
* `wrap-params` to capture query & path parameters
* set of middleware for content negotiation, exceptions, multipart etc.
* missed routes are handled by `create-default-handler`
* served via [ring-jetty](https://github.com/ring-clojure/ring/tree/master/ring-jetty-adapter)
Whole example project is in [`/examples/ring-swagger`](https://github.com/metosin/reitit/tree/master/examples/ring-swagger).
```clj
(require '[reitit.ring :as ring]
(require '[reitit.swagger :as swagger]
(require '[reitit.swagger-ui :as swagger-ui]
;; coercion
(require '[reitit.ring.coercion :as rrc]
(require '[reitit.coercion.spec :as spec]
(require '[reitit.coercion.schema :as schema]
(require '[schema.core :refer [Int]]
;; web server
(require '[ring.adapter.jetty :as jetty]
(require '[ring.middleware.params]
(require '[muuntaja.middleware]))
(ns example.server
(:require [reitit.ring :as ring]
[reitit.swagger :as swagger]
[reitit.swagger-ui :as swagger-ui]
[reitit.ring.coercion :as coercion]
[reitit.coercion.spec]
[reitit.ring.middleware.muuntaja :as muuntaja]
[reitit.ring.middleware.exception :as exception]
[reitit.ring.middleware.multipart :as multipart]
[ring.middleware.params :as params]
[ring.adapter.jetty :as jetty]
[muuntaja.core :as m]
[clojure.java.io :as io]))
(def app
(ring/ring-handler
(ring/router
["/api"
["/swagger.json"
[["/swagger.json"
{:get {:no-doc true
:swagger {:info {:title "my-api"}}
:handler (swagger/create-swagger-handler)}}]
["/spec"
{:coercion spec/coercion
:swagger {:tags ["spec"]}}
["/files"
{:swagger {:tags ["files"]}}
["/upload"
{:post {:summary "upload a file"
:parameters {:multipart {:file multipart/temp-file-part}}
:responses {200 {:body {:file multipart/temp-file-part}}}
:handler (fn [{{{:keys [file]} :multipart} :parameters}]
{:status 200
:body {:file file}})}}]
["/download"
{:get {:summary "downloads a file"
:swagger {:produces ["image/png"]}
:handler (fn [_]
{:status 200
:headers {"Content-Type" "image/png"}
:body (io/input-stream (io/resource "reitit.png"))})}}]]
["/math"
{:swagger {:tags ["math"]}}
["/plus"
{:get {:summary "plus with spec"
{:get {:summary "plus with spec query parameters"
:parameters {:query {:x int?, :y int?}}
:responses {200 {:body {:total int?}}}
:handler (fn [{{{:keys [x y]} :query} :parameters}]
{:status 200
:body {:total (+ x y)}})}}]]
:body {:total (+ x y)}})}
:post {:summary "plus with spec body parameters"
:parameters {:body {:x int?, :y int?}}
:responses {200 {:body {:total int?}}}
:handler (fn [{{{:keys [x y]} :body} :parameters}]
{:status 200
:body {:total (+ x y)}})}}]]]
["/schema"
{:coercion schema/coercion
:swagger {:tags ["schema"]}}
["/plus"
{:get {:summary "plus with schema"
:parameters {:query {:x Int, :y Int}}
:responses {200 {:body {:total Int}}}
:handler (fn [{{{:keys [x y]} :query} :parameters}]
{:status 200
:body {:total (+ x y)}})}}]]]
{:data {:middleware [ring.middleware.params/wrap-params
muuntaja.middleware/wrap-format
swagger/swagger-feature
rrc/coerce-exceptions-middleware
rrc/coerce-request-middleware
rrc/coerce-response-middleware]
:swagger {:produces #{"application/json"
"application/edn"
"application/transit+json"}
:consumes #{"application/json"
"application/edn"
"application/transit+json"}}}})
{:data {:coercion reitit.coercion.spec/coercion
:muuntaja m/instance
:middleware [;; query-params & form-params
params/wrap-params
;; content-negotiation
muuntaja/format-negotiate-middleware
;; encoding response body
muuntaja/format-response-middleware
;; exception handling
exception/exception-middleware
;; decoding request body
muuntaja/format-request-middleware
;; coercing response bodys
coercion/coerce-response-middleware
;; coercing request parameters
coercion/coerce-request-middleware
;; multipart
multipart/multipart-middleware]}})
(ring/routes
(swagger-ui/create-swagger-ui-handler
{:path "/", :url "/api/swagger.json"})
(swagger-ui/create-swagger-ui-handler {:path "/"})
(ring/create-default-handler))))
(defn start []
@ -242,7 +257,6 @@ Example with:
### TODO
* create a data-driven version of [Muuntaja](https://github.com/metosin/muuntaja) that integrates into `:produces` and `:consumes`
* ClojureScript
* example for [Macchiato](https://github.com/macchiato-framework)
* body formatting

View file

@ -0,0 +1,37 @@
# Transformation Middleware Chain
There is an extra option in ring-router (actually, in the underlying middleware-router): `:reitit.middleware/transform` to transform the middleware chain per endpoint. It gets the vector of compiled middleware and should return a new vector of middleware.
## Adding debug middleware between all other middleware
```clj
(def app
(ring/ring-handler
(ring/router
["/api" {:middleware [[wrap 1] [wrap2 2]]}
["/ping" {:get {:middleware [[wrap3 3]]
:handler handler}}]]
{::middleware/transform #(interleave % (repeat [wrap :debug]))})))
```
```clj
(app {:request-method :get, :uri "/api/ping"})
; {:status 200, :body [1 :debug 2 :debug 3 :debug :handler]}
```
## Reversing the middleware chain
```clj
(def app
(ring/ring-handler
(ring/router
["/api" {:middleware [[wrap 1] [wrap2 2]]}
["/ping" {:get {:middleware [[wrap3 3]]
:handler handler}}]]
{::middleware/transform reverse)})))
```
```clj
(app {:request-method :get, :uri "/api/ping"})
; {:status 200, :body [3 2 1 :handler]}
```

View file

@ -63,7 +63,7 @@
(if muuntaja
{:data {:swagger {:consumes (displace (m/decodes muuntaja))}}
:wrap #(muuntaja.middleware/wrap-format-request % muuntaja)}))})
©
(def format-response-middleware
"Middleware for response formatting.