diff --git a/doc/ring/swagger.md b/doc/ring/swagger.md index 5dfaa9b8..881ef205 100644 --- a/doc/ring/swagger.md +++ b/doc/ring/swagger.md @@ -18,7 +18,7 @@ The following route data keys contribute to the generated swagger specification: | key | description | | --------------|-------------| -| :swagger | map of any swagger-data. Must have `:id` (keyword or sequence of keywords) to identify the api +| :swagger | map of any swagger-data. Can have `:id` (keyword or sequence of keywords) to identify the api | :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 @@ -67,7 +67,7 @@ Webjars also hosts a [version](https://github.com/webjars/swagger-ui) of the swa ### Simple example -* two routes in a single swagger-api `::api` +* two routes * swagger-spec served from `"/swagger.json"` * swagger-ui mounted to `"/"` @@ -84,8 +84,7 @@ Webjars also hosts a [version](https://github.com/webjars/swagger-ui) of the swa ["/pong" {:post (constantly "pong")}]] ["/swagger.json" {:get {:no-doc true - :handler (swagger/create-swagger-handler)}}]] - {:data {:swagger {:id ::api}}}) ;; for all routes + :handler (swagger/create-swagger-handler)}}]]) (swagger-ui/create-swagger-ui-handler {:path "/"}))) ``` @@ -95,7 +94,7 @@ The generated swagger spec: (app {:request-method :get :uri "/swagger.json"}) ;{:status 200 ; :body {:swagger "2.0" -; :x-id #{:user/api} +; :x-id #{:reitit.swagger/default} ; :paths {"/api/ping" {:get {}} ; "/api/pong" {:post {}}}}} ``` @@ -138,8 +137,7 @@ Whole example project is in [`/examples/ring-swagger`](https://github.com/metosi (ring/ring-handler (ring/router ["/api" - {:swagger {:id ::math}} - + ["/swagger.json" {:get {:no-doc true :swagger {:info {:title "my-api"}} @@ -195,9 +193,9 @@ http://localhost:3000 should render now the swagger-ui: ![Swagger-ui](../images/swagger.png) -## Advanced +## Multiple swagger apis -Route data in path `[:swagger :id]` can be either a keyword or a sequence of keywords. This enables one route to be part of multiple swagger apis. Normal route data [scoping rules](../basics/route_data.md#nested-route-data) rules apply. +There can be multiple swagger apis within a router. Each route can be part of 0..n swagger apis. Swagger apis are identified by value in route data under key path `[:swagger :id]`. It can be either a keyword or a sequence of keywords. Normal route data [scoping rules](../basics/route_data.md#nested-route-data) rules apply. Example with: diff --git a/examples/ring-swagger/src/example/server.clj b/examples/ring-swagger/src/example/server.clj index a359a8c2..adb86200 100644 --- a/examples/ring-swagger/src/example/server.clj +++ b/examples/ring-swagger/src/example/server.clj @@ -15,7 +15,6 @@ (ring/ring-handler (ring/router ["/api" - {:swagger {:id ::math}} ["/swagger.json" {:get {:no-doc true diff --git a/modules/reitit-swagger/src/reitit/swagger.cljc b/modules/reitit-swagger/src/reitit/swagger.cljc index 082a6253..a5e6511d 100644 --- a/modules/reitit-swagger/src/reitit/swagger.cljc +++ b/modules/reitit-swagger/src/reitit/swagger.cljc @@ -74,13 +74,13 @@ "Create a ring handler to emit swagger spec. Collects all routes from router which have an intersecting `[:swagger :id]` and which are not marked with `:no-doc` route data." (fn [{:keys [::r/router ::r/match :request-method]}] - (let [{:keys [id] :as swagger} (-> match :result request-method :data :swagger) + (let [{:keys [id] :or {id ::default} :as swagger} (-> match :result request-method :data :swagger) ->set (fn [x] (if (or (set? x) (sequential? x)) (set x) (conj #{} x))) ids (->set id) swagger (->> (dissoc swagger :id) (merge {:swagger "2.0" :x-id ids})) - accept-route #(-> % second :swagger :id ->set (set/intersection ids) seq) + accept-route #(-> % second :swagger :id (or ::default) ->set (set/intersection ids) seq) transform-endpoint (fn [[method {{:keys [coercion no-doc swagger] :as data} :data}]] (if (and data (not no-doc)) [method @@ -92,7 +92,6 @@ transform-path (fn [[p _ c]] (if-let [endpoint (some->> c (keep transform-endpoint) (seq) (into {}))] [(path->template p) endpoint]))] - (if id - (let [paths (->> router (r/compiled-routes) (filter accept-route) (map transform-path) (into {}))] - {:status 200 - :body (meta-merge swagger {:paths paths})}))))) + (let [paths (->> router (r/compiled-routes) (filter accept-route) (map transform-path) (into {}))] + {:status 200 + :body (meta-merge swagger {:paths paths})})))) diff --git a/test/cljc/reitit/swagger_test.clj b/test/cljc/reitit/swagger_test.clj index f3411042..7c563ec2 100644 --- a/test/cljc/reitit/swagger_test.clj +++ b/test/cljc/reitit/swagger_test.clj @@ -129,6 +129,9 @@ :summary "plus"}}}} spec))))) +(defn spec-paths [app uri] + (-> {:request-method :get, :uri uri} app :body :paths keys)) + (deftest multiple-swagger-apis-test (let [ping-route ["/ping" {:get (constantly "ping")}] spec-route ["/swagger.json" @@ -149,15 +152,13 @@ ["/deep" {:swagger {:id ::one}} ping-route]] ["/one-two" {:swagger {:id #{::one ::two}}} - spec-route]])) - spec-paths (fn [uri] - (-> {:request-method :get, :uri uri} app :body :paths keys))] + spec-route]]))] (is (= ["/common/ping" "/one/ping" "/two/deep/ping"] - (spec-paths "/one/swagger.json"))) + (spec-paths app "/one/swagger.json"))) (is (= ["/common/ping" "/two/ping"] - (spec-paths "/two/swagger.json"))) + (spec-paths app "/two/swagger.json"))) (is (= ["/common/ping" "/one/ping" "/two/ping" "/two/deep/ping"] - (spec-paths "/one-two/swagger.json"))))) + (spec-paths app "/one-two/swagger.json"))))) (deftest swagger-ui-congif-test (let [app (swagger-ui/create-swagger-ui-handler @@ -168,3 +169,16 @@ (is (= {:jsonEditor true, :url "/swagger.json"} (->> {:request-method :get, :uri "/config.json"} (app) :body (m/decode m/instance "application/json")))))) + +(deftest without-swagger-id-test + (let [app (ring/ring-handler + (ring/router + [["/ping" + {:get (constantly "ping")}] + ["/swagger.json" + {:get {:no-doc true + :handler (swagger/create-swagger-handler)}}]]))] + (is (= ["/ping"] (spec-paths app "/swagger.json"))) + (is (= #{::swagger/default} + (-> {:request-method :get :uri "/swagger.json"} + (app) :body :x-id)))))