forked from frankiesardo/route-swagger
/
doc.clj
74 lines (64 loc) · 3.01 KB
/
doc.clj
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
(ns route-swagger.doc
(:require [ring.swagger.swagger2-schema :as spec]
[ring.swagger.common :refer [deep-merge]]
[schema.core :as s]
[plumbing.core :refer [map-vals]]
[clojure.set :as set]
[linked.core :as linked]))
(s/defn annotate
"Attaches swagger documentation to an object"
[doc :- spec/Operation, obj]
(vary-meta obj assoc ::doc doc))
(def annotation
"Gets documentation from an annotated object"
(comp ::doc meta))
(defn- swagger-json-route? [route]
(when (= ::swagger-json (:route-name route)) route))
(defn- find-docs [{:keys [interceptors]}]
(keep annotation interceptors))
(defn- inject-swagger-into-routes [route-table swagger-object]
(for [route route-table]
(as-> route route
(if (swagger-json-route? route)
(vary-meta route assoc ::swagger-object swagger-object)
route)
(if-let [docs (seq (find-docs route))]
(annotate (apply deep-merge :into docs) route)
route))))
(defn- documented-handler? [route]
(-> route :interceptors last annotation))
(defn- ring-keys->swagger [operation]
(-> operation
(update :parameters (fn [m] (set/rename-keys m {:query-params :query
:path-params :path
:body-params :body
:form-params :formData
:headers :header})))
(update :responses (fn [m] (map-vals #(set/rename-keys % {:body :schema}) m)))))
(s/defschema SwaggerPaths
{s/Str {s/Keyword spec/Operation}})
(s/defn paths :- SwaggerPaths
"Generates swagger paths from an expanded route table.
This function can also be used to generate documentation offline or for easy
debugging (turning schema checks on)."
[route-table]
(apply merge-with merge
(for [{:keys [path method] :as route} route-table
:let [docs (find-docs route)
operation-id (some-> route :interceptors last :name name)]
:when (documented-handler? route)]
(linked/map path
(linked/map method
(ring-keys->swagger
(apply deep-merge :into (cons {:operationId operation-id} docs))))))))
(defn with-swagger
"Attaches swagger information as a meta key to each documented route. The
context passed to each interceptor has a reference to the selected route, so
information like request and response schemas and the swagger object can be
retrieved from its meta."
([route-table] (with-swagger route-table {:swagger "2.0"
:info {:title "Swagger API"
:version "0.0.1"}}))
([route-table docs]
(let [swagger-object (deep-merge :into {:paths (paths route-table)} docs)]
(inject-swagger-into-routes route-table swagger-object))))