mirror of
https://github.com/metosin/reitit.git
synced 2025-12-20 09:31:11 +00:00
Initial swagger-ui integration
This commit is contained in:
parent
0b711b2560
commit
05fbaa1110
6 changed files with 71 additions and 22 deletions
|
|
@ -3,6 +3,5 @@
|
||||||
:dependencies [[org.clojure/clojure "1.9.0"]
|
:dependencies [[org.clojure/clojure "1.9.0"]
|
||||||
[ring "1.6.3"]
|
[ring "1.6.3"]
|
||||||
[metosin/muuntaja "0.5.0"]
|
[metosin/muuntaja "0.5.0"]
|
||||||
[org.webjars/swagger-ui "3.13.6"]
|
|
||||||
[metosin/reitit "0.1.1-SNAPSHOT"]]
|
[metosin/reitit "0.1.1-SNAPSHOT"]]
|
||||||
:repl-options {:init-ns example.server})
|
:repl-options {:init-ns example.server})
|
||||||
|
|
|
||||||
|
|
@ -21,26 +21,29 @@
|
||||||
:swagger {:info {:title "my-api"}}
|
:swagger {:info {:title "my-api"}}
|
||||||
:handler (swagger/create-swagger-handler)}}]
|
:handler (swagger/create-swagger-handler)}}]
|
||||||
|
|
||||||
["/spec" {:coercion spec/coercion}
|
["/spec"
|
||||||
|
{:coercion spec/coercion
|
||||||
|
:swagger {:tags ["spec"]}}
|
||||||
|
|
||||||
["/plus"
|
["/plus"
|
||||||
{:get {:summary "plus"
|
{:get {:summary "plus with spec"
|
||||||
:parameters {:query {:x int?, :y int?}}
|
:parameters {:query {:x int?, :y int?}}
|
||||||
:responses {200 {:body {:total int?}}}
|
:responses {200 {:body {:total int?}}}
|
||||||
:handler (fn [{{{:keys [x y]} :query} :parameters}]
|
:handler (fn [{{{:keys [x y]} :query} :parameters}]
|
||||||
{:status 200, :body {:total (+ x y)}})}}]]
|
{:status 200
|
||||||
|
:body {:total (+ x y)}})}}]]
|
||||||
|
|
||||||
|
["/schema"
|
||||||
|
{:coercion schema/coercion
|
||||||
|
:swagger {:tags ["schema"]}}
|
||||||
|
|
||||||
["/schema" {:coercion schema/coercion}
|
|
||||||
["/plus"
|
["/plus"
|
||||||
{:get {:summary "plus"
|
{:get {:summary "plus with schema"
|
||||||
:parameters {:query {:x Int, :y Int}}
|
:parameters {:query {:x Int, :y Int}}
|
||||||
:responses {200 {:body {:total Int}}}
|
:responses {200 {:body {:total Int}}}
|
||||||
:handler (fn [{{{:keys [x y]} :query} :parameters}]
|
:handler (fn [{{{:keys [x y]} :query} :parameters}]
|
||||||
{:status 200, :body {:total (+ x y)}})}}]]]
|
{:status 200
|
||||||
|
:body {:total (+ x y)}})}}]]]]
|
||||||
["/api-docs/*"
|
|
||||||
{:no-doc true
|
|
||||||
:handler (ring/create-resource-handler
|
|
||||||
{:root "META-INF/resources/webjars/swagger-ui/3.13.6"})}]]
|
|
||||||
|
|
||||||
{:data {:middleware [ring.middleware.params/wrap-params
|
{:data {:middleware [ring.middleware.params/wrap-params
|
||||||
muuntaja.middleware/wrap-format
|
muuntaja.middleware/wrap-format
|
||||||
|
|
@ -49,7 +52,8 @@
|
||||||
rrc/coerce-request-middleware
|
rrc/coerce-request-middleware
|
||||||
rrc/coerce-response-middleware]}})
|
rrc/coerce-response-middleware]}})
|
||||||
(ring/routes
|
(ring/routes
|
||||||
(ring/create-resource-handler {:path "/"})
|
(swagger/create-swagger-ui-handler
|
||||||
|
{:path "", :url "/api/swagger.json"})
|
||||||
(ring/create-default-handler))))
|
(ring/create-default-handler))))
|
||||||
|
|
||||||
(defn start []
|
(defn start []
|
||||||
|
|
|
||||||
|
|
@ -69,6 +69,8 @@
|
||||||
|
|
||||||
#?(:clj
|
#?(:clj
|
||||||
;; TODO: optimize for perf
|
;; TODO: optimize for perf
|
||||||
|
;; TODO: ring.middleware.not-modified/wrap-not-modified
|
||||||
|
;; TODO: ring.middleware.head/wrap-head
|
||||||
(defn create-resource-handler
|
(defn create-resource-handler
|
||||||
"A ring handler for serving classpath resources, configured via options:
|
"A ring handler for serving classpath resources, configured via options:
|
||||||
|
|
||||||
|
|
@ -82,19 +84,20 @@
|
||||||
| :allow-symlinks? | allow symlinks that lead to paths outside the root classpath directories, defaults to `false`"
|
| :allow-symlinks? | allow symlinks that lead to paths outside the root classpath directories, defaults to `false`"
|
||||||
([]
|
([]
|
||||||
(create-resource-handler nil))
|
(create-resource-handler nil))
|
||||||
([{:keys [parameter root path loader allow-symlinks? index-files]
|
([{:keys [parameter root path loader allow-symlinks? index-files paths]
|
||||||
:or {parameter (keyword "")
|
:or {parameter (keyword "")
|
||||||
root "public"
|
root "public"
|
||||||
index-files ["index.html"]}}]
|
index-files ["index.html"]
|
||||||
|
paths (constantly nil)}}]
|
||||||
(let [options {:root root, :loader loader, :allow-symlinks? allow-symlinks?}
|
(let [options {:root root, :loader loader, :allow-symlinks? allow-symlinks?}
|
||||||
path-size (count path)
|
path-size (inc (count path))
|
||||||
create (fn [handler]
|
create (fn [handler]
|
||||||
(fn
|
(fn
|
||||||
([request] (handler request))
|
([request] (handler request))
|
||||||
([request respond _] (respond (handler request)))))
|
([request respond _] (respond (handler request)))))
|
||||||
resource-response (fn [path accept]
|
resource-response (fn [path accept]
|
||||||
(if-let [path (accept path)]
|
(if-let [path (accept path)]
|
||||||
(if-let [response (response/resource-response path options)]
|
(if-let [response (or (paths path) (response/resource-response path options))]
|
||||||
(response/content-type response (mime-type/ext-mime-type path)))))
|
(response/content-type response (mime-type/ext-mime-type path)))))
|
||||||
path-or-index-response (fn [path accept]
|
path-or-index-response (fn [path accept]
|
||||||
(or (resource-response path accept)
|
(or (resource-response path accept)
|
||||||
|
|
|
||||||
|
|
@ -6,4 +6,6 @@
|
||||||
:plugins [[lein-parent "0.3.2"]]
|
:plugins [[lein-parent "0.3.2"]]
|
||||||
:parent-project {:path "../../project.clj"
|
:parent-project {:path "../../project.clj"
|
||||||
:inherit [:deploy-repositories :managed-dependencies]}
|
:inherit [:deploy-repositories :managed-dependencies]}
|
||||||
:dependencies [[metosin/reitit-core]])
|
:dependencies [[metosin/reitit-ring]
|
||||||
|
[metosin/jsonista]
|
||||||
|
[metosin/ring-swagger-ui]])
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,11 @@
|
||||||
[meta-merge.core :refer [meta-merge]]
|
[meta-merge.core :refer [meta-merge]]
|
||||||
[clojure.spec.alpha :as s]
|
[clojure.spec.alpha :as s]
|
||||||
[clojure.set :as set]
|
[clojure.set :as set]
|
||||||
[reitit.coercion :as coercion]))
|
[clojure.string :as str]
|
||||||
|
[reitit.ring :as ring]
|
||||||
|
[reitit.coercion :as coercion]
|
||||||
|
#?@(:clj [
|
||||||
|
[jsonista.core :as j]])))
|
||||||
|
|
||||||
(s/def ::id keyword?)
|
(s/def ::id keyword?)
|
||||||
(s/def ::no-doc boolean?)
|
(s/def ::no-doc boolean?)
|
||||||
|
|
@ -69,7 +73,8 @@
|
||||||
"Create a ring handler to emit swagger spec."
|
"Create a ring handler to emit swagger spec."
|
||||||
(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] :as swagger} (-> match :result request-method :data :swagger)
|
||||||
swagger (set/rename-keys swagger {:id :x-id})
|
swagger (->> (set/rename-keys swagger {:id :x-id})
|
||||||
|
(merge {:swagger "2.0"}))
|
||||||
accept-route #(-> % second :swagger :id (= id))
|
accept-route #(-> % second :swagger :id (= id))
|
||||||
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))
|
||||||
|
|
@ -86,3 +91,36 @@
|
||||||
(let [paths (->> router (r/routes) (filter accept-route) (map transform-path) (into {}))]
|
(let [paths (->> router (r/routes) (filter accept-route) (map transform-path) (into {}))]
|
||||||
{:status 200
|
{:status 200
|
||||||
:body (meta-merge swagger {:paths paths})})))))
|
:body (meta-merge swagger {:paths paths})})))))
|
||||||
|
|
||||||
|
#?(:clj
|
||||||
|
(defn create-swagger-ui-handler
|
||||||
|
"Creates a ring handler which can be used to serve swagger-ui.
|
||||||
|
|
||||||
|
| key | description |
|
||||||
|
| -----------------|-------------|
|
||||||
|
| :parameter | optional name of the wildcard parameter, defaults to unnamed keyword `:`
|
||||||
|
| :root | optional resource root, defaults to `\"swagger-ui\"`
|
||||||
|
| :url | path to swagger endpoint, defaults to `/swagger.json`
|
||||||
|
| :path | optional path to mount the handler to. Works only if mounted outside of a router.
|
||||||
|
| :config | parameters passed to swaggger-ui, keys transformed into camelCase."
|
||||||
|
([]
|
||||||
|
(create-swagger-ui-handler nil))
|
||||||
|
([options]
|
||||||
|
(let [mixed-case (fn [k]
|
||||||
|
(let [[f & rest] (str/split (name k) #"-")]
|
||||||
|
(apply str (str/lower-case f) (map str/capitalize rest))))
|
||||||
|
mixed-case-key (fn [[k v]] [(mixed-case k) v])
|
||||||
|
config-json (fn [{:keys [url config]}] (j/write-value-as-string (merge config {:url url})))
|
||||||
|
conf-js (fn [opts] (str "window.API_CONF = " (config-json opts) ";"))
|
||||||
|
options (as-> options $
|
||||||
|
(update $ :root (fnil identity "swagger-ui"))
|
||||||
|
(update $ :url (fnil identity "/swagger.json"))
|
||||||
|
(update $ :config #(->> % (map mixed-case-key) (into {})))
|
||||||
|
(assoc $ :paths {"conf.js" {:headers {"Content-Type" "application/javascript"}
|
||||||
|
:status 200
|
||||||
|
:body (conf-js $)}
|
||||||
|
"config.json" {:headers {"Content-Type" "application/json"}
|
||||||
|
:status 200
|
||||||
|
:body (config-json $)}}))]
|
||||||
|
(ring/routes
|
||||||
|
(ring/create-resource-handler options))))))
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,9 @@
|
||||||
[meta-merge "1.0.0"]
|
[meta-merge "1.0.0"]
|
||||||
[ring/ring-core "1.6.3"]
|
[ring/ring-core "1.6.3"]
|
||||||
[metosin/spec-tools "0.6.2-SNAPSHOT"]
|
[metosin/spec-tools "0.6.2-SNAPSHOT"]
|
||||||
[metosin/schema-tools "0.10.2-SNAPSHOT"]]
|
[metosin/schema-tools "0.10.2-SNAPSHOT"]
|
||||||
|
[metosin/ring-swagger-ui "2.2.10"]
|
||||||
|
[metosin/jsonista "0.2.0"]]
|
||||||
|
|
||||||
:plugins [[jonase/eastwood "0.2.5"]
|
:plugins [[jonase/eastwood "0.2.5"]
|
||||||
[lein-doo "0.1.10"]
|
[lein-doo "0.1.10"]
|
||||||
|
|
@ -50,7 +52,8 @@
|
||||||
|
|
||||||
[ring "1.6.3"]
|
[ring "1.6.3"]
|
||||||
[metosin/muuntaja "0.5.0"]
|
[metosin/muuntaja "0.5.0"]
|
||||||
[metosin/jsonista "0.1.1"]
|
[metosin/jsonista "0.2.0"]
|
||||||
|
[metosin/ring-swagger-ui "2.2.10"]
|
||||||
|
|
||||||
[criterium "0.4.4"]
|
[criterium "0.4.4"]
|
||||||
[org.clojure/test.check "0.9.0"]
|
[org.clojure/test.check "0.9.0"]
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue