mirror of
https://github.com/metosin/reitit.git
synced 2025-12-18 00:41:12 +00:00
Initial reitit-swagger
This commit is contained in:
parent
a21a4f4476
commit
32c3082475
7 changed files with 158 additions and 3 deletions
|
|
@ -37,6 +37,7 @@ Optionally, the parts can be required separately:
|
||||||
[metosin/reitit-ring "0.1.0"] ; ring-router
|
[metosin/reitit-ring "0.1.0"] ; ring-router
|
||||||
[metosin/reitit-spec "0.1.0"] ; spec coercion
|
[metosin/reitit-spec "0.1.0"] ; spec coercion
|
||||||
[metosin/reitit-schema "0.1.0"] ; schema coercion
|
[metosin/reitit-schema "0.1.0"] ; schema coercion
|
||||||
|
[metosin/reitit-swagger "0.1.0"] ; swagger docs
|
||||||
```
|
```
|
||||||
|
|
||||||
## Quick start
|
## Quick start
|
||||||
|
|
|
||||||
|
|
@ -29,6 +29,7 @@ Optionally, the parts can be required separately:
|
||||||
[metosin/reitit-ring "0.1.0"] ; ring-router
|
[metosin/reitit-ring "0.1.0"] ; ring-router
|
||||||
[metosin/reitit-spec "0.1.0"] ; spec coercion
|
[metosin/reitit-spec "0.1.0"] ; spec coercion
|
||||||
[metosin/reitit-schema "0.1.0"] ; schema coercion
|
[metosin/reitit-schema "0.1.0"] ; schema coercion
|
||||||
|
[metosin/reitit-swagger "0.1.0"] ; swagger docs
|
||||||
```
|
```
|
||||||
|
|
||||||
For discussions, there is a [#reitit](https://clojurians.slack.com/messages/reitit/) channel in [Clojurians slack](http://clojurians.net/).
|
For discussions, there is a [#reitit](https://clojurians.slack.com/messages/reitit/) channel in [Clojurians slack](http://clojurians.net/).
|
||||||
|
|
|
||||||
9
modules/reitit-swagger/project.clj
Normal file
9
modules/reitit-swagger/project.clj
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
(defproject metosin/reitit-swagger "0.1.0-SNAPSHOT"
|
||||||
|
:description "Reitit: Swagger-support"
|
||||||
|
:url "https://github.com/metosin/reitit"
|
||||||
|
:license {:name "Eclipse Public License"
|
||||||
|
:url "http://www.eclipse.org/legal/epl-v10.html"}
|
||||||
|
:plugins [[lein-parent "0.3.2"]]
|
||||||
|
:parent-project {:path "../../project.clj"
|
||||||
|
:inherit [:deploy-repositories :managed-dependencies]}
|
||||||
|
:dependencies [[metosin/reitit-core]])
|
||||||
141
modules/reitit-swagger/src/reitit/swagger.cljc
Normal file
141
modules/reitit-swagger/src/reitit/swagger.cljc
Normal file
|
|
@ -0,0 +1,141 @@
|
||||||
|
(ns reitit.swagger
|
||||||
|
(:require [reitit.core :as r]
|
||||||
|
[meta-merge.core :refer [meta-merge]]
|
||||||
|
[clojure.spec.alpha :as s]
|
||||||
|
[clojure.set :as set]))
|
||||||
|
|
||||||
|
(s/def ::id keyword?)
|
||||||
|
(s/def ::no-doc boolean?)
|
||||||
|
(s/def ::tags (s/coll-of (s/or :keyword keyword? :string string?) :kind #{}))
|
||||||
|
(s/def ::summary string?)
|
||||||
|
(s/def ::description string?)
|
||||||
|
|
||||||
|
(s/def ::swagger (s/keys :req-un [::id]))
|
||||||
|
(s/def ::spec (s/keys :opt-un [::swagger ::no-doc ::tags ::summary ::description]))
|
||||||
|
|
||||||
|
(def swagger-feature
|
||||||
|
"Feature for handling swagger-documentation for routes.
|
||||||
|
Works both with Middleware & Interceptors. Does not participate
|
||||||
|
in actual request processing, just provides specs for the extra
|
||||||
|
valid keys for the route data. Should be accompanied by a
|
||||||
|
[[swagger-spec-handler]] to expose the swagger spec.
|
||||||
|
|
||||||
|
Swagger-spesific keys:
|
||||||
|
|
||||||
|
| key | description |
|
||||||
|
| --------------|-------------|
|
||||||
|
| :swagger | map of any swagger-data. Must have `:id` to identify the api
|
||||||
|
|
||||||
|
The following common route keys also contribute to swagger spec:
|
||||||
|
|
||||||
|
| key | description |
|
||||||
|
| --------------|-------------|
|
||||||
|
| :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
|
||||||
|
| :description | optional long description of an endpoint. Supports http://spec.commonmark.org/
|
||||||
|
| :parameters | optional input parameters for a route, in a format defined by the coercion
|
||||||
|
| :responses | optional descriptions of responess, in a format defined by coercion
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
[\"/api\"
|
||||||
|
{:swagger {:id :my-api}
|
||||||
|
:middleware [reitit.swagger/swagger-feature]}
|
||||||
|
|
||||||
|
[\"/swagger.json\"
|
||||||
|
{:get {:no-doc true
|
||||||
|
:swagger {:info {:title \"my-api\"}}
|
||||||
|
:handler reitit.swagger/swagger-spec-handler}}]
|
||||||
|
|
||||||
|
[\"/plus\"
|
||||||
|
{:get {:tags #{:math}
|
||||||
|
:summary \"adds numbers together\"
|
||||||
|
:description \"takes `x` and `y` query-params and adds them together\"
|
||||||
|
:parameters {:query {:x int?, :y int?}}
|
||||||
|
:responses {200 {:body {:total pos-int?}}}
|
||||||
|
:handler (fn [{:keys [parameters]}]
|
||||||
|
{:status 200
|
||||||
|
:body (+ (-> parameters :query :x)
|
||||||
|
(-> parameters :query :y)})}}]]"
|
||||||
|
{:name ::swagger
|
||||||
|
:spec ::spec})
|
||||||
|
|
||||||
|
(defn swagger-spec-handler
|
||||||
|
"Ring handler to emit swagger spec."
|
||||||
|
[{:keys [::r/router ::r/match :request-method]}]
|
||||||
|
(let [{:keys [id] :as swagger} (-> match :result request-method :data :swagger)
|
||||||
|
swagger (set/rename-keys swagger {:id :x-id})]
|
||||||
|
(if id
|
||||||
|
(let [paths (->> router
|
||||||
|
(r/routes)
|
||||||
|
(filter #(-> % second :swagger :id (= id)))
|
||||||
|
(map (fn [[p _ c]]
|
||||||
|
[p (some->> c
|
||||||
|
(keep
|
||||||
|
(fn [[m e]]
|
||||||
|
(if (and e (-> e :data :no-doc not))
|
||||||
|
[m (meta-merge
|
||||||
|
(-> e :data (select-keys [:tags :summary :description :parameters :responses]))
|
||||||
|
(-> e :data :swagger))])))
|
||||||
|
(seq)
|
||||||
|
(into {}))]))
|
||||||
|
(filter second)
|
||||||
|
(into {}))]
|
||||||
|
;; TODO: create the swagger spec
|
||||||
|
{:status 200
|
||||||
|
:body (meta-merge
|
||||||
|
swagger
|
||||||
|
{:paths paths})}))))
|
||||||
|
|
||||||
|
;;
|
||||||
|
;; spike
|
||||||
|
;;
|
||||||
|
|
||||||
|
(ns reitit.swagger.spike)
|
||||||
|
(require '[reitit.ring :as ring])
|
||||||
|
(require '[reitit.swagger :as swagger])
|
||||||
|
(require '[reitit.ring.coercion :as rrc])
|
||||||
|
(require '[reitit.coercion.spec :as spec])
|
||||||
|
|
||||||
|
(def app
|
||||||
|
(ring/ring-handler
|
||||||
|
(ring/router
|
||||||
|
["/api"
|
||||||
|
{:swagger {:id ::math}}
|
||||||
|
|
||||||
|
["/swagger.json"
|
||||||
|
{:get {:no-doc true
|
||||||
|
:swagger {:info {:title "my-api"}}
|
||||||
|
:handler swagger/swagger-spec-handler}}]
|
||||||
|
|
||||||
|
["/minus"
|
||||||
|
{:get {:summary "minus"
|
||||||
|
:parameters {:query {:x int?, :y int?}}
|
||||||
|
:responses {200 {:body {:total int?}}}
|
||||||
|
:handler (fn [{{{:keys [x y]} :query} :parameters}]
|
||||||
|
{:status 200, :body {:total (- x y)}})}}]
|
||||||
|
|
||||||
|
["/plus"
|
||||||
|
{:get {:summary "plus"
|
||||||
|
:parameters {:query {:x int?, :y int?}}
|
||||||
|
:responses {200 {:body {:total int?}}}
|
||||||
|
:handler (fn [{{{:keys [x y]} :query} :parameters}]
|
||||||
|
{:status 200, :body {:total (+ x y)}})}}]]
|
||||||
|
|
||||||
|
{:data {:middleware [swagger/swagger-feature
|
||||||
|
rrc/coerce-exceptions-middleware
|
||||||
|
rrc/coerce-request-middleware
|
||||||
|
rrc/coerce-response-middleware]
|
||||||
|
:coercion spec/coercion}})))
|
||||||
|
|
||||||
|
(app
|
||||||
|
{:request-method :get
|
||||||
|
:uri "/api/plus"
|
||||||
|
:query-params {:x "1", :y "2"}})
|
||||||
|
; {:body {:total 3}, :status 200}
|
||||||
|
|
||||||
|
(app
|
||||||
|
{:request-method :get
|
||||||
|
:uri "/api/swagger.json"})
|
||||||
|
; ... swagger-spec for "/api/minus" & "/api/plus"
|
||||||
|
|
@ -9,4 +9,5 @@
|
||||||
:dependencies [[metosin/reitit-core]
|
:dependencies [[metosin/reitit-core]
|
||||||
[metosin/reitit-ring]
|
[metosin/reitit-ring]
|
||||||
[metosin/reitit-spec]
|
[metosin/reitit-spec]
|
||||||
[metosin/reitit-schema]])
|
[metosin/reitit-schema]
|
||||||
|
[metosin/reitit-swagger]])
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,7 @@
|
||||||
[metosin/reitit-ring "0.1.0"]
|
[metosin/reitit-ring "0.1.0"]
|
||||||
[metosin/reitit-spec "0.1.0"]
|
[metosin/reitit-spec "0.1.0"]
|
||||||
[metosin/reitit-schema "0.1.0"]
|
[metosin/reitit-schema "0.1.0"]
|
||||||
|
[metosin/reitit-swagger "0.1.0-SNAPSHOT"]
|
||||||
|
|
||||||
[meta-merge "1.0.0"]
|
[meta-merge "1.0.0"]
|
||||||
[metosin/spec-tools "0.6.1"]
|
[metosin/spec-tools "0.6.1"]
|
||||||
|
|
@ -33,7 +34,8 @@
|
||||||
"modules/reitit-core/src"
|
"modules/reitit-core/src"
|
||||||
"modules/reitit-ring/src"
|
"modules/reitit-ring/src"
|
||||||
"modules/reitit-spec/src"
|
"modules/reitit-spec/src"
|
||||||
"modules/reitit-schema/src"]
|
"modules/reitit-schema/src"
|
||||||
|
"modules/reitit-swagger/src"]
|
||||||
|
|
||||||
:dependencies [[org.clojure/clojure "1.9.0"]
|
:dependencies [[org.clojure/clojure "1.9.0"]
|
||||||
[org.clojure/clojurescript "1.9.946"]
|
[org.clojure/clojurescript "1.9.946"]
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,6 @@
|
||||||
set -e
|
set -e
|
||||||
|
|
||||||
# Modules
|
# Modules
|
||||||
for ext in reitit-core reitit-ring reitit-spec reitit-schema reitit; do
|
for ext in reitit-core reitit-ring reitit-spec reitit-schema reitit-swagger reitit; do
|
||||||
cd modules/$ext; lein "$@"; cd ../..;
|
cd modules/$ext; lein "$@"; cd ../..;
|
||||||
done
|
done
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue