Skip to content

Commit eded74c

Browse files
committed
Merge pull request metosin#217 from metosin/swagger-routes
Swagger routes
2 parents ede30f1 + be25179 commit eded74c

File tree

12 files changed

+212
-137
lines changed

12 files changed

+212
-137
lines changed

CHANGELOG.md

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,26 @@
4646
* `context*` => `context`
4747
* `defroutes*` => `defroutes`
4848

49-
* **BREAKING** `public-resource-routes` & `public-resources` are removed from `compojure.api.middleware`.
49+
* **BREAKING** `swagger-docs` and `swagger-ui` are now longer in `compojure.api.sweet`
50+
* Syntax was hairy and when configuring the spec-url it needed to be set to both in order to work
51+
* In future, there are multiple ways of setting the swagger stuff:
52+
* via api-options `:swagger` (has no defaults)
53+
* via `swagger-routes` function, mounting both the `swagger-ui` and `swagger-docs` and wiring them together
54+
* by default, mounts the swagger-ui to `/` and the swagger-spec to `/swagger.json`
55+
* via the old `swagger-ui` & `swagger-docs` (need to be separately imported from `compojure.api.swagger`).
56+
* see https://github.com/metosin/compojure-api/wiki/Swagger-integration for details
57+
58+
```clj
59+
(defapi app
60+
(swagger-routes)
61+
(GET "/ping" []
62+
(ok {:message "pong"})))
63+
64+
(defapi app
65+
{:swagger {:ui "/", :spec "/swagger.json"}}
66+
(GET "/ping" []
67+
(ok {:message "pong"})))
68+
```
5069

5170
* **BREAKING**: api-level coercion option is now a function of `request => type => matcher` as it is documented.
5271
Previously required a `type => matcher` map. Options are checked against `type => matcher` coercion input, and a
@@ -70,6 +89,8 @@ take a vector of middleware containing either
7089
has been renamed to `:swagger`.
7190
* will break at macro-expansion time with helpful exception
7291

92+
* **BREAKING** `public-resource-routes` & `public-resources` are removed from `compojure.api.middleware`.
93+
7394
* **BREAKING**: `compojure.api.legacy` namespace has been removed.
7495

7596
### Migration guide
@@ -84,8 +105,6 @@ https://github.com/metosin/compojure-api/wiki/Migration-Guide-to-1.0.0
84105

85106
* top-level `api` is now just function, not a macro. It takes an optional options maps and a top-level route function.
86107

87-
* `swagger-docs` and `swagger-ui` are now functions instead of macros.
88-
89108
* Coercer cache is now at api-level with 10000 entries.
90109

91110
* Code generated from restructured route macros is much cleaner now

README.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -52,11 +52,11 @@ Stuff on top of [Compojure](https://github.com/weavejester/compojure) for making
5252
:city s/Str}})
5353

