From 32c3082475ae212fca62e5c6d861563e1675a91a Mon Sep 17 00:00:00 2001 From: Tommi Reiman Date: Mon, 12 Feb 2018 07:55:08 +0200 Subject: [PATCH 1/7] Initial reitit-swagger --- README.md | 1 + doc/README.md | 1 + modules/reitit-swagger/project.clj | 9 ++ .../reitit-swagger/src/reitit/swagger.cljc | 141 ++++++++++++++++++ modules/reitit/project.clj | 3 +- project.clj | 4 +- scripts/lein-modules | 2 +- 7 files changed, 158 insertions(+), 3 deletions(-) create mode 100644 modules/reitit-swagger/project.clj create mode 100644 modules/reitit-swagger/src/reitit/swagger.cljc diff --git a/README.md b/README.md index 1db02408..f48d21e3 100644 --- a/README.md +++ b/README.md @@ -37,6 +37,7 @@ Optionally, the parts can be required separately: [metosin/reitit-ring "0.1.0"] ; ring-router [metosin/reitit-spec "0.1.0"] ; spec coercion [metosin/reitit-schema "0.1.0"] ; schema coercion +[metosin/reitit-swagger "0.1.0"] ; swagger docs ``` ## Quick start diff --git a/doc/README.md b/doc/README.md index 4c10988a..8ce9e261 100644 --- a/doc/README.md +++ b/doc/README.md @@ -29,6 +29,7 @@ Optionally, the parts can be required separately: [metosin/reitit-ring "0.1.0"] ; ring-router [metosin/reitit-spec "0.1.0"] ; spec coercion [metosin/reitit-schema "0.1.0"] ; schema coercion +[metosin/reitit-swagger "0.1.0"] ; swagger docs ``` For discussions, there is a [#reitit](https://clojurians.slack.com/messages/reitit/) channel in [Clojurians slack](http://clojurians.net/). diff --git a/modules/reitit-swagger/project.clj b/modules/reitit-swagger/project.clj new file mode 100644 index 00000000..29babf81 --- /dev/null +++ b/modules/reitit-swagger/project.clj @@ -0,0 +1,9 @@ +(defproject metosin/reitit-swagger "0.1.0-SNAPSHOT" + :description "Reitit: Swagger-support" + :url "https://github.com/metosin/reitit" + :license {:name "Eclipse Public License" + :url "http://www.eclipse.org/legal/epl-v10.html"} + :plugins [[lein-parent "0.3.2"]] + :parent-project {:path "../../project.clj" + :inherit [:deploy-repositories :managed-dependencies]} + :dependencies [[metosin/reitit-core]]) diff --git a/modules/reitit-swagger/src/reitit/swagger.cljc b/modules/reitit-swagger/src/reitit/swagger.cljc new file mode 100644 index 00000000..8e630dde --- /dev/null +++ b/modules/reitit-swagger/src/reitit/swagger.cljc @@ -0,0 +1,141 @@ +(ns reitit.swagger + (:require [reitit.core :as r] + [meta-merge.core :refer [meta-merge]] + [clojure.spec.alpha :as s] + [clojure.set :as set])) + +(s/def ::id keyword?) +(s/def ::no-doc boolean?) +(s/def ::tags (s/coll-of (s/or :keyword keyword? :string string?) :kind #{})) +(s/def ::summary string?) +(s/def ::description string?) + +(s/def ::swagger (s/keys :req-un [::id])) +(s/def ::spec (s/keys :opt-un [::swagger ::no-doc ::tags ::summary ::description])) + +(def swagger-feature + "Feature for handling swagger-documentation for routes. + Works both with Middleware & Interceptors. Does not participate + in actual request processing, just provides specs for the extra + valid keys for the route data. Should be accompanied by a + [[swagger-spec-handler]] to expose the swagger spec. + + Swagger-spesific keys: + + | key | description | + | --------------|-------------| + | :swagger | map of any swagger-data. Must have `:id` to identify the api + + The following common route keys also contribute to swagger spec: + + | key | description | + | --------------|-------------| + | :no-doc | optional boolean to exclude endpoint from api docs + | :tags | optional set of strings of keywords tags for an endpoint api docs + | :summary | optional short string summary of an endpoint + | :description | optional long description of an endpoint. Supports http://spec.commonmark.org/ + | :parameters | optional input parameters for a route, in a format defined by the coercion + | :responses | optional descriptions of responess, in a format defined by coercion + + Example: + + [\"/api\" + {:swagger {:id :my-api} + :middleware [reitit.swagger/swagger-feature]} + + [\"/swagger.json\" + {:get {:no-doc true + :swagger {:info {:title \"my-api\"}} + :handler reitit.swagger/swagger-spec-handler}}] + + [\"/plus\" + {:get {:tags #{:math} + :summary \"adds numbers together\" + :description \"takes `x` and `y` query-params and adds them together\" + :parameters {:query {:x int?, :y int?}} + :responses {200 {:body {:total pos-int?}}} + :handler (fn [{:keys [parameters]}] + {:status 200 + :body (+ (-> parameters :query :x) + (-> parameters :query :y)})}}]]" + {:name ::swagger + :spec ::spec}) + +(defn swagger-spec-handler + "Ring handler to emit swagger spec." + [{:keys [::r/router ::r/match :request-method]}] + (let [{:keys [id] :as swagger} (-> match :result request-method :data :swagger) + swagger (set/rename-keys swagger {:id :x-id})] + (if id + (let [paths (->> router + (r/routes) + (filter #(-> % second :swagger :id (= id))) + (map (fn [[p _ c]] + [p (some->> c + (keep + (fn [[m e]] + (if (and e (-> e :data :no-doc not)) + [m (meta-merge + (-> e :data (select-keys [:tags :summary :description :parameters :responses])) + (-> e :data :swagger))]))) + (seq) + (into {}))])) + (filter second) + (into {}))] + ;; TODO: create the swagger spec + {:status 200 + :body (meta-merge + swagger + {:paths paths})})))) + +;; +;; spike +;; + +(ns reitit.swagger.spike) +(require '[reitit.ring :as ring]) +(require '[reitit.swagger :as swagger]) +(require '[reitit.ring.coercion :as rrc]) +(require '[reitit.coercion.spec :as spec]) + +(def app + (ring/ring-handler + (ring/router + ["/api" + {:swagger {:id ::math}} + + ["/swagger.json" + {:get {:no-doc true + :swagger {:info {:title "my-api"}} + :handler swagger/swagger-spec-handler}}] + + ["/minus" + {:get {:summary "minus" + :parameters {:query {:x int?, :y int?}} + :responses {200 {:body {:total int?}}} + :handler (fn [{{{:keys [x y]} :query} :parameters}] + {:status 200, :body {:total (- x y)}})}}] + + ["/plus" + {:get {:summary "plus" + :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 [swagger/swagger-feature + rrc/coerce-exceptions-middleware + rrc/coerce-request-middleware + rrc/coerce-response-middleware] + :coercion spec/coercion}}))) + +(app + {:request-method :get + :uri "/api/plus" + :query-params {:x "1", :y "2"}}) +; {:body {:total 3}, :status 200} + +(app + {:request-method :get + :uri "/api/swagger.json"}) +; ... swagger-spec for "/api/minus" & "/api/plus" diff --git a/modules/reitit/project.clj b/modules/reitit/project.clj index 9b4af0af..b13185df 100644 --- a/modules/reitit/project.clj +++ b/modules/reitit/project.clj @@ -9,4 +9,5 @@ :dependencies [[metosin/reitit-core] [metosin/reitit-ring] [metosin/reitit-spec] - [metosin/reitit-schema]]) + [metosin/reitit-schema] + [metosin/reitit-swagger]]) diff --git a/project.clj b/project.clj index 16cbcbf3..a0503927 100644 --- a/project.clj +++ b/project.clj @@ -14,6 +14,7 @@ [metosin/reitit-ring "0.1.0"] [metosin/reitit-spec "0.1.0"] [metosin/reitit-schema "0.1.0"] + [metosin/reitit-swagger "0.1.0-SNAPSHOT"] [meta-merge "1.0.0"] [metosin/spec-tools "0.6.1"] @@ -33,7 +34,8 @@ "modules/reitit-core/src" "modules/reitit-ring/src" "modules/reitit-spec/src" - "modules/reitit-schema/src"] + "modules/reitit-schema/src" + "modules/reitit-swagger/src"] :dependencies [[org.clojure/clojure "1.9.0"] [org.clojure/clojurescript "1.9.946"] diff --git a/scripts/lein-modules b/scripts/lein-modules index 8ae825fd..e93284b9 100755 --- a/scripts/lein-modules +++ b/scripts/lein-modules @@ -3,6 +3,6 @@ set -e # Modules -for ext in reitit-core reitit-ring reitit-spec reitit-schema reitit; do +for ext in reitit-core reitit-ring reitit-spec reitit-schema reitit-swagger reitit; do cd modules/$ext; lein "$@"; cd ../..; done From b43c8cfed956262140a4a49531c5f144e1bd511a Mon Sep 17 00:00:00 2001 From: Tommi Reiman Date: Sat, 17 Mar 2018 10:53:19 +0200 Subject: [PATCH 2/7] Swagger WIP --- modules/reitit-core/src/reitit/coercion.cljc | 2 +- .../reitit-spec/src/reitit/coercion/spec.cljc | 33 +++++++++++-------- .../reitit-swagger/src/reitit/swagger.cljc | 19 +++++++---- 3 files changed, 33 insertions(+), 21 deletions(-) diff --git a/modules/reitit-core/src/reitit/coercion.cljc b/modules/reitit-core/src/reitit/coercion.cljc index 4560db84..36ed1fad 100644 --- a/modules/reitit-core/src/reitit/coercion.cljc +++ b/modules/reitit-core/src/reitit/coercion.cljc @@ -12,7 +12,7 @@ "Pluggable coercion protocol" (-get-name [this] "Keyword name for the coercion") (-get-options [this] "Coercion options") - (-get-apidocs [this model data] "???") + (-get-apidocs [this type data] "???") (-compile-model [this model name] "Compiles a model") (-open-model [this model] "Returns a new model which allows extra keys in maps") (-encode-error [this error] "Converts error in to a serializable format") diff --git a/modules/reitit-spec/src/reitit/coercion/spec.cljc b/modules/reitit-spec/src/reitit/coercion/spec.cljc index 52fb65e8..4ecad5e4 100644 --- a/modules/reitit-spec/src/reitit/coercion/spec.cljc +++ b/modules/reitit-spec/src/reitit/coercion/spec.cljc @@ -67,20 +67,25 @@ (reify coercion/Coercion (-get-name [_] :spec) (-get-options [_] opts) - (-get-apidocs [this _ {:keys [parameters responses] :as info}] - (cond-> (dissoc info :parameters :responses) - parameters (assoc - ::swagger/parameters - (into - (empty parameters) - (for [[k v] parameters] - [k (coercion/-compile-model this v nil)]))) - responses (assoc - ::swagger/responses - (into - (empty responses) - (for [[k response] responses] - [k (update response :body #(coercion/-compile-model this % nil))]))))) + (-get-apidocs [this type {:keys [parameters responses]}] + (condp = type + :swagger (merge + (if parameters + {::swagger/parameters + (into + (empty parameters) + (for [[k v] parameters] + [k (coercion/-compile-model this v nil)]))}) + (if responses + {::swagger/responses + (into + (empty responses) + (for [[k response] responses] + [k (update response :body #(coercion/-compile-model this % nil))]))})) + (throw + (ex-info + (str "Can't produce Spec apidocs for " type) + {:type type, :coercion :spec})))) (-compile-model [_ model name] (into-spec model name)) (-open-model [_ spec] spec) diff --git a/modules/reitit-swagger/src/reitit/swagger.cljc b/modules/reitit-swagger/src/reitit/swagger.cljc index 8e630dde..5e875620 100644 --- a/modules/reitit-swagger/src/reitit/swagger.cljc +++ b/modules/reitit-swagger/src/reitit/swagger.cljc @@ -2,7 +2,8 @@ (:require [reitit.core :as r] [meta-merge.core :refer [meta-merge]] [clojure.spec.alpha :as s] - [clojure.set :as set])) + [clojure.set :as set] + [reitit.coercion :as coercion])) (s/def ::id keyword?) (s/def ::no-doc boolean?) @@ -26,7 +27,7 @@ | --------------|-------------| | :swagger | map of any swagger-data. Must have `:id` to identify the api - The following common route keys also contribute to swagger spec: + The following common keys also contribute to swagger spec: | key | description | | --------------|-------------| @@ -34,6 +35,9 @@ | :tags | optional set of strings of keywords tags for an endpoint api docs | :summary | optional short string summary of an endpoint | :description | optional long description of an endpoint. Supports http://spec.commonmark.org/ + + Also the coercion keys contribute to swagger spec: + | :parameters | optional input parameters for a route, in a format defined by the coercion | :responses | optional descriptions of responess, in a format defined by coercion @@ -74,10 +78,13 @@ [p (some->> c (keep (fn [[m e]] - (if (and e (-> e :data :no-doc not)) - [m (meta-merge - (-> e :data (select-keys [:tags :summary :description :parameters :responses])) - (-> e :data :swagger))]))) + (let [coercion (-> e :data :coercion)] + (if (and e (-> e :data :no-doc not)) + [m (meta-merge + (if coercion + (coercion/-get-apidocs coercion :swagger (-> e :data))) + (-> e :data (select-keys [:tags :summary :description])) + (-> e :data :swagger))])))) (seq) (into {}))])) (filter second) From f87cd2f09f6a8a76540c726ad1c8f85d69a1217a Mon Sep 17 00:00:00 2001 From: Tommi Reiman Date: Sat, 17 Mar 2018 11:06:53 +0200 Subject: [PATCH 3/7] Support both Schema & Spec swagger --- .../src/reitit/coercion/schema.cljc | 24 +++++++-- .../reitit-swagger/src/reitit/swagger.cljc | 54 +++++++++++++------ project.clj | 4 +- 3 files changed, 61 insertions(+), 21 deletions(-) diff --git a/modules/reitit-schema/src/reitit/coercion/schema.cljc b/modules/reitit-schema/src/reitit/coercion/schema.cljc index 741f08a7..6843721a 100644 --- a/modules/reitit-schema/src/reitit/coercion/schema.cljc +++ b/modules/reitit-schema/src/reitit/coercion/schema.cljc @@ -5,6 +5,7 @@ [schema.coerce :as sc] [schema.utils :as su] [schema-tools.coerce :as stc] + [schema-tools.swagger.core :as swagger] [reitit.coercion :as coercion])) (def string-coercion-matcher @@ -44,10 +45,25 @@ (reify coercion/Coercion (-get-name [_] :schema) (-get-options [_] opts) - (-get-apidocs [_ _ {:keys [parameters responses] :as info}] - (cond-> (dissoc info :parameters :responses) - parameters (assoc ::parameters parameters) - responses (assoc ::responses responses))) + (-get-apidocs [this type {:keys [parameters responses]}] + (condp = type + :swagger (merge + (if parameters + {::swagger/parameters + (into + (empty parameters) + (for [[k v] parameters] + [k (coercion/-compile-model this v nil)]))}) + (if responses + {::swagger/responses + (into + (empty responses) + (for [[k response] responses] + [k (update response :body #(coercion/-compile-model this % nil))]))})) + (throw + (ex-info + (str "Can't produce Schem apidocs for " type) + {:type type, :coercion :schema})))) (-compile-model [_ model _] model) (-open-model [_ schema] (st/open-schema schema)) (-encode-error [_ error] diff --git a/modules/reitit-swagger/src/reitit/swagger.cljc b/modules/reitit-swagger/src/reitit/swagger.cljc index 5e875620..9883d8a8 100644 --- a/modules/reitit-swagger/src/reitit/swagger.cljc +++ b/modules/reitit-swagger/src/reitit/swagger.cljc @@ -104,6 +104,7 @@ (require '[reitit.swagger :as swagger]) (require '[reitit.ring.coercion :as rrc]) (require '[reitit.coercion.spec :as spec]) +(require '[reitit.coercion.schema :as schema]) (def app (ring/ring-handler @@ -116,29 +117,52 @@ :swagger {:info {:title "my-api"}} :handler swagger/swagger-spec-handler}}] - ["/minus" - {:get {:summary "minus" - :parameters {:query {:x int?, :y int?}} - :responses {200 {:body {:total int?}}} - :handler (fn [{{{:keys [x y]} :query} :parameters}] - {:status 200, :body {:total (- x y)}})}}] + ["/spec" {:coercion spec/coercion} - ["/plus" - {:get {:summary "plus" - :parameters {:query {:x int?, :y int?}} - :responses {200 {:body {:total int?}}} - :handler (fn [{{{:keys [x y]} :query} :parameters}] - {:status 200, :body {:total (+ x y)}})}}]] + ["/minus" + {:get {:summary "minus" + :parameters {:query {:x int?, :y int?}} + :responses {200 {:body {:total int?}}} + :handler (fn [{{{:keys [x y]} :query} :parameters}] + {:status 200, :body {:total (- x y)}})}}] + + ["/plus" + {:get {:summary "plus" + :parameters {:query {:x int?, :y int?}} + :responses {200 {:body {:total int?}}} + :handler (fn [{{{:keys [x y]} :query} :parameters}] + {:status 200, :body {:total (+ x y)}})}}]] + + ["/schema" {:coercion schema/coercion} + + ["/minus" + {:get {:summary "minus" + :parameters {:query {:x Long, :y Long}} + :responses {200 {:body {:total Long}}} + :handler (fn [{{{:keys [x y]} :query} :parameters}] + {:status 200, :body {:total (- x y)}})}}] + + ["/plus" + {:get {:summary "plus" + :parameters {:query {:x Long, :y Long}} + :responses {200 {:body {:total Long}}} + :handler (fn [{{{:keys [x y]} :query} :parameters}] + {:status 200, :body {:total (+ x y)}})}}]]] {:data {:middleware [swagger/swagger-feature rrc/coerce-exceptions-middleware rrc/coerce-request-middleware - rrc/coerce-response-middleware] - :coercion spec/coercion}}))) + rrc/coerce-response-middleware]}}))) (app {:request-method :get - :uri "/api/plus" + :uri "/api/spec/plus" + :query-params {:x "1", :y "2"}}) +; {:body {:total 3}, :status 200} + +(app + {:request-method :get + :uri "/api/schema/plus" :query-params {:x "1", :y "2"}}) ; {:body {:total 3}, :status 200} diff --git a/project.clj b/project.clj index a0503927..9c57bacc 100644 --- a/project.clj +++ b/project.clj @@ -18,7 +18,7 @@ [meta-merge "1.0.0"] [metosin/spec-tools "0.6.1"] - [metosin/schema-tools "0.10.0"]] + [metosin/schema-tools "0.10.1-SNAPSHOT"]] :plugins [[jonase/eastwood "0.2.5"] [lein-doo "0.1.9"] @@ -42,7 +42,7 @@ ;; modules dependencies [metosin/reitit] - [metosin/schema-tools "0.10.0"] + [metosin/schema-tools] [expound "0.5.0"] [orchestra "2017.11.12-1"] From 9a2a8a1f16e89fbda0ca76822176995ad07b71c3 Mon Sep 17 00:00:00 2001 From: Tommi Reiman Date: Sat, 17 Mar 2018 14:18:55 +0200 Subject: [PATCH 4/7] Tests for swagger --- .../src/reitit/coercion/schema.cljc | 31 +++-- .../reitit-spec/src/reitit/coercion/spec.cljc | 31 +++-- .../reitit-swagger/src/reitit/swagger.cljc | 78 +---------- test/cljc/reitit/swagger_test.clj | 129 ++++++++++++++++++ 4 files changed, 164 insertions(+), 105 deletions(-) create mode 100644 test/cljc/reitit/swagger_test.clj diff --git a/modules/reitit-schema/src/reitit/coercion/schema.cljc b/modules/reitit-schema/src/reitit/coercion/schema.cljc index 6843721a..9d9b706a 100644 --- a/modules/reitit-schema/src/reitit/coercion/schema.cljc +++ b/modules/reitit-schema/src/reitit/coercion/schema.cljc @@ -6,7 +6,8 @@ [schema.utils :as su] [schema-tools.coerce :as stc] [schema-tools.swagger.core :as swagger] - [reitit.coercion :as coercion])) + [reitit.coercion :as coercion] + [clojure.set :as set])) (def string-coercion-matcher stc/string-coercion-matcher) @@ -47,19 +48,21 @@ (-get-options [_] opts) (-get-apidocs [this type {:keys [parameters responses]}] (condp = type - :swagger (merge - (if parameters - {::swagger/parameters - (into - (empty parameters) - (for [[k v] parameters] - [k (coercion/-compile-model this v nil)]))}) - (if responses - {::swagger/responses - (into - (empty responses) - (for [[k response] responses] - [k (update response :body #(coercion/-compile-model this % nil))]))})) + :swagger (swagger/swagger-spec + (merge + (if parameters + {::swagger/parameters + (into + (empty parameters) + (for [[k v] parameters] + [k (coercion/-compile-model this v nil)]))}) + (if responses + {::swagger/responses + (into + (empty responses) + (for [[k response] responses + :let [response (set/rename-keys response {:body :schema})]] + [k (update response :schema #(coercion/-compile-model this % nil))]))}))) (throw (ex-info (str "Can't produce Schem apidocs for " type) diff --git a/modules/reitit-spec/src/reitit/coercion/spec.cljc b/modules/reitit-spec/src/reitit/coercion/spec.cljc index 4ecad5e4..ce905451 100644 --- a/modules/reitit-spec/src/reitit/coercion/spec.cljc +++ b/modules/reitit-spec/src/reitit/coercion/spec.cljc @@ -4,7 +4,8 @@ [spec-tools.data-spec :as ds] [spec-tools.conform :as conform] [spec-tools.swagger.core :as swagger] - [reitit.coercion :as coercion]) + [reitit.coercion :as coercion] + [clojure.set :as set]) #?(:clj (:import (spec_tools.core Spec)))) @@ -69,19 +70,21 @@ (-get-options [_] opts) (-get-apidocs [this type {:keys [parameters responses]}] (condp = type - :swagger (merge - (if parameters - {::swagger/parameters - (into - (empty parameters) - (for [[k v] parameters] - [k (coercion/-compile-model this v nil)]))}) - (if responses - {::swagger/responses - (into - (empty responses) - (for [[k response] responses] - [k (update response :body #(coercion/-compile-model this % nil))]))})) + :swagger (swagger/swagger-spec + (merge + (if parameters + {::swagger/parameters + (into + (empty parameters) + (for [[k v] parameters] + [k (coercion/-compile-model this v nil)]))}) + (if responses + {::swagger/responses + (into + (empty responses) + (for [[k response] responses + :let [response (set/rename-keys response {:body :schema})]] + [k (update response :schema #(coercion/-compile-model this % nil))]))}))) (throw (ex-info (str "Can't produce Spec apidocs for " type) diff --git a/modules/reitit-swagger/src/reitit/swagger.cljc b/modules/reitit-swagger/src/reitit/swagger.cljc index 9883d8a8..1347a17e 100644 --- a/modules/reitit-swagger/src/reitit/swagger.cljc +++ b/modules/reitit-swagger/src/reitit/swagger.cljc @@ -84,7 +84,7 @@ (if coercion (coercion/-get-apidocs coercion :swagger (-> e :data))) (-> e :data (select-keys [:tags :summary :description])) - (-> e :data :swagger))])))) + (-> e :data :swagger (dissoc :id)))])))) (seq) (into {}))])) (filter second) @@ -94,79 +94,3 @@ :body (meta-merge swagger {:paths paths})})))) - -;; -;; spike -;; - -(ns reitit.swagger.spike) -(require '[reitit.ring :as ring]) -(require '[reitit.swagger :as swagger]) -(require '[reitit.ring.coercion :as rrc]) -(require '[reitit.coercion.spec :as spec]) -(require '[reitit.coercion.schema :as schema]) - -(def app - (ring/ring-handler - (ring/router - ["/api" - {:swagger {:id ::math}} - - ["/swagger.json" - {:get {:no-doc true - :swagger {:info {:title "my-api"}} - :handler swagger/swagger-spec-handler}}] - - ["/spec" {:coercion spec/coercion} - - ["/minus" - {:get {:summary "minus" - :parameters {:query {:x int?, :y int?}} - :responses {200 {:body {:total int?}}} - :handler (fn [{{{:keys [x y]} :query} :parameters}] - {:status 200, :body {:total (- x y)}})}}] - - ["/plus" - {:get {:summary "plus" - :parameters {:query {:x int?, :y int?}} - :responses {200 {:body {:total int?}}} - :handler (fn [{{{:keys [x y]} :query} :parameters}] - {:status 200, :body {:total (+ x y)}})}}]] - - ["/schema" {:coercion schema/coercion} - - ["/minus" - {:get {:summary "minus" - :parameters {:query {:x Long, :y Long}} - :responses {200 {:body {:total Long}}} - :handler (fn [{{{:keys [x y]} :query} :parameters}] - {:status 200, :body {:total (- x y)}})}}] - - ["/plus" - {:get {:summary "plus" - :parameters {:query {:x Long, :y Long}} - :responses {200 {:body {:total Long}}} - :handler (fn [{{{:keys [x y]} :query} :parameters}] - {:status 200, :body {:total (+ x y)}})}}]]] - - {:data {:middleware [swagger/swagger-feature - rrc/coerce-exceptions-middleware - rrc/coerce-request-middleware - rrc/coerce-response-middleware]}}))) - -(app - {:request-method :get - :uri "/api/spec/plus" - :query-params {:x "1", :y "2"}}) -; {:body {:total 3}, :status 200} - -(app - {:request-method :get - :uri "/api/schema/plus" - :query-params {:x "1", :y "2"}}) -; {:body {:total 3}, :status 200} - -(app - {:request-method :get - :uri "/api/swagger.json"}) -; ... swagger-spec for "/api/minus" & "/api/plus" diff --git a/test/cljc/reitit/swagger_test.clj b/test/cljc/reitit/swagger_test.clj new file mode 100644 index 00000000..8edcd777 --- /dev/null +++ b/test/cljc/reitit/swagger_test.clj @@ -0,0 +1,129 @@ +(ns reitit.swagger-test + (:require [clojure.test :refer :all] + [reitit.ring :as ring] + [reitit.swagger :as swagger] + [reitit.ring.coercion :as rrc] + [reitit.coercion.spec :as spec] + [reitit.coercion.schema :as schema])) + +(def app + (ring/ring-handler + (ring/router + ["/api" + {:swagger {:id ::math}} + + ["/swagger.json" + {:get {:no-doc true + :swagger {:info {:title "my-api"}} + :handler swagger/swagger-spec-handler}}] + + ["/spec" {:coercion spec/coercion} + + ["/minus" + {:get {:summary "minus" + :parameters {:query {:x int?, :y int?}} + :responses {200 {:body {:total int?}}} + :handler (fn [{{{:keys [x y]} :query} :parameters}] + {:status 200, :body {:total (- x y)}})}}] + + ["/plus" + {:get {:summary "plus" + :parameters {:query {:x int?, :y int?}} + :responses {200 {:body {:total int?}}} + :handler (fn [{{{:keys [x y]} :query} :parameters}] + {:status 200, :body {:total (+ x y)}})}}]] + + ["/schema" {:coercion schema/coercion} + + ["/minus" + {:get {:summary "minus" + :parameters {:query {:x Long, :y Long}} + :responses {200 {:body {:total Long}}} + :handler (fn [{{{:keys [x y]} :query} :parameters}] + {:status 200, :body {:total (- x y)}})}}] + + ["/plus" + {:get {:summary "plus" + :parameters {:query {:x Long, :y Long}} + :responses {200 {:body {:total Long}}} + :handler (fn [{{{:keys [x y]} :query} :parameters}] + {:status 200, :body {:total (+ x y)}})}}]]] + + {:data {:middleware [swagger/swagger-feature + rrc/coerce-exceptions-middleware + rrc/coerce-request-middleware + rrc/coerce-response-middleware]}}))) + +(deftest swagger-test + (testing "endpoints work" + (testing "spec" + (is (= {:body {:total 3}, :status 200} + (app + {:request-method :get + :uri "/api/spec/plus" + :query-params {:x "2", :y "1"}}))) + (is (= {:body {:total 1}, :status 200} + (app + {:request-method :get + :uri "/api/spec/minus" + :query-params {:x "2", :y "1"}})))) + (testing "schema" + (is (= {:body {:total 3}, :status 200} + (app + {:request-method :get + :uri "/api/schema/plus" + :query-params {:x "2", :y "1"}}))) + (is (= {:body {:total 1}, :status 200} + (app + {:request-method :get + :uri "/api/schema/minus" + :query-params {:x "2", :y "1"}}))))) + (testing "swagger-spec" + (let [spec (:body (app + {:request-method :get + :uri "/api/swagger.json"}))] + (is (= {:x-id ::math + :info {:title "my-api"} + :paths { + ;; schema doesn't yet generate parameter data + "/api/schema/minus" {:get {:summary "minus"}} + "/api/schema/plus" {:get {:summary "plus"}} + + ;; spec does! + "/api/spec/minus" {:get {:parameters [{:description "" + :format "int64" + :in "query" + :name "x" + :required true + :type "integer"} + {:description "" + :format "int64" + :in "query" + :name "y" + :required true + :type "integer"}] + :responses {200 {:description "" + :schema {:properties {"total" {:format "int64" + :type "integer"}} + :required ["total"] + :type "object"}}} + :summary "minus"}} + "/api/spec/plus" {:get {:parameters [{:description "" + :format "int64" + :in "query" + :name "x" + :required true + :type "integer"} + {:description "" + :format "int64" + :in "query" + :name "y" + :required true + :type "integer"}] + :responses {200 {:description "" + :schema {:properties {"total" {:format "int64" + :type "integer"}} + :required ["total"] + :type "object"}}} + :summary "plus"}}}} + spec))))) From b57d900507c19b8e3ee2fd40d0b92939784f04f3 Mon Sep 17 00:00:00 2001 From: Tommi Reiman Date: Sat, 17 Mar 2018 14:32:51 +0200 Subject: [PATCH 5/7] 0.1.1-SNAPSHOT --- README.md | 12 ++++++------ doc/README.md | 12 ++++++------ doc/ring/ring.md | 2 +- examples/just-coercion-with-ring/project.clj | 2 +- examples/ring-example/project.clj | 2 +- modules/reitit-core/project.clj | 2 +- modules/reitit-ring/project.clj | 2 +- modules/reitit-schema/project.clj | 2 +- modules/reitit-spec/project.clj | 2 +- modules/reitit-swagger/project.clj | 2 +- modules/reitit/project.clj | 2 +- project.clj | 14 +++++++------- scripts/set-version | 5 ++--- 13 files changed, 30 insertions(+), 31 deletions(-) diff --git a/README.md b/README.md index f48d21e3..b24a7559 100644 --- a/README.md +++ b/README.md @@ -27,17 +27,17 @@ See the [full documentation](https://metosin.github.io/reitit/) for details. All bundled: ```clj -[metosin/reitit "0.1.0"] +[metosin/reitit "0.1.1-SNAPSHOT"] ``` Optionally, the parts can be required separately: ```clj -[metosin/reitit-core "0.1.0"] ; routing core -[metosin/reitit-ring "0.1.0"] ; ring-router -[metosin/reitit-spec "0.1.0"] ; spec coercion -[metosin/reitit-schema "0.1.0"] ; schema coercion -[metosin/reitit-swagger "0.1.0"] ; swagger docs +[metosin/reitit-core "0.1.1-SNAPSHOT"] ; routing core +[metosin/reitit-ring "0.1.1-SNAPSHOT"] ; ring-router +[metosin/reitit-spec "0.1.1-SNAPSHOT"] ; spec coercion +[metosin/reitit-schema "0.1.1-SNAPSHOT"] ; schema coercion +[metosin/reitit-swagger "0.1.1-SNAPSHOT"] ; swagger docs ``` ## Quick start diff --git a/doc/README.md b/doc/README.md index 8ce9e261..450c7f7b 100644 --- a/doc/README.md +++ b/doc/README.md @@ -19,17 +19,17 @@ The following higher-level routers are also available as separate modules: To use Reitit, add the following dependecy to your project: ```clj -[metosin/reitit "0.1.0"] +[metosin/reitit "0.1.1-SNAPSHOT"] ``` Optionally, the parts can be required separately: ```clj -[metosin/reitit-core "0.1.0"] ; routing core -[metosin/reitit-ring "0.1.0"] ; ring-router -[metosin/reitit-spec "0.1.0"] ; spec coercion -[metosin/reitit-schema "0.1.0"] ; schema coercion -[metosin/reitit-swagger "0.1.0"] ; swagger docs +[metosin/reitit-core "0.1.1-SNAPSHOT"] ; routing core +[metosin/reitit-ring "0.1.1-SNAPSHOT"] ; ring-router +[metosin/reitit-spec "0.1.1-SNAPSHOT"] ; spec coercion +[metosin/reitit-schema "0.1.1-SNAPSHOT"] ; schema coercion +[metosin/reitit-swagger "0.1.1-SNAPSHOT"] ; swagger docs ``` For discussions, there is a [#reitit](https://clojurians.slack.com/messages/reitit/) channel in [Clojurians slack](http://clojurians.net/). diff --git a/doc/ring/ring.md b/doc/ring/ring.md index 3b4ca9c1..f85afac7 100644 --- a/doc/ring/ring.md +++ b/doc/ring/ring.md @@ -3,7 +3,7 @@ [Ring](https://github.com/ring-clojure/ring) is a Clojure web applications library inspired by Python's WSGI and Ruby's Rack. By abstracting the details of HTTP into a simple, unified API, Ring allows web applications to be constructed of modular components that can be shared among a variety of applications, web servers, and web frameworks. ```clj -[metosin/reitit-ring "0.1.0-SNAPSHOT"] +[metosin/reitit-ring "0.1.1-SNAPSHOT"] ``` Ring-router adds support for [handlers](https://github.com/ring-clojure/ring/wiki/Concepts#handlers), [middleware](https://github.com/ring-clojure/ring/wiki/Concepts#middleware) and routing based on `:request-method`. Ring-router is created with `reitit.ring/router` function. It uses a custom route compiler, creating a optimized data structure for handling route matches, with compiled middleware chain & handlers for all request methods. It also ensures that all routes have a `:handler` defined. `reitit.ring/ring-handler` is used to create a Ring handler out of ring-router. diff --git a/examples/just-coercion-with-ring/project.clj b/examples/just-coercion-with-ring/project.clj index 77a971ee..d77b03cc 100644 --- a/examples/just-coercion-with-ring/project.clj +++ b/examples/just-coercion-with-ring/project.clj @@ -3,4 +3,4 @@ :dependencies [[org.clojure/clojure "1.9.0"] [ring "1.6.3"] [metosin/muuntaja "0.4.1"] - [metosin/reitit "0.1.0"]]) + [metosin/reitit "0.1.1-SNAPSHOT"]]) diff --git a/examples/ring-example/project.clj b/examples/ring-example/project.clj index 2a46b31e..a4783cf9 100644 --- a/examples/ring-example/project.clj +++ b/examples/ring-example/project.clj @@ -3,4 +3,4 @@ :dependencies [[org.clojure/clojure "1.9.0"] [ring "1.6.3"] [metosin/muuntaja "0.4.1"] - [metosin/reitit "0.1.0"]]) + [metosin/reitit "0.1.1-SNAPSHOT"]]) diff --git a/modules/reitit-core/project.clj b/modules/reitit-core/project.clj index 67b52b30..b49f1317 100644 --- a/modules/reitit-core/project.clj +++ b/modules/reitit-core/project.clj @@ -1,4 +1,4 @@ -(defproject metosin/reitit-core "0.1.0" +(defproject metosin/reitit-core "0.1.1-SNAPSHOT" :description "Snappy data-driven router for Clojure(Script)" :url "https://github.com/metosin/reitit" :license {:name "Eclipse Public License" diff --git a/modules/reitit-ring/project.clj b/modules/reitit-ring/project.clj index 7a38772c..45fb455b 100644 --- a/modules/reitit-ring/project.clj +++ b/modules/reitit-ring/project.clj @@ -1,4 +1,4 @@ -(defproject metosin/reitit-ring "0.1.0" +(defproject metosin/reitit-ring "0.1.1-SNAPSHOT" :description "Reitit: Ring routing" :url "https://github.com/metosin/reitit" :license {:name "Eclipse Public License" diff --git a/modules/reitit-schema/project.clj b/modules/reitit-schema/project.clj index a71566f7..4327d3de 100644 --- a/modules/reitit-schema/project.clj +++ b/modules/reitit-schema/project.clj @@ -1,4 +1,4 @@ -(defproject metosin/reitit-schema "0.1.0" +(defproject metosin/reitit-schema "0.1.1-SNAPSHOT" :description "Reitit: Plumatic Schema coercion" :url "https://github.com/metosin/reitit" :license {:name "Eclipse Public License" diff --git a/modules/reitit-spec/project.clj b/modules/reitit-spec/project.clj index 34678751..545408e9 100644 --- a/modules/reitit-spec/project.clj +++ b/modules/reitit-spec/project.clj @@ -1,4 +1,4 @@ -(defproject metosin/reitit-spec "0.1.0" +(defproject metosin/reitit-spec "0.1.1-SNAPSHOT" :description "Reitit: clojure.spec coercion" :url "https://github.com/metosin/reitit" :license {:name "Eclipse Public License" diff --git a/modules/reitit-swagger/project.clj b/modules/reitit-swagger/project.clj index 29babf81..384e6c5f 100644 --- a/modules/reitit-swagger/project.clj +++ b/modules/reitit-swagger/project.clj @@ -1,4 +1,4 @@ -(defproject metosin/reitit-swagger "0.1.0-SNAPSHOT" +(defproject metosin/reitit-swagger "0.1.1-SNAPSHOT" :description "Reitit: Swagger-support" :url "https://github.com/metosin/reitit" :license {:name "Eclipse Public License" diff --git a/modules/reitit/project.clj b/modules/reitit/project.clj index b13185df..9263d98b 100644 --- a/modules/reitit/project.clj +++ b/modules/reitit/project.clj @@ -1,4 +1,4 @@ -(defproject metosin/reitit "0.1.0" +(defproject metosin/reitit "0.1.1-SNAPSHOT" :description "Snappy data-driven router for Clojure(Script)" :url "https://github.com/metosin/reitit" :license {:name "Eclipse Public License" diff --git a/project.clj b/project.clj index 9c57bacc..58396d62 100644 --- a/project.clj +++ b/project.clj @@ -1,4 +1,4 @@ -(defproject metosin/reitit-parent "0.1.0" +(defproject metosin/reitit-parent "0.1.1-SNAPSHOT" :description "Snappy data-driven router for Clojure(Script)" :url "https://github.com/metosin/reitit" :license {:name "Eclipse Public License" @@ -9,12 +9,12 @@ :source-uri "https://github.com/metosin/reitit/{version}/{filepath}#L{line}" :metadata {:doc/format :markdown}} - :managed-dependencies [[metosin/reitit "0.1.0"] - [metosin/reitit-core "0.1.0"] - [metosin/reitit-ring "0.1.0"] - [metosin/reitit-spec "0.1.0"] - [metosin/reitit-schema "0.1.0"] - [metosin/reitit-swagger "0.1.0-SNAPSHOT"] + :managed-dependencies [[metosin/reitit "0.1.1-SNAPSHOT"] + [metosin/reitit-core "0.1.1-SNAPSHOT"] + [metosin/reitit-ring "0.1.1-SNAPSHOT"] + [metosin/reitit-spec "0.1.1-SNAPSHOT"] + [metosin/reitit-schema "0.1.1-SNAPSHOT"] + [metosin/reitit-swagger "0.1.1-SNAPSHOT"] [meta-merge "1.0.0"] [metosin/spec-tools "0.6.1"] diff --git a/scripts/set-version b/scripts/set-version index ec30ad58..c4c47b31 100755 --- a/scripts/set-version +++ b/scripts/set-version @@ -1,9 +1,8 @@ -#!/bin/sh +#!/bin/zsh ext="sedbak$$" find . -name project.clj -exec sed -i.$ext "s/\[metosin\/reitit\(.*\) \".*\"\]/[metosin\/reitit\1 \"$1\"\]/g" '{}' \; find . -name project.clj -exec sed -i.$ext "s/defproject metosin\/reitit\(.*\) \".*\"/defproject metosin\/reitit\1 \"$1\"/g" '{}' \; -sed -i.$ext "s/\[metosin\/reitit\(.*\) \".*\"\]/[metosin\/reitit\1 \"$1\"\]/g" doc/*.md -sed -i.$ext "s/\[metosin\/reitit\(.*\) \".*\"\]/[metosin\/reitit\1 \"$1\"\]/g" *.md +sed -i.$ext "s/\[metosin\/reitit\(.*\) \".*\"\]/[metosin\/reitit\1 \"$1\"\]/g" **/*.md find . -name "*.$ext" -exec rm '{}' \; From f3058b90fe38d0304effb7fb8a24024589864afd Mon Sep 17 00:00:00 2001 From: Tommi Reiman Date: Sat, 17 Mar 2018 14:35:28 +0200 Subject: [PATCH 6/7] Fix tests for cljs --- test/cljc/reitit/swagger_test.clj | 58 +++---------------------------- 1 file changed, 5 insertions(+), 53 deletions(-) diff --git a/test/cljc/reitit/swagger_test.clj b/test/cljc/reitit/swagger_test.clj index 8edcd777..e7ee183e 100644 --- a/test/cljc/reitit/swagger_test.clj +++ b/test/cljc/reitit/swagger_test.clj @@ -4,7 +4,8 @@ [reitit.swagger :as swagger] [reitit.ring.coercion :as rrc] [reitit.coercion.spec :as spec] - [reitit.coercion.schema :as schema])) + [reitit.coercion.schema :as schema] + [schema.core :refer [Int]])) (def app (ring/ring-handler @@ -18,14 +19,6 @@ :handler swagger/swagger-spec-handler}}] ["/spec" {:coercion spec/coercion} - - ["/minus" - {:get {:summary "minus" - :parameters {:query {:x int?, :y int?}} - :responses {200 {:body {:total int?}}} - :handler (fn [{{{:keys [x y]} :query} :parameters}] - {:status 200, :body {:total (- x y)}})}}] - ["/plus" {:get {:summary "plus" :parameters {:query {:x int?, :y int?}} @@ -34,18 +27,10 @@ {:status 200, :body {:total (+ x y)}})}}]] ["/schema" {:coercion schema/coercion} - - ["/minus" - {:get {:summary "minus" - :parameters {:query {:x Long, :y Long}} - :responses {200 {:body {:total Long}}} - :handler (fn [{{{:keys [x y]} :query} :parameters}] - {:status 200, :body {:total (- x y)}})}}] - ["/plus" {:get {:summary "plus" - :parameters {:query {:x Long, :y Long}} - :responses {200 {:body {:total Long}}} + :parameters {:query {:x Int, :y Int}} + :responses {200 {:body {:total Int}}} :handler (fn [{{{:keys [x y]} :query} :parameters}] {:status 200, :body {:total (+ x y)}})}}]]] @@ -61,22 +46,12 @@ (app {:request-method :get :uri "/api/spec/plus" - :query-params {:x "2", :y "1"}}))) - (is (= {:body {:total 1}, :status 200} - (app - {:request-method :get - :uri "/api/spec/minus" :query-params {:x "2", :y "1"}})))) (testing "schema" (is (= {:body {:total 3}, :status 200} (app {:request-method :get :uri "/api/schema/plus" - :query-params {:x "2", :y "1"}}))) - (is (= {:body {:total 1}, :status 200} - (app - {:request-method :get - :uri "/api/schema/minus" :query-params {:x "2", :y "1"}}))))) (testing "swagger-spec" (let [spec (:body (app @@ -84,30 +59,7 @@ :uri "/api/swagger.json"}))] (is (= {:x-id ::math :info {:title "my-api"} - :paths { - ;; schema doesn't yet generate parameter data - "/api/schema/minus" {:get {:summary "minus"}} - "/api/schema/plus" {:get {:summary "plus"}} - - ;; spec does! - "/api/spec/minus" {:get {:parameters [{:description "" - :format "int64" - :in "query" - :name "x" - :required true - :type "integer"} - {:description "" - :format "int64" - :in "query" - :name "y" - :required true - :type "integer"}] - :responses {200 {:description "" - :schema {:properties {"total" {:format "int64" - :type "integer"}} - :required ["total"] - :type "object"}}} - :summary "minus"}} + :paths {"/api/schema/plus" {:get {:summary "plus"}} ;; TODO: implement! "/api/spec/plus" {:get {:parameters [{:description "" :format "int64" :in "query" From 3cc9fedcbf241cdc8d1a8f9cd56e446697d5daa9 Mon Sep 17 00:00:00 2001 From: Tommi Reiman Date: Sun, 18 Mar 2018 11:21:49 +0200 Subject: [PATCH 7/7] =?UTF-8?q?Fixed=20based=20on=20Miikka=E2=80=99s=20com?= =?UTF-8?q?ments?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- modules/reitit-core/src/reitit/coercion.cljc | 2 +- .../src/reitit/coercion/schema.cljc | 9 ++-- .../reitit-spec/src/reitit/coercion/spec.cljc | 8 ++-- .../reitit-swagger/src/reitit/swagger.cljc | 44 ++++++++----------- 4 files changed, 28 insertions(+), 35 deletions(-) diff --git a/modules/reitit-core/src/reitit/coercion.cljc b/modules/reitit-core/src/reitit/coercion.cljc index 36ed1fad..5c833dca 100644 --- a/modules/reitit-core/src/reitit/coercion.cljc +++ b/modules/reitit-core/src/reitit/coercion.cljc @@ -12,7 +12,7 @@ "Pluggable coercion protocol" (-get-name [this] "Keyword name for the coercion") (-get-options [this] "Coercion options") - (-get-apidocs [this type data] "???") + (-get-apidocs [this spesification data] "Returns api documentation") (-compile-model [this model name] "Compiles a model") (-open-model [this model] "Returns a new model which allows extra keys in maps") (-encode-error [this error] "Converts error in to a serializable format") diff --git a/modules/reitit-schema/src/reitit/coercion/schema.cljc b/modules/reitit-schema/src/reitit/coercion/schema.cljc index 9d9b706a..1f626886 100644 --- a/modules/reitit-schema/src/reitit/coercion/schema.cljc +++ b/modules/reitit-schema/src/reitit/coercion/schema.cljc @@ -46,8 +46,9 @@ (reify coercion/Coercion (-get-name [_] :schema) (-get-options [_] opts) - (-get-apidocs [this type {:keys [parameters responses]}] - (condp = type + (-get-apidocs [this spesification {:keys [parameters responses]}] + ;; TODO: this looks identical to spec, refactor when schema is done. + (condp = spesification :swagger (swagger/swagger-spec (merge (if parameters @@ -65,8 +66,8 @@ [k (update response :schema #(coercion/-compile-model this % nil))]))}))) (throw (ex-info - (str "Can't produce Schem apidocs for " type) - {:type type, :coercion :schema})))) + (str "Can't produce Schema apidocs for " spesification) + {:type spesification, :coercion :schema})))) (-compile-model [_ model _] model) (-open-model [_ schema] (st/open-schema schema)) (-encode-error [_ error] diff --git a/modules/reitit-spec/src/reitit/coercion/spec.cljc b/modules/reitit-spec/src/reitit/coercion/spec.cljc index ce905451..72e9dc84 100644 --- a/modules/reitit-spec/src/reitit/coercion/spec.cljc +++ b/modules/reitit-spec/src/reitit/coercion/spec.cljc @@ -68,8 +68,8 @@ (reify coercion/Coercion (-get-name [_] :spec) (-get-options [_] opts) - (-get-apidocs [this type {:keys [parameters responses]}] - (condp = type + (-get-apidocs [this spesification {:keys [parameters responses]}] + (condp = spesification :swagger (swagger/swagger-spec (merge (if parameters @@ -87,8 +87,8 @@ [k (update response :schema #(coercion/-compile-model this % nil))]))}))) (throw (ex-info - (str "Can't produce Spec apidocs for " type) - {:type type, :coercion :spec})))) + (str "Can't produce Spec apidocs for " spesification) + {:type spesification, :coercion :spec})))) (-compile-model [_ model name] (into-spec model name)) (-open-model [_ spec] spec) diff --git a/modules/reitit-swagger/src/reitit/swagger.cljc b/modules/reitit-swagger/src/reitit/swagger.cljc index 1347a17e..ee232a99 100644 --- a/modules/reitit-swagger/src/reitit/swagger.cljc +++ b/modules/reitit-swagger/src/reitit/swagger.cljc @@ -17,11 +17,11 @@ (def swagger-feature "Feature for handling swagger-documentation for routes. Works both with Middleware & Interceptors. Does not participate - in actual request processing, just provides specs for the extra - valid keys for the route data. Should be accompanied by a + in actual request processing, just provides specs for the new + documentation keys for the route data. Should be accompanied by a [[swagger-spec-handler]] to expose the swagger spec. - Swagger-spesific keys: + Swagger-specific keys: | key | description | | --------------|-------------| @@ -69,28 +69,20 @@ "Ring handler to emit swagger spec." [{:keys [::r/router ::r/match :request-method]}] (let [{:keys [id] :as swagger} (-> match :result request-method :data :swagger) - swagger (set/rename-keys swagger {:id :x-id})] + swagger (set/rename-keys swagger {:id :x-id}) + this-swagger? #(-> % second :swagger :id (= id)) + transform-endpoint (fn [[method endpoint]] + (let [coercion (-> endpoint :data :coercion)] + (if (and endpoint (-> endpoint :data :no-doc not)) + [method (meta-merge + (if coercion + (coercion/-get-apidocs coercion :swagger (-> endpoint :data))) + (-> endpoint :data (select-keys [:tags :summary :description])) + (-> endpoint :data :swagger (dissoc :id)))]))) + transform-path (fn [[p _ c]] + (if-let [endpoint (some->> c (keep transform-endpoint) (seq) (into {}))] + [p endpoint]))] (if id - (let [paths (->> router - (r/routes) - (filter #(-> % second :swagger :id (= id))) - (map (fn [[p _ c]] - [p (some->> c - (keep - (fn [[m e]] - (let [coercion (-> e :data :coercion)] - (if (and e (-> e :data :no-doc not)) - [m (meta-merge - (if coercion - (coercion/-get-apidocs coercion :swagger (-> e :data))) - (-> e :data (select-keys [:tags :summary :description])) - (-> e :data :swagger (dissoc :id)))])))) - (seq) - (into {}))])) - (filter second) - (into {}))] - ;; TODO: create the swagger spec + (let [paths (->> router (r/routes) (filter this-swagger?) (map transform-path) (into {}))] {:status 200 - :body (meta-merge - swagger - {:paths paths})})))) + :body (meta-merge swagger {:paths paths})}))))