Skip to content

Commit

Permalink
Merge pull request metosin#197 from metosin/reitit-pedestal
Browse files Browse the repository at this point in the history
Reitit pedestal
  • Loading branch information
ikitommi authored Dec 26, 2018
2 parents e6e407c + 8e0aaf7 commit f524459
Show file tree
Hide file tree
Showing 19 changed files with 164 additions and 125 deletions.
15 changes: 12 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ A fast data-driven router for Clojure(Script).
* First-class [route data](https://metosin.github.io/reitit/basics/route_data.html)
* Bi-directional routing
* [Pluggable coercion](https://metosin.github.io/reitit/coercion/coercion.html) ([schema](https://github.com/plumatic/schema) & [clojure.spec](https://clojure.org/about/spec))
* Helpers for [ring](https://metosin.github.io/reitit/ring/ring.html), [http](https://metosin.github.io/reitit/http/interceptors.html) & [the frontend](https://metosin.github.io/reitit/frontend/basics.html)
* Helpers for [ring](https://metosin.github.io/reitit/ring/ring.html), [http](https://metosin.github.io/reitit/http/interceptors.html), [pedestal](http://pedestal.io) & [frontend](https://metosin.github.io/reitit/frontend/basics.html)
* Extendable
* Modular
* [Fast](https://metosin.github.io/reitit/performance.html)
Expand All @@ -21,7 +21,7 @@ See the [full documentation](https://metosin.github.io/reitit/) for details.

There is [#reitit](https://clojurians.slack.com/messages/reitit/) in [Clojurians Slack](http://clojurians.net/) for discussion & help.

## Modules
## Main Modules

* `reitit` - all bundled
* `reitit-core` - the routing core
Expand All @@ -36,9 +36,13 @@ There is [#reitit](https://clojurians.slack.com/messages/reitit/) in [Clojurians
* `reitit-interceptors` - [common interceptors](https://metosin.github.io/reitit/http/default_interceptors.html)
* `reitit-sieppari` support for [Sieppari](https://github.com/metosin/sieppari)

## Extra modules

* `reitit-pedestal` support for [Pedestal](http://pedestal.io)

## Latest version

All bundled:
All main modules bundled:

```clj
[metosin/reitit "0.2.9"]
Expand Down Expand Up @@ -70,6 +74,11 @@ Optionally, the parts can be required separately:
[metosin/reitit-sieppari "0.2.9"]
```

```clj
;; pedestal
[metosin/reitit-pedestal "0.2.9"]
```

## Quick start

```clj
Expand Down
67 changes: 56 additions & 11 deletions doc/http/pedestal.md
Original file line number Diff line number Diff line change
@@ -1,25 +1,70 @@
# Pedestal

[Pedestal](http://pedestal.io/) is a well known interceptor-based web framework for Clojure. To use `reitit-http` with Pedestal, we need to change the default routing interceptor into a new one. Examples projects show how to do this.
[Pedestal](http://pedestal.io/) is a well known interceptor-based web framework for Clojure. To use `reitit-http` with Pedestal, we need to change the default routing interceptor. The needed helpers for this are found in a separate package:

```clj
[metosin/reitit-ring "0.2.9"]
```

You should read the [interceptor guide](interceptors.md) to understand the basics on Interceptor-based dispatch.

## Example

A minimalistic example on how to to swap the default-router with a reitit router.

```clj
; [io.pedestal/pedestal.service "0.5.5"]
; [io.pedestal/pedestal.jetty "0.5.5"]
; [metosin/reitit-pedestal "0.2.9"]
; [metosin/reitit "0.2.9"]

(ns example.server
(:require [io.pedestal.http :as server]
[reitit.pedestal :as pedestal]
[reitit.http :as http]
[reitit.ring :as ring]))

(def router
(pedestal/routing-interceptor
(http/router
["/ping" (fn [_] {:status 200, :body "pong"})])
(ring/create-default-handler)))

(defn start []
(-> {::server/type :jetty
::server/port 3000
::server/join? false
;; no pedestal routes
::server/routes []}
(server/default-interceptors)
;; swap the reitit router
(pedestal/replace-last-interceptor router)
(server/dev-interceptors)
(server/create-server)
(server/start))
(println "server running in port 3000"))

(start)
```

## Caveat

`reitit-http` defines Interceptors as `reitit.interceptor/Interceptor`. Compared to Pedestal 2-arity error handlers, reitit uses a simplified (1-arity) handlers. Differences in error handling are described in the [Sieppari README](https://github.com/metosin/sieppari#differences-to-pedestal).
There is no common interceptor spec for Clojure and All default reitit interceptors (coercion, exceptions etc.) use the [Sieppari](https://github.com/metosin/sieppari) interceptor model. For most parts, they are fully compatible with the Pedestal Interceptor model. Only exception being that the `:error` handlers take just 1 arity (`context`) compared to [Pedestal's 2-arity](http://pedestal.io/reference/error-handling) (`context` and `exception`).

* you can use any [pedestal-style interceptor](http://pedestal.io/reference/interceptors) within reitit router (as Pedestal is executing those anyway)
* you can use any reitit-style interceptor that doesn't have `:error`-stage defined
* using a reitit-style interceptor with `:error` defined will cause `ArityException` if invoked
Currently, there is only the `reitit.http.interceptors.exception/exception-interceptor` which has `:error` defined - just don't use it and everything should just work.

You are most welcome to discuss about a common interceptor spec in [#interceptors](https://clojurians.slack.com/messages/interceptors/) in [Clojurians Slack](http://clojurians.net/).

See the [error handling guide](http://pedestal.io/reference/error-handling) on how to handle errors with Pedestal.

## Examples
## More examples

### Simple

* simple example, with both sync & async code:
* https://github.com/metosin/reitit/tree/master/examples/pedestal
Simple example, with both sync & async interceptors: https://github.com/metosin/reitit/tree/master/examples/pedestal

### Swagger

### With batteries
More complete example with custom interceptors, [default interceptors](default_interceptors.md), [coercion](../coercion/coercion.md) and [swagger](../ring/swagger.md)-support: https://github.com/metosin/reitit/tree/master/examples/pedestal-swagger

* with [default interceptors](default_interceptors.md), [coercion](../coercion/coercion.md) and [swagger](../ring/swagger.md)-support (note: exception handling is disabled):
* https://github.com/metosin/reitit/tree/master/examples/pedestal-swagger
note: exception handling is disabled in this example
2 changes: 1 addition & 1 deletion examples/frontend-controllers/project.clj
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
:license {:name "Eclipse Public License"
:url "http://www.eclipse.org/legal/epl-v10.html"}

:dependencies [[org.clojure/clojure "1.9.0"]
:dependencies [[org.clojure/clojure "1.10.0"]
[ring-server "0.5.0"]
[reagent "0.8.1"]
[ring "1.6.3"]
Expand Down
2 changes: 1 addition & 1 deletion examples/frontend/project.clj
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
:license {:name "Eclipse Public License"
:url "http://www.eclipse.org/legal/epl-v10.html"}

:dependencies [[org.clojure/clojure "1.9.0"]
:dependencies [[org.clojure/clojure "1.10.0"]
[ring-server "0.5.0"]
[reagent "0.8.1"]
[ring "1.6.3"]
Expand Down
2 changes: 1 addition & 1 deletion examples/http-swagger/project.clj
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
(defproject ring-example "0.1.0-SNAPSHOT"
:description "Reitit Http App with Swagger"
:dependencies [[org.clojure/clojure "1.9.0"]
:dependencies [[org.clojure/clojure "1.10.0"]
[ring/ring-jetty-adapter "1.7.0"]
[aleph "0.4.6"]
[metosin/reitit "0.2.9"]]
Expand Down
2 changes: 1 addition & 1 deletion examples/http/project.clj
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
(defproject ring-example "0.1.0-SNAPSHOT"
:description "Reitit Ring App with Swagger"
:dependencies [[org.clojure/clojure "1.9.0"]
:dependencies [[org.clojure/clojure "1.10.0"]
[org.clojure/core.async "0.4.474"]
[funcool/promesa "1.9.0"]
[manifold "0.1.8"]
Expand Down
2 changes: 1 addition & 1 deletion examples/just-coercion-with-ring/project.clj
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
(defproject just-coercion-with-ring "0.1.0-SNAPSHOT"
:description "Reitit coercion with vanilla ring"
:dependencies [[org.clojure/clojure "1.9.0"]
:dependencies [[org.clojure/clojure "1.10.0"]
[ring/ring-jetty-adapter "1.7.0"]
[metosin/muuntaja "0.4.1"]
[metosin/reitit "0.2.9"]])
7 changes: 4 additions & 3 deletions examples/pedestal-swagger/project.clj
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
(defproject ring-example "0.1.0-SNAPSHOT"
:description "Reitit-http with pedestal"
:dependencies [[org.clojure/clojure "1.9.0"]
[io.pedestal/pedestal.service "0.5.4"]
[io.pedestal/pedestal.jetty "0.5.4"]
:dependencies [[org.clojure/clojure "1.10.0"]
[io.pedestal/pedestal.service "0.5.5"]
[io.pedestal/pedestal.jetty "0.5.5"]
[metosin/reitit-pedestal "0.2.9"]
[metosin/reitit "0.2.9"]]
:repl-options {:init-ns example.server})
64 changes: 38 additions & 26 deletions examples/pedestal-swagger/src/example/server.clj
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
(ns example.server
(:require [io.pedestal.http]
[reitit.interceptor.pedestal :as pedestal]
(:require [io.pedestal.http :as server]
[reitit.pedestal :as pedestal]
[reitit.ring :as ring]
[reitit.http :as http]
[reitit.swagger :as swagger]
Expand All @@ -9,12 +9,15 @@
[reitit.coercion.spec :as spec-coercion]
[reitit.http.interceptors.parameters :as parameters]
[reitit.http.interceptors.muuntaja :as muuntaja]
#_[reitit.http.interceptors.exception :as exception]
[reitit.http.interceptors.multipart :as multipart]
[muuntaja.core :as m]
[clojure.java.io :as io]))
[clojure.core.async :as a]
[clojure.java.io :as io]
[muuntaja.core :as m]))

(def routing-interceptor
(defn interceptor [number]
{:enter (fn [ctx] (a/go (update-in ctx [:request :number] (fnil + 0) number)))})

(def router
(pedestal/routing-interceptor
(http/router
[["/swagger.json"
Expand All @@ -23,6 +26,17 @@
:description "with pedestal & reitit-http"}}
:handler (swagger/create-swagger-handler)}}]

["/interceptors"
{:swagger {:tags ["interceptors"]}
:interceptors [(interceptor 1)]}

["/number"
{:interceptors [(interceptor 10)]
:get {:interceptors [(interceptor 100)]
:handler (fn [req]
{:status 200
:body (select-keys req [:number])})}}]]

["/files"
{:swagger {:tags ["files"]}}

Expand Down Expand Up @@ -69,8 +83,6 @@
(muuntaja/format-negotiate-interceptor)
;; encoding response body
(muuntaja/format-response-interceptor)
;; exception handling - doesn't work
;;(exception/exception-interceptor)
;; decoding request body
(muuntaja/format-request-interceptor)
;; coercing response bodys
Expand All @@ -85,27 +97,27 @@
(swagger-ui/create-swagger-ui-handler
{:path "/"
:config {:validatorUrl nil}})
(ring/create-resource-handler)
(ring/create-default-handler))))

(defonce server (atom nil))

(defn start []
(when @server
(io.pedestal.http/stop @server)
(println "server stopped"))
(-> {:env :prod
:io.pedestal.http/routes []
:io.pedestal.http/resource-path "/public"
:io.pedestal.http/type :jetty
:io.pedestal.http/port 3000}
(merge {:env :dev
:io.pedestal.http/join? false
:io.pedestal.http/allowed-origins {:creds true :allowed-origins (constantly true)}})
(pedestal/default-interceptors routing-interceptor)
io.pedestal.http/dev-interceptors
io.pedestal.http/create-server
io.pedestal.http/start
(->> (reset! server)))
(-> {:env :dev
::server/type :jetty
::server/port 3000
::server/join? false
;; no pedestal routes
::server/routes []
;; allow serving the swagger-ui styles & scripts from self
::server/secure-headers {:content-security-policy-settings
{:default-src "'self'"
:style-src "'self' 'unsafe-inline'"
:script-src "'self' 'unsafe-inline'"}}}
(io.pedestal.http/default-interceptors)
;; use the reitit router
(pedestal/replace-last-interceptor router)
(io.pedestal.http/dev-interceptors)
(io.pedestal.http/create-server)
(io.pedestal.http/start))
(println "server running in port 3000"))

(comment
Expand Down
7 changes: 4 additions & 3 deletions examples/pedestal/project.clj
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
(defproject ring-example "0.1.0-SNAPSHOT"
:description "Reitit-http with pedestal"
:dependencies [[org.clojure/clojure "1.9.0"]
[io.pedestal/pedestal.service "0.5.4"]
[io.pedestal/pedestal.jetty "0.5.4"]
:dependencies [[org.clojure/clojure "1.10.0"]
[io.pedestal/pedestal.service "0.5.5"]
[io.pedestal/pedestal.jetty "0.5.5"]
[metosin/reitit-pedestal "0.2.9"]
[metosin/reitit "0.2.9"]]
:repl-options {:init-ns example.server})
41 changes: 18 additions & 23 deletions examples/pedestal/src/example/server.clj
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
(ns example.server
(:require [io.pedestal.http]
(:require [io.pedestal.http :as server]
[clojure.core.async :as a]
[reitit.interceptor.pedestal :as pedestal]
[reitit.pedestal :as pedestal]
[muuntaja.interceptor]
[reitit.http :as http]
[reitit.ring :as ring]))
Expand All @@ -18,7 +18,7 @@
{:enter (fn [{:keys [request] :as ctx}]
(a/go (assoc ctx :response (handler request))))})

(def routing-interceptor
(def router
(pedestal/routing-interceptor
(http/router
["/api"
Expand All @@ -36,32 +36,27 @@
;; optional interceptors for all matched routes
{:data {:interceptors [(interceptor :router)]}})

;; optional default ring handler (if no routes have matched)
(ring/create-default-handler)
;; optional default ring handlers (if no routes have matched)
(ring/routes
(ring/create-resource-handler)
(ring/create-default-handler))

;; optional top-level routes for both routes & default route
{:interceptors [(muuntaja.interceptor/format-interceptor)
(interceptor :top)]}))

(defonce server (atom nil))

(defn start []
(when @server
(io.pedestal.http/stop @server)
(println "server stopped"))
(-> {:env :prod
:io.pedestal.http/routes []
:io.pedestal.http/resource-path "/public"
:io.pedestal.http/type :jetty
:io.pedestal.http/port 3000}
(merge {:env :dev
:io.pedestal.http/join? false
:io.pedestal.http/allowed-origins {:creds true :allowed-origins (constantly true)}})
(pedestal/default-interceptors routing-interceptor)
io.pedestal.http/dev-interceptors
io.pedestal.http/create-server
io.pedestal.http/start
(->> (reset! server)))
(-> {::server/type :jetty
::server/port 3000
::server/join? false
;; no pedestal routes
::server/routes []}
(server/default-interceptors)
;; use the reitit router
(pedestal/replace-last-interceptor router)
(server/dev-interceptors)
(server/create-server)
(server/start))
(println "server running in port 3000"))

(comment
Expand Down
Loading

0 comments on commit f524459

Please sign in to comment.