5454
(defapi app
55-
(swagger-ui)
56-
(swagger-docs
57-
{:info {:title "My Swagger API"
58-
:description "Compojure Api example"}
59-
:tags [{:name "api", :description "sample api"}]})
55+
{:swagger {:spec "/swagger.json"
56+
:ui "/api-docs"
57+
:data {:data {:info {:title "My Swagger API"
58+
:description "Compojure Api example"}
59+
:tags [{:name "api", :description "sample api"}]}})
6060
(context "/api" []
6161
:tags ["api"]
6262
(GET "/hello" []

examples/src/examples/thingie.clj

Lines changed: 21 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -23,27 +23,27 @@
2323

2424
(def app
2525
(api
26-
(swagger-ui)
27-
(swagger-docs
28-
{:info {:version "1.0.0"
29-
:title "Thingies API"
30-
:description "the description"
31-
:termsOfService "http://www.metosin.fi"
32-
:contact {:name "My API Team"
33-
34-
:url "http://www.metosin.fi"}
35-
:license {:name "Eclipse Public License"
36-
:url "http://www.eclipse.org/legal/epl-v10.html"}}
37-
:tags [{:name "math", :description "Math with parameters"}
38-
{:name "pizzas", :description "Pizza API"}
39-
{:name "failing", :description "Handling uncaught exceptions"}
40-
{:name "dates", :description "Dates API"}
41-
{:name "responses", :description "Responses demo"}
42-
{:name "primitives", :description "Returning primitive values"}
43-
{:name "context", :description "context routes"}
44-
{:name "echo", :description "Echoes data"}
45-
{:name "ordered", :description "Ordered routes"}
46-
{:name "file", :description "File upload"}]})
26+
{:swagger {:ui "/"
27+
:spec "/swagger.json"
28+
:data {:info {:version "1.0.0"
29+
:title "Thingies API"
30+
:description "the description"
31+
:termsOfService "http://www.metosin.fi"
32+
:contact {:name "My API Team"
33+
34+
:url "http://www.metosin.fi"}
35+
:license {:name "Eclipse Public License"
36+
:url "http://www.eclipse.org/legal/epl-v10.html"}}
37+
:tags [{:name "math", :description "Math with parameters"}
38+
{:name "pizzas", :description "Pizza API"}
39+
{:name "failing", :description "Handling uncaught exceptions"}
40+
{:name "dates", :description "Dates API"}
41+
{:name "responses", :description "Responses demo"}
42+
{:name "primitives", :description "Returning primitive values"}
43+
{:name "context", :description "context routes"}
44+
{:name "echo", :description "Echoes data"}
45+
{:name "ordered", :description "Ordered routes"}
46+
{:name "file", :description "File upload"}]}}}
4747

4848
(context "/math" []
4949
:tags ["math"]

src/compojure/api/api.clj

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,18 @@
11
(ns compojure.api.api
2-
(:require [compojure.api.core :as core]
2+
(:require [compojure.api.core :as c]
33
[compojure.api.swagger :as swagger]
44
[compojure.api.middleware :as middleware]
55
[compojure.api.routes :as routes]
66
[compojure.api.common :as common]
77
[ring.swagger.common :as rsc]
8-
[compojure.api.meta :as meta]))
8+
[compojure.api.meta :as meta]
9+
[ring.swagger.middleware :as rsm]))
910

1011
(def api-defaults
1112
(merge
1213
middleware/api-middleware-defaults
13-
{:api {:invalid-routes-fn routes/log-invalid-child-routes}}))
14+
{:api {:invalid-routes-fn routes/log-invalid-child-routes}
15+
:swagger nil}))
1416

1517
(defn
1618
^{:doc (str
@@ -31,23 +33,27 @@
3133
invalid routes (not satisfying compojure.api.route.Routing)
3234
setting value to nil ignores invalid routes completely.
3335
defaults to `compojure.api.routes/log-invalid-child-routes`
36+
- **:swagger** Options to configure the Swagger-routes. Defaults to nil.
37+
See `compojure.api.swagger/swagger-routes` for details.
3438
3539
### api-middleware options
3640
3741
" (:doc (meta #'compojure.api.middleware/api-middleware)))}
3842
api
3943
[& body]
40-
(let [[options handlers] (common/extract-parameters body)
44+
(let [[options handlers] (common/extract-parameters body false)
4145
options (rsc/deep-merge api-defaults options)
42-
handler (apply core/routes handlers)
46+
handler (apply c/routes (concat handlers [(swagger/swagger-routes (:swagger options))]))
4347
routes (routes/get-routes handler (:api options))
4448
paths (-> routes routes/ring-swagger-paths swagger/transform-operations)
4549
lookup (routes/route-lookup-table routes)
50+
swagger-data (get-in options [:swagger :data])
4651
api-handler (-> handler
47-
(middleware/api-middleware (dissoc options :api))
52+
(cond-> swagger-data (rsm/wrap-swagger-data swagger-data))
53+
(middleware/api-middleware (dissoc options :api :swagger))
4854
(middleware/wrap-options {:paths paths
49-
:coercer (meta/memoized-coercer)
50-
:lookup lookup}))]
55+
:coercer (meta/memoized-coercer)
56+
:lookup lookup}))]
5157
(routes/create nil nil {} [handler] api-handler)))
5258

5359
(defmacro

src/compojure/api/common.clj

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,9 @@
1212
3. else => `{}`
1313
1414
Returns a tuple with parameters and body without the parameters"
15-
[c]
15+
[c expect-body]
1616
(cond
17-
(plain-map? (first c))
17+
(and (plain-map? (first c)) (or (not expect-body) (seq (rest c))))
1818
[(first c) (seq (rest c))]
1919

2020
(keyword? (first c))

src/compojure/api/meta.clj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -318,7 +318,7 @@
318318
(seq responses) (assoc :responses (apply merge responses))))
319319

320320
(defn restructure [method [path arg & args] {:keys [context?]}]
321-
(let [[options body] (extract-parameters args)
321+
(let [[options body] (extract-parameters args true)
322322
[path-string lets arg-with-request arg] (destructure-compojure-api-request path arg)
323323

324324
{:keys [lets

src/compojure/api/swagger.clj

Lines changed: 63 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
(ns compojure.api.swagger
2-
(:require [compojure.api.common :refer :all]
3-
[compojure.api.core :refer [GET undocumented]]
4-
[compojure.api.common :refer [extract-parameters]]
2+
(:require [compojure.api.core :as c]
3+
[compojure.api.common :as common]
54
[compojure.api.middleware :as mw]
65
[ring.util.http-response :refer [ok]]
76
[ring.swagger.common :as rsc]
@@ -13,10 +12,6 @@
1312
[compojure.api.routes :as routes]
1413
[cheshire.core :as cheshire]))
1514

16-
;;
17-
;; generate schema names
18-
;;
19-
2015
#_(defn ensure-parameter-schema-names [endpoint]
2116
(if (get-in endpoint [:parameters :body])
2217
(update-in endpoint [:parameters :body] #(swagger/with-named-sub-schemas % "Body"))
@@ -33,51 +28,34 @@
3328
responses))))
3429
endpoint))
3530

36-
;;
37-
;; routes
38-
;;
31+
(defn base-path [request]
32+
(let [context (swagger/context request)]
33+
(if (= "" context) "/" context)))
34+
35+
(defn swagger-spec-path
36+
[app]
37+
(some-> app
38+
routes/get-routes
39+
routes/route-lookup-table
40+
::swagger
41+
keys
42+
first))
3943

4044
(defn transform-operations [swagger]
4145
(->> swagger
4246
(swagger2/transform-operations routes/non-nil-routes)
4347
(swagger2/transform-operations routes/strip-no-doc-endpoints)))
4448

45-
(defn base-path [request]
46-
(let [context (swagger/context request)]
47-
(if (= "" context) "/" context)))
48-
49-
;;
50-
;; Public api
51-
;;
52-
5349
(defn swagger-ui [& params]
54-
(undocumented
50+
(c/undocumented
5551
(apply rsui/swagger-ui params)))
5652

57-
(defn swagger-docs
58-
"Route to serve the swagger api-docs. If the first
59-
parameter is a String, it is used as a url for the
60-
api-docs, otherwise \"/swagger.json\" will be used.
61-
Next Keyword value pairs OR a map for meta-data.
62-
Meta-data can be any valid swagger 2.0 data. Common
63-
case is to introduce API Info and Tags here:
64-
65-
{:info {:version \"1.0.0\"
66-
:title \"Sausages\"
67-
:description \"Sausage description\"
68-
:termsOfService \"http://helloreverb.com/terms/\"
69-
:contact {:name \"My API Team\"
70-
:email \"[email protected]\"
71-
:url \"http://www.metosin.fi\"}
72-
:license {:name: \"Eclipse Public License\"
73-
:url: \"http://www.eclipse.org/legal/epl-v10.html\"}}
74-
:tags [{:name \"sausages\", :description \"Sausage api-set}]}"
75-
[& body]
53+
(defn swagger-docs [& body]
7654
(let [[path body] (if (string? (first body))
7755
[(first body) (rest body)]
7856
["/swagger.json" body])
79-
[extra-info] (extract-parameters body)]
80-
(GET path request
57+
[extra-info] (common/extract-parameters body false)]
58+
(c/GET path request
8159
:no-doc true
8260
:name ::swagger
8361
(let [runtime-info (rsm/get-swagger-data request)
@@ -88,13 +66,51 @@
8866
spec (swagger2/swagger-json swagger options)]
8967
(ok spec)))))
9068

91-
(defn swagger-spec-path [app]
92-
(some-> app
93-
routes/get-routes
94-
routes/route-lookup-table
95-
::swagger
96-
keys
97-
first))
69+
;;
70+
;; Public api
71+
;;
72+
73+
(def swagger-defaults {:ui "/", :spec "/swagger.json"})
74+
75+
(defn swagger-routes
76+
"Returns routes for swagger-articats (ui & spec). Accepts an options map, with the
77+
following options:
78+
79+
**:ui** Uri for the swagger-ui (defaults to \"/\").
80+
Setting the value to nil will cause the swagger-ui not to be mounted
81+
82+
**:spec** Uri for the swagger-spec (defaults to \"/swagger.json\")
83+
Setting the value to nil will cause the swagger-ui not to be mounted
84+
85+
**:data** Swagger data in the Ring-Swagger format.
86+
87+
**:options**
88+
**:ui** Options to configure the ui
89+
**:spec** Options to configure the spec. Nada at the moment.
90+
91+
Example options:
92+
93+
{:ui \"/api-docs\"
94+
:spec \"/swagger.json\"
95+
:options {:ui {:jsonEditor true}
96+
:spec {}}
97+
:data {:info {:version \"1.0.0\"
98+
:title \"Sausages\"
99+
:description \"Sausage description\"
100+
:termsOfService \"http://helloreverb.com/terms/\"
101+
:contact {:name \"My API Team\"
102+
:email \"[email protected]\"
103+
:url \"http://www.metosin.fi\"}
104+
:license {:name: \"Eclipse Public License\"
105+
:url: \"http://www.eclipse.org/legal/epl-v10.html\"}}
106+
:tags [{:name \"sausages\", :description \"Sausage api-set\"}]}}"
107+
([] (swagger-routes {}))
108+
([options]
109+
(if options
110+
(let [{:keys [ui spec data] {ui-options :ui spec-options :spec} :options} (merge swagger-defaults options)]
111+
(c/routes
112+
(if ui (apply swagger-ui ui (mapcat identity (merge ui-options (if spec {:swagger-docs spec})))))
113+
(if spec (apply swagger-docs spec (mapcat identity data))))))))
98114

99115
(defn validate
100116
"Validates a api. If the api is Swagger-enabled, the swagger-spec

src/compojure/api/sweet.clj

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,7 @@
3838

3939
[compojure.api.swagger
4040

41-
swagger-ui
42-
swagger-docs]
41+
swagger-routes]
4342

4443
[ring.swagger.json-schema
4544

test/compojure/api/common_test.clj

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,23 @@
11
(ns compojure.api.common-test
2-
(:require [compojure.api.common :refer :all]
2+
(:require [compojure.api.common :as common]
33
[midje.sweet :refer :all]))
44

55
(fact "group-with"
6-
(group-with pos? [1 -10 2 -4 -1 999]) => [[1 2 999] [-10 -4 -1]]
7-
(group-with pos? [1 2 999]) => [[1 2 999] nil])
6+
(common/group-with pos? [1 -10 2 -4 -1 999]) => [[1 2 999] [-10 -4 -1]]
7+
(common/group-with pos? [1 2 999]) => [[1 2 999] nil])
8+
9+
(fact "extract-parameters"
10+
11+
(facts "expect body"
12+
(common/extract-parameters [] true) => [{} nil]
13+
(common/extract-parameters [{:a 1}] true) => [{} [{:a 1}]]
14+
(common/extract-parameters [:a 1] true) => [{:a 1} nil]
15+
(common/extract-parameters [{:a 1} {:b 2}] true) => [{:a 1} [{:b 2}]]
16+
(common/extract-parameters [:a 1 {:b 2}] true) => [{:a 1} [{:b 2}]])
17+
18+
(facts "don't expect body"
19+
(common/extract-parameters [] false) => [{} nil]
20+
(common/extract-parameters [{:a 1}] false) => [{:a 1} nil]
21+
(common/extract-parameters [:a 1] false) => [{:a 1} nil]
22+
(common/extract-parameters [{:a 1} {:b 2}] false) => [{:a 1} [{:b 2}]]
23+
(common/extract-parameters [:a 1 {:b 2}] false) => [{:a 1} [{:b 2}]]))

0 commit comments

Comments
 (0)