mirror of
https://github.com/metosin/reitit.git
synced 2025-12-18 17:01:11 +00:00
better docs
This commit is contained in:
parent
cef7de58d3
commit
7b3aa5e631
7 changed files with 106 additions and 94 deletions
|
|
@ -27,6 +27,7 @@
|
||||||
* [Static Resources](ring/static.md)
|
* [Static Resources](ring/static.md)
|
||||||
* [Dynamic Extensions](ring/dynamic_extensions.md)
|
* [Dynamic Extensions](ring/dynamic_extensions.md)
|
||||||
* [Data-driven Middleware](ring/data_driven_middleware.md)
|
* [Data-driven Middleware](ring/data_driven_middleware.md)
|
||||||
|
* [Transformations Middleware Chain](ring/transformating_middleware_chain.md)
|
||||||
* [Middleware Registry](ring/middleware_registry.md)
|
* [Middleware Registry](ring/middleware_registry.md)
|
||||||
* [Default Middleware](ring/default_middleware.md)
|
* [Default Middleware](ring/default_middleware.md)
|
||||||
* [Pluggable Coercion](ring/coercion.md)
|
* [Pluggable Coercion](ring/coercion.md)
|
||||||
|
|
|
||||||
Binary file not shown.
|
Before Width: | Height: | Size: 203 KiB After Width: | Height: | Size: 228 KiB |
|
|
@ -6,6 +6,7 @@
|
||||||
* [Static Resources](static.md)
|
* [Static Resources](static.md)
|
||||||
* [Dynamic Extensions](dynamic_extensions.md)
|
* [Dynamic Extensions](dynamic_extensions.md)
|
||||||
* [Data-driven Middleware](data_driven_middleware.md)
|
* [Data-driven Middleware](data_driven_middleware.md)
|
||||||
|
* [Transformations Middleware Chain](transformating_middleware_chain.md)
|
||||||
* [Middleware Registry](middleware_registry.md)
|
* [Middleware Registry](middleware_registry.md)
|
||||||
* [Default Middleware](default_middleware.md)
|
* [Default Middleware](default_middleware.md)
|
||||||
* [Pluggable Coercion](coercion.md)
|
* [Pluggable Coercion](coercion.md)
|
||||||
|
|
|
||||||
|
|
@ -88,49 +88,8 @@ All the middleware are applied correctly:
|
||||||
|
|
||||||
Middleware can be optimized against an endpoint using [middleware compilation](compiling_middleware.md).
|
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
|
## 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.
|
* 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}`
|
* `InjectUserIntoRequestMiddleware` requires `#{:session}` and provides `#{:user}`
|
||||||
* `AuthorizationMiddleware` requires `#{:user}`
|
* `AuthorizationMiddleware` requires `#{:user}`
|
||||||
|
|
|
||||||
|
|
@ -108,80 +108,95 @@ Swagger-ui:
|
||||||
|
|
||||||
### More complete example
|
### More complete example
|
||||||
|
|
||||||
* `clojure.spec` and `Schema` coercion
|
* `clojure.spec` coercion
|
||||||
* swagger data (`:tags`, `:produces`, `:consumes`)
|
* swagger data (`:tags`, `:produces`, `:summary`)
|
||||||
* swagger-spec served from `"/api/swagger.json"`
|
* swagger-spec served from `"/swagger.json"`
|
||||||
* swagger-ui mounted to `"/"`
|
* swagger-ui mounted to `"/"`
|
||||||
* [Muuntaja](https://github.com/metosin/muuntaja) for request & response formatting
|
* set of middleware for content negotiation, exceptions, multipart etc.
|
||||||
* `wrap-params` to capture query & path parameters
|
|
||||||
* missed routes are handled by `create-default-handler`
|
* missed routes are handled by `create-default-handler`
|
||||||
* served via [ring-jetty](https://github.com/ring-clojure/ring/tree/master/ring-jetty-adapter)
|
* 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).
|
Whole example project is in [`/examples/ring-swagger`](https://github.com/metosin/reitit/tree/master/examples/ring-swagger).
|
||||||
|
|
||||||
```clj
|
```clj
|
||||||
(require '[reitit.ring :as ring]
|
(ns example.server
|
||||||
(require '[reitit.swagger :as swagger]
|
(:require [reitit.ring :as ring]
|
||||||
(require '[reitit.swagger-ui :as swagger-ui]
|
[reitit.swagger :as swagger]
|
||||||
;; coercion
|
[reitit.swagger-ui :as swagger-ui]
|
||||||
(require '[reitit.ring.coercion :as rrc]
|
[reitit.ring.coercion :as coercion]
|
||||||
(require '[reitit.coercion.spec :as spec]
|
[reitit.coercion.spec]
|
||||||
(require '[reitit.coercion.schema :as schema]
|
[reitit.ring.middleware.muuntaja :as muuntaja]
|
||||||
(require '[schema.core :refer [Int]]
|
[reitit.ring.middleware.exception :as exception]
|
||||||
;; web server
|
[reitit.ring.middleware.multipart :as multipart]
|
||||||
(require '[ring.adapter.jetty :as jetty]
|
[ring.middleware.params :as params]
|
||||||
(require '[ring.middleware.params]
|
[ring.adapter.jetty :as jetty]
|
||||||
(require '[muuntaja.middleware]))
|
[muuntaja.core :as m]
|
||||||
|
[clojure.java.io :as io]))
|
||||||
|
|
||||||
(def app
|
(def app
|
||||||
(ring/ring-handler
|
(ring/ring-handler
|
||||||
(ring/router
|
(ring/router
|
||||||
["/api"
|
[["/swagger.json"
|
||||||
|
|
||||||
["/swagger.json"
|
|
||||||
{:get {:no-doc true
|
{:get {:no-doc true
|
||||||
:swagger {:info {:title "my-api"}}
|
:swagger {:info {:title "my-api"}}
|
||||||
:handler (swagger/create-swagger-handler)}}]
|
:handler (swagger/create-swagger-handler)}}]
|
||||||
|
|
||||||
["/spec"
|
["/files"
|
||||||
{:coercion spec/coercion
|
{:swagger {:tags ["files"]}}
|
||||||
:swagger {:tags ["spec"]}}
|
|
||||||
|
["/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"
|
["/plus"
|
||||||
{:get {:summary "plus with spec"
|
{:get {:summary "plus with spec query parameters"
|
||||||
:parameters {:query {:x int?, :y int?}}
|
:parameters {:query {:x int?, :y int?}}
|
||||||
:responses {200 {:body {:total int?}}}
|
:responses {200 {:body {:total int?}}}
|
||||||
:handler (fn [{{{:keys [x y]} :query} :parameters}]
|
:handler (fn [{{{:keys [x y]} :query} :parameters}]
|
||||||
{:status 200
|
{:status 200
|
||||||
:body {:total (+ x y)}})}}]]
|
:body {:total (+ x y)}})}
|
||||||
|
:post {:summary "plus with spec body parameters"
|
||||||
["/schema"
|
:parameters {:body {:x int?, :y int?}}
|
||||||
{:coercion schema/coercion
|
:responses {200 {:body {:total int?}}}
|
||||||
:swagger {:tags ["schema"]}}
|
:handler (fn [{{{:keys [x y]} :body} :parameters}]
|
||||||
|
|
||||||
["/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
|
{:status 200
|
||||||
:body {:total (+ x y)}})}}]]]
|
:body {:total (+ x y)}})}}]]]
|
||||||
|
|
||||||
{:data {:middleware [ring.middleware.params/wrap-params
|
{:data {:coercion reitit.coercion.spec/coercion
|
||||||
muuntaja.middleware/wrap-format
|
:muuntaja m/instance
|
||||||
swagger/swagger-feature
|
:middleware [;; query-params & form-params
|
||||||
rrc/coerce-exceptions-middleware
|
params/wrap-params
|
||||||
rrc/coerce-request-middleware
|
;; content-negotiation
|
||||||
rrc/coerce-response-middleware]
|
muuntaja/format-negotiate-middleware
|
||||||
:swagger {:produces #{"application/json"
|
;; encoding response body
|
||||||
"application/edn"
|
muuntaja/format-response-middleware
|
||||||
"application/transit+json"}
|
;; exception handling
|
||||||
:consumes #{"application/json"
|
exception/exception-middleware
|
||||||
"application/edn"
|
;; decoding request body
|
||||||
"application/transit+json"}}}})
|
muuntaja/format-request-middleware
|
||||||
|
;; coercing response bodys
|
||||||
|
coercion/coerce-response-middleware
|
||||||
|
;; coercing request parameters
|
||||||
|
coercion/coerce-request-middleware
|
||||||
|
;; multipart
|
||||||
|
multipart/multipart-middleware]}})
|
||||||
(ring/routes
|
(ring/routes
|
||||||
(swagger-ui/create-swagger-ui-handler
|
(swagger-ui/create-swagger-ui-handler {:path "/"})
|
||||||
{:path "/", :url "/api/swagger.json"})
|
|
||||||
(ring/create-default-handler))))
|
(ring/create-default-handler))))
|
||||||
|
|
||||||
(defn start []
|
(defn start []
|
||||||
|
|
@ -242,7 +257,6 @@ Example with:
|
||||||
|
|
||||||
### TODO
|
### TODO
|
||||||
|
|
||||||
* create a data-driven version of [Muuntaja](https://github.com/metosin/muuntaja) that integrates into `:produces` and `:consumes`
|
|
||||||
* ClojureScript
|
* ClojureScript
|
||||||
* example for [Macchiato](https://github.com/macchiato-framework)
|
* example for [Macchiato](https://github.com/macchiato-framework)
|
||||||
* body formatting
|
* body formatting
|
||||||
|
|
|
||||||
37
doc/ring/transforming_middleware_chain.md
Normal file
37
doc/ring/transforming_middleware_chain.md
Normal 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]}
|
||||||
|
```
|
||||||
|
|
@ -63,7 +63,7 @@
|
||||||
(if muuntaja
|
(if muuntaja
|
||||||
{:data {:swagger {:consumes (displace (m/decodes muuntaja))}}
|
{:data {:swagger {:consumes (displace (m/decodes muuntaja))}}
|
||||||
:wrap #(muuntaja.middleware/wrap-format-request % muuntaja)}))})
|
:wrap #(muuntaja.middleware/wrap-format-request % muuntaja)}))})
|
||||||
©
|
|
||||||
(def format-response-middleware
|
(def format-response-middleware
|
||||||
"Middleware for response formatting.
|
"Middleware for response formatting.
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue