diff --git a/README.md b/README.md index ba8b7e5b..2551b0c2 100644 --- a/README.md +++ b/README.md @@ -143,7 +143,7 @@ Invalid request: ## More examples -* [`reitit-ring` with coercion, swagger and default middleware](https://github.com/metosin/reitit/blob/master/examples/ring-swagger/src/example/server.clj) +* [`reitit-ring` with coercion, swagger and default middleware](https://github.com/metosin/reitit/blob/master/examples/ring-malli-swagger/src/example/server.clj) * [`reitit-frontend`, the easy way](https://github.com/metosin/reitit/blob/master/examples/frontend/src/frontend/core.cljs) * [`reitit-frontend` with Keechma-style controllers](https://github.com/metosin/reitit/blob/master/examples/frontend-controllers/src/frontend/core.cljs) * [`reitit-http` with Pedestal](https://github.com/metosin/reitit/blob/master/examples/pedestal/src/example/server.clj) diff --git a/doc/ring/default_middleware.md b/doc/ring/default_middleware.md index c2245e67..2d4138ec 100644 --- a/doc/ring/default_middleware.md +++ b/doc/ring/default_middleware.md @@ -59,4 +59,4 @@ Partial sample output: ## Example app -See an example app with the default middleware in action: https://github.com/metosin/reitit/blob/master/examples/ring-swagger/src/example/server.clj. +See an example app with the default middleware in action: . diff --git a/doc/ring/openapi.md b/doc/ring/openapi.md index c5187095..0f7103ea 100644 --- a/doc/ring/openapi.md +++ b/doc/ring/openapi.md @@ -5,8 +5,11 @@ Reitit can generate [OpenAPI 3.1.0](https://spec.openapis.org/oas/v3.1.0) documentation. The feature works similarly to [Swagger documentation](swagger.md). -The [http-swagger](../../examples/http-swagger) and -[ring-malli-swagger](../../examples/ring-malli-swagger) examples also +The +[ring-malli-swagger](../../examples/ring-malli-swagger) +and +[ring-spec-swagger](../../examples/ring-spec-swagger) +examples also have OpenAPI documentation. ## OpenAPI data @@ -51,7 +54,7 @@ that are not generated automatically by reitit. ...}}] ``` -See [the http-swagger example](../../examples/http-swagger) for a +See [the ring-malli-swagger example](../../examples/ring-malli-swagger) for working examples of `"securitySchemes"` and `"examples"`. ## OpenAPI spec diff --git a/doc/ring/swagger.md b/doc/ring/swagger.md index 0e7a064c..79c0c148 100644 --- a/doc/ring/swagger.md +++ b/doc/ring/swagger.md @@ -145,7 +145,7 @@ Another way to serve the swagger-ui is using the [default handler](default_handl * 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). +Whole example project is in [`/examples/ring-spec-swagger`](https://github.com/metosin/reitit/tree/master/examples/ring-spec-swagger). ```clj (ns example.server diff --git a/examples/README.md b/examples/README.md index 27134eb3..dbc42b05 100644 --- a/examples/README.md +++ b/examples/README.md @@ -44,7 +44,3 @@ Coercion with Malli and Swagger generation. ## ring-spec-swagger Coercion with Spec and Swagger generation. - -## ring-swagger - -Coercion with Spec and Swagger generation. Same as previous! diff --git a/examples/ring-malli-swagger/README.md b/examples/ring-malli-swagger/README.md index 6162591b..ee281fb2 100644 --- a/examples/ring-malli-swagger/README.md +++ b/examples/ring-malli-swagger/README.md @@ -1,4 +1,4 @@ -# reitit-ring, malli, swagger +# reitit-ring, malli, swagger, openapi 3 ## Usage diff --git a/examples/ring-malli-swagger/src/example/server.clj b/examples/ring-malli-swagger/src/example/server.clj index b7ab91b4..b2aa10f0 100644 --- a/examples/ring-malli-swagger/src/example/server.clj +++ b/examples/ring-malli-swagger/src/example/server.clj @@ -27,6 +27,10 @@ :swagger {:info {:title "my-api" :description "swagger docs with [malli](https://github.com/metosin/malli) and reitit-ring" :version "0.0.1"} + ;; used in /secure APIs below + :securityDefinitions {"auth" {:type :apiKey + :in :header + :name "Example-Api-Key"}} :tags [{:name "files", :description "file api"} {:name "math", :description "math api"}]} :handler (swagger/create-swagger-handler)}}] @@ -34,7 +38,11 @@ {:get {:no-doc true :openapi {:info {:title "my-api" :description "openapi3 docs with [malli](https://github.com/metosin/malli) and reitit-ring" - :version "0.0.1"}} + :version "0.0.1"} + ;; used in /secure APIs below + :components {:securitySchemes {"auth" {:type :apiKey + :in :header + :name "Example-Api-Key"}}}} :handler (openapi/create-openapi-handler)}}] ["/files" @@ -85,10 +93,42 @@ :json-schema/default 42} int?] [:y int?]]} + ;; OpenAPI3 named examples for request & response + :openapi {:requestBody + {:content + {"application/json" + {:examples {"add-one-one" {:summary "1+1" + :value {:x 1 :y 1}} + "add-one-two" {:summary "1+2" + :value {:x 1 :y 2}}}}}} + :responses + {200 + {:content + {"application/json" + {:examples {"two" {:summary "2" + :value {:total 2}} + "three" {:summary "3" + :value {:total 3}}}}}}}} :responses {200 {:body [:map [:total int?]]}} :handler (fn [{{{:keys [x y]} :body} :parameters}] {:status 200 - :body {:total (+ x y)}})}}]]] + :body {:total (+ x y)}})}}]] + + ["/secure" + {:tags ["secure"] + :openapi {:security [{"auth" []}]} + :swagger {:security [{"auth" []}]}} + ["/get" + {:get {:summary "endpoint authenticated with a header" + :responses {200 {:body [:map [:secret :string]]} + 401 {:body [:map [:error :string]]}} + :handler (fn [request] + ;; In a real app authentication would be handled by middleware + (if (= "secret" (get-in request [:headers "example-api-key"])) + {:status 200 + :body {:secret "I am a marmot"}} + {:status 401 + :body {:error "unauthorized"}}))}}]]] {;;:reitit.middleware/transform dev/print-request-diffs ;; pretty diffs ;;:validate spec/validate ;; enable spec validation for route data diff --git a/examples/ring-malli-swagger/swagger.png b/examples/ring-malli-swagger/swagger.png index 9d5a55b8..7f0fd089 100644 Binary files a/examples/ring-malli-swagger/swagger.png and b/examples/ring-malli-swagger/swagger.png differ diff --git a/examples/ring-spec-swagger/README.md b/examples/ring-spec-swagger/README.md index 3eb99d0c..00c30dca 100644 --- a/examples/ring-spec-swagger/README.md +++ b/examples/ring-spec-swagger/README.md @@ -1,4 +1,4 @@ -# reitit-ring, clojure.spec, swagger +# reitit-ring, clojure.spec, swagger, openapi 3 ## Usage @@ -7,6 +7,10 @@ (start) ``` +- Swagger spec served at +- Openapi spec served at +- Swagger UI served at + To test the endpoints using [httpie](https://httpie.org/): ```bash diff --git a/examples/ring-spec-swagger/src/example/server.clj b/examples/ring-spec-swagger/src/example/server.clj index 31ac2bc0..fe0ba885 100644 --- a/examples/ring-spec-swagger/src/example/server.clj +++ b/examples/ring-spec-swagger/src/example/server.clj @@ -1,6 +1,7 @@ (ns example.server (:require [reitit.ring :as ring] [reitit.coercion.spec] + [reitit.openapi :as openapi] [reitit.swagger :as swagger] [reitit.swagger-ui :as swagger-ui] [reitit.ring.coercion :as coercion] @@ -44,9 +45,15 @@ {:get {:no-doc true :swagger {:info {:title "my-api"}} :handler (swagger/create-swagger-handler)}}] + ["/openapi.json" + {:get {:no-doc true + :openapi {:info {:title "my-api" + :description "openapi3-docs with reitit-http" + :version "0.0.1"}} + :handler (openapi/create-openapi-handler)}}] ["/files" - {:swagger {:tags ["files"]}} + {:tags ["files"]} ["/upload" {:post {:summary "upload a file" @@ -67,7 +74,7 @@ (io/resource "reitit.png"))})}}]] ["/math" - {:swagger {:tags ["math"]}} + {:tags ["math"]} ["/plus" {:get {:summary "plus with spec query parameters" @@ -111,6 +118,9 @@ (swagger-ui/create-swagger-ui-handler {:path "/" :config {:validatorUrl nil + :urls [{:name "swagger" :url "swagger.json"} + {:name "openapi" :url "openapi.json"}] + :urls.primaryName "openapi" :operationsSorter "alpha"}}) (ring/create-default-handler)))) diff --git a/examples/ring-spec-swagger/swagger.png b/examples/ring-spec-swagger/swagger.png index 9d5a55b8..e7ba4003 100644 Binary files a/examples/ring-spec-swagger/swagger.png and b/examples/ring-spec-swagger/swagger.png differ diff --git a/examples/ring-swagger/.gitignore b/examples/ring-swagger/.gitignore deleted file mode 100644 index c53038ec..00000000 --- a/examples/ring-swagger/.gitignore +++ /dev/null @@ -1,11 +0,0 @@ -/target -/classes -/checkouts -pom.xml -pom.xml.asc -*.jar -*.class -/.lein-* -/.nrepl-port -.hgignore -.hg/ diff --git a/examples/ring-swagger/README.md b/examples/ring-swagger/README.md deleted file mode 100644 index 90585d1e..00000000 --- a/examples/ring-swagger/README.md +++ /dev/null @@ -1,23 +0,0 @@ -# Ring with Swagger example - -## Usage - -```clj -> lein repl -(start) -``` - -To test the endpoints using [httpie](https://httpie.org/): - -```bash -http GET :3000/math/plus x==1 y==20 -http POST :3000/math/spec/plus x:=1 y:=20 - -http GET :3000/swagger.json -``` - - - -## License - -Copyright © 2017-2018 Metosin Oy diff --git a/examples/ring-swagger/project.clj b/examples/ring-swagger/project.clj deleted file mode 100644 index 770f0584..00000000 --- a/examples/ring-swagger/project.clj +++ /dev/null @@ -1,6 +0,0 @@ -(defproject ring-example "0.1.0-SNAPSHOT" - :description "Reitit Ring App with Swagger" - :dependencies [[org.clojure/clojure "1.10.0"] - [ring/ring-jetty-adapter "1.7.1"] - [metosin/reitit "0.7.0-alpha1"]] - :repl-options {:init-ns example.server}) diff --git a/examples/ring-swagger/resources/reitit.png b/examples/ring-swagger/resources/reitit.png deleted file mode 100644 index c89c3654..00000000 Binary files a/examples/ring-swagger/resources/reitit.png and /dev/null differ diff --git a/examples/ring-swagger/src/example/server.clj b/examples/ring-swagger/src/example/server.clj deleted file mode 100644 index 58d01810..00000000 --- a/examples/ring-swagger/src/example/server.clj +++ /dev/null @@ -1,105 +0,0 @@ -(ns example.server - (:require [reitit.ring :as ring] - [reitit.coercion.spec] - [reitit.swagger :as swagger] - [reitit.swagger-ui :as swagger-ui] - [reitit.ring.coercion :as coercion] - [reitit.dev.pretty :as pretty] - [reitit.ring.middleware.muuntaja :as muuntaja] - [reitit.ring.middleware.exception :as exception] - [reitit.ring.middleware.multipart :as multipart] - [reitit.ring.middleware.parameters :as parameters] - ;; Uncomment to use - ; [reitit.ring.middleware.dev :as dev] - [ring.adapter.jetty :as jetty] - [muuntaja.core :as m] - [clojure.java.io :as io])) - -(def app - (ring/ring-handler - (ring/router - [["/swagger.json" - {:get {:no-doc true - :swagger {:info {:title "my-api" - :description "with reitit-ring"}} - :handler (swagger/create-swagger-handler)}}] - - ["/files" - {:swagger {:tags ["files"]}} - - ["/upload" - {:post {:summary "upload a file" - :parameters {:multipart {:file multipart/temp-file-part}} - :responses {200 {:body {:name string?, :size int?}}} - :handler (fn [{{{:keys [file]} :multipart} :parameters}] - {:status 200 - :body {:name (:filename file) - :size (:size file)}})}}] - - ["/download" - {:get {:summary "downloads a file" - :swagger {:produces ["image/png"]} - :handler (fn [_] - {:status 200 - :headers {"Content-Type" "image/png"} - :body (-> "reitit.png" - (io/resource) - (io/input-stream))})}}]] - - ["/math" - {:swagger {:tags ["math"]}} - - ["/plus" - {: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)}})} - :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)}})}}]]] - - {;;:reitit.middleware/transform dev/print-request-diffs ;; pretty diffs - ;;:validate spec/validate ;; enable spec validation for route data - ;;:reitit.spec/wrap spell/closed ;; strict top-level validation - :exception pretty/exception - :data {:coercion reitit.coercion.spec/coercion - :muuntaja m/instance - :middleware [;; swagger feature - swagger/swagger-feature - ;; query-params & form-params - parameters/parameters-middleware - ;; content-negotiation - muuntaja/format-negotiate-middleware - ;; encoding response body - muuntaja/format-response-middleware - ;; exception handling - (exception/create-exception-middleware - {::exception/default (partial exception/wrap-log-to-console exception/default-handler)}) - ;; 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 "/" - :config {:validatorUrl nil - :operationsSorter "alpha"}}) - (ring/create-default-handler)))) - -(defn start [] - (jetty/run-jetty #'app {:port 3000, :join? false}) - (println "server running in port 3000")) - -(comment - (start)) diff --git a/examples/ring-swagger/swagger.png b/examples/ring-swagger/swagger.png deleted file mode 100644 index 9d5a55b8..00000000 Binary files a/examples/ring-swagger/swagger.png and /dev/null differ