[:swagger :id] defaults to :reitit.swagger/default

This commit is contained in:
Tommi Reiman 2018-07-21 09:38:44 +03:00
parent 7fcefdd428
commit 8b6bc9bb80
4 changed files with 32 additions and 22 deletions

View file

@ -18,7 +18,7 @@ The following route data keys contribute to the generated swagger specification:
| key | description | | 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 | :no-doc | optional boolean to exclude endpoint from api docs
| :tags | optional set of strings of keywords tags for an endpoint api docs | :tags | optional set of strings of keywords tags for an endpoint api docs
| :summary | optional short string summary of an endpoint | :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 ### Simple example
* two routes in a single swagger-api `::api` * two routes
* swagger-spec served from `"/swagger.json"` * swagger-spec served from `"/swagger.json"`
* swagger-ui mounted to `"/"` * 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")}]] ["/pong" {:post (constantly "pong")}]]
["/swagger.json" ["/swagger.json"
{:get {:no-doc true {:get {:no-doc true
:handler (swagger/create-swagger-handler)}}]] :handler (swagger/create-swagger-handler)}}]])
{:data {:swagger {:id ::api}}}) ;; for all routes
(swagger-ui/create-swagger-ui-handler {:path "/"}))) (swagger-ui/create-swagger-ui-handler {:path "/"})))
``` ```
@ -95,7 +94,7 @@ The generated swagger spec:
(app {:request-method :get :uri "/swagger.json"}) (app {:request-method :get :uri "/swagger.json"})
;{:status 200 ;{:status 200
; :body {:swagger "2.0" ; :body {:swagger "2.0"
; :x-id #{:user/api} ; :x-id #{:reitit.swagger/default}
; :paths {"/api/ping" {:get {}} ; :paths {"/api/ping" {:get {}}
; "/api/pong" {:post {}}}}} ; "/api/pong" {:post {}}}}}
``` ```
@ -138,8 +137,7 @@ Whole example project is in [`/examples/ring-swagger`](https://github.com/metosi
(ring/ring-handler (ring/ring-handler
(ring/router (ring/router
["/api" ["/api"
{:swagger {:id ::math}}
["/swagger.json" ["/swagger.json"
{:get {:no-doc true {:get {:no-doc true
:swagger {:info {:title "my-api"}} :swagger {:info {:title "my-api"}}
@ -195,9 +193,9 @@ http://localhost:3000 should render now the swagger-ui:
![Swagger-ui](../images/swagger.png) ![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: Example with:

View file

@ -15,7 +15,6 @@
(ring/ring-handler (ring/ring-handler
(ring/router (ring/router
["/api" ["/api"
{:swagger {:id ::math}}
["/swagger.json" ["/swagger.json"
{:get {:no-doc true {:get {:no-doc true

View file

@ -74,13 +74,13 @@
"Create a ring handler to emit swagger spec. Collects all routes from router which have "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." an intersecting `[:swagger :id]` and which are not marked with `:no-doc` route data."
(fn [{:keys [::r/router ::r/match :request-method]}] (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))) ->set (fn [x] (if (or (set? x) (sequential? x)) (set x) (conj #{} x)))
ids (->set id) ids (->set id)
swagger (->> (dissoc swagger :id) swagger (->> (dissoc swagger :id)
(merge {:swagger "2.0" (merge {:swagger "2.0"
:x-id ids})) :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}]] transform-endpoint (fn [[method {{:keys [coercion no-doc swagger] :as data} :data}]]
(if (and data (not no-doc)) (if (and data (not no-doc))
[method [method
@ -92,7 +92,6 @@
transform-path (fn [[p _ c]] transform-path (fn [[p _ c]]
(if-let [endpoint (some->> c (keep transform-endpoint) (seq) (into {}))] (if-let [endpoint (some->> c (keep transform-endpoint) (seq) (into {}))]
[(path->template p) endpoint]))] [(path->template p) endpoint]))]
(if id (let [paths (->> router (r/compiled-routes) (filter accept-route) (map transform-path) (into {}))]
(let [paths (->> router (r/compiled-routes) (filter accept-route) (map transform-path) (into {}))] {:status 200
{:status 200 :body (meta-merge swagger {:paths paths})}))))
:body (meta-merge swagger {:paths paths})})))))

View file

@ -129,6 +129,9 @@
:summary "plus"}}}} :summary "plus"}}}}
spec))))) spec)))))
(defn spec-paths [app uri]
(-> {:request-method :get, :uri uri} app :body :paths keys))
(deftest multiple-swagger-apis-test (deftest multiple-swagger-apis-test
(let [ping-route ["/ping" {:get (constantly "ping")}] (let [ping-route ["/ping" {:get (constantly "ping")}]
spec-route ["/swagger.json" spec-route ["/swagger.json"
@ -149,15 +152,13 @@
["/deep" {:swagger {:id ::one}} ["/deep" {:swagger {:id ::one}}
ping-route]] ping-route]]
["/one-two" {:swagger {:id #{::one ::two}}} ["/one-two" {:swagger {:id #{::one ::two}}}
spec-route]])) spec-route]]))]
spec-paths (fn [uri]
(-> {:request-method :get, :uri uri} app :body :paths keys))]
(is (= ["/common/ping" "/one/ping" "/two/deep/ping"] (is (= ["/common/ping" "/one/ping" "/two/deep/ping"]
(spec-paths "/one/swagger.json"))) (spec-paths app "/one/swagger.json")))
(is (= ["/common/ping" "/two/ping"] (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"] (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 (deftest swagger-ui-congif-test
(let [app (swagger-ui/create-swagger-ui-handler (let [app (swagger-ui/create-swagger-ui-handler
@ -168,3 +169,16 @@
(is (= {:jsonEditor true, :url "/swagger.json"} (is (= {:jsonEditor true, :url "/swagger.json"}
(->> {:request-method :get, :uri "/config.json"} (->> {:request-method :get, :uri "/config.json"}
(app) :body (m/decode m/instance "application/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)))))