mirror of
https://github.com/metosin/reitit.git
synced 2025-12-17 00:11:11 +00:00
Merge remote-tracking branch 'origin/master' into fix-openapi-examples
This commit is contained in:
commit
b4c0936207
10 changed files with 94 additions and 58 deletions
|
|
@ -14,6 +14,7 @@ We use [Break Versioning][breakver]. The version numbers follow a `<major>.<mino
|
||||||
|
|
||||||
## UNRELEASED
|
## UNRELEASED
|
||||||
|
|
||||||
|
* **BREAKING**: require Clojure 1.11, drop support for Clojure 1.10
|
||||||
* **BREAKING**: new syntax for `:request` and `:response` per-content-type coercions. See [coercion.md](doc/ring/coercion.md). [#627](https://github.com/metosin/reitit/issues/627)
|
* **BREAKING**: new syntax for `:request` and `:response` per-content-type coercions. See [coercion.md](doc/ring/coercion.md). [#627](https://github.com/metosin/reitit/issues/627)
|
||||||
* **BREAKING**: replace the openapi `:content-types` keyword with separate `:openapi/request-content-types` and `:openapi/response-content-types`. See [openapi.md](doc/ring/openapi.md)
|
* **BREAKING**: replace the openapi `:content-types` keyword with separate `:openapi/request-content-types` and `:openapi/response-content-types`. See [openapi.md](doc/ring/openapi.md)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -61,7 +61,7 @@
|
||||||
{:get {:summary "downloads a file"
|
{:get {:summary "downloads a file"
|
||||||
:swagger {:produces ["image/png"]}
|
:swagger {:produces ["image/png"]}
|
||||||
:responses {200 {:description "an image"
|
:responses {200 {:description "an image"
|
||||||
:content {"image/png" {:schema any?}}}}
|
:content {"image/png" {:schema string?}}}}
|
||||||
:handler (fn [_]
|
:handler (fn [_]
|
||||||
{:status 200
|
{:status 200
|
||||||
:headers {"Content-Type" "image/png"}
|
:headers {"Content-Type" "image/png"}
|
||||||
|
|
|
||||||
|
|
@ -67,6 +67,8 @@
|
||||||
["/download"
|
["/download"
|
||||||
{:get {:summary "downloads a file"
|
{:get {:summary "downloads a file"
|
||||||
:swagger {:produces ["image/png"]}
|
:swagger {:produces ["image/png"]}
|
||||||
|
:responses {200 {:description "an image"
|
||||||
|
:content {"image/png" {:schema string?}}}}
|
||||||
:handler (fn [_]
|
:handler (fn [_]
|
||||||
{:status 200
|
{:status 200
|
||||||
:headers {"Content-Type" "image/png"}
|
:headers {"Content-Type" "image/png"}
|
||||||
|
|
|
||||||
|
|
@ -76,33 +76,6 @@
|
||||||
(assoc error :transformed transformed))))
|
(assoc error :transformed transformed))))
|
||||||
value))))))))
|
value))))))))
|
||||||
|
|
||||||
;;
|
|
||||||
;; swagger
|
|
||||||
;;
|
|
||||||
|
|
||||||
(defmulti extract-parameter (fn [in _ _] in))
|
|
||||||
|
|
||||||
(defmethod extract-parameter :body [_ schema options]
|
|
||||||
(let [swagger-schema (swagger/transform schema (merge options {:in :body, :type :parameter}))]
|
|
||||||
[{:in "body"
|
|
||||||
:name (:title swagger-schema "body")
|
|
||||||
:description (:description swagger-schema "")
|
|
||||||
:required (not= :maybe (m/type schema))
|
|
||||||
:schema swagger-schema}]))
|
|
||||||
|
|
||||||
(defmethod extract-parameter :default [in schema options]
|
|
||||||
(let [{:keys [properties required]} (swagger/transform schema (merge options {:in in, :type :parameter}))]
|
|
||||||
(mapv
|
|
||||||
(fn [[k {:keys [type] :as schema}]]
|
|
||||||
(merge
|
|
||||||
{:in (name in)
|
|
||||||
:name k
|
|
||||||
:description (:description schema "")
|
|
||||||
:type type
|
|
||||||
:required (contains? (set required) k)}
|
|
||||||
schema))
|
|
||||||
properties)))
|
|
||||||
|
|
||||||
;;
|
;;
|
||||||
;; public api
|
;; public api
|
||||||
;;
|
;;
|
||||||
|
|
@ -156,24 +129,24 @@
|
||||||
{:type specification, :coercion :malli}))))
|
{:type specification, :coercion :malli}))))
|
||||||
(-get-apidocs [this specification {:keys [parameters responses] :as data}]
|
(-get-apidocs [this specification {:keys [parameters responses] :as data}]
|
||||||
(case specification
|
(case specification
|
||||||
:swagger (merge
|
:swagger (swagger/swagger-spec
|
||||||
(if parameters
|
(merge
|
||||||
{:parameters
|
(if parameters
|
||||||
(->> (for [[in schema] parameters
|
{::swagger/parameters
|
||||||
parameter (extract-parameter in schema options)]
|
(into
|
||||||
parameter)
|
(empty parameters)
|
||||||
(into []))})
|
(for [[k v] parameters]
|
||||||
(if responses
|
[k (compile v options)]))})
|
||||||
{:responses
|
(if responses
|
||||||
(into
|
{::swagger/responses
|
||||||
(empty responses)
|
(into
|
||||||
(for [[status response] responses]
|
(empty responses)
|
||||||
[status (as-> response $
|
(for [[k response] responses]
|
||||||
(set/rename-keys $ {:body :schema})
|
[k (as-> response $
|
||||||
(update $ :description (fnil identity ""))
|
(set/rename-keys $ {:body :schema})
|
||||||
(if (:schema $)
|
(if (:schema $)
|
||||||
(update $ :schema swagger/transform {:type :schema})
|
(update $ :schema compile options)
|
||||||
$))]))}))
|
$))]))})))
|
||||||
;; :openapi handled in reitit.openapi/-get-apidocs-openapi
|
;; :openapi handled in reitit.openapi/-get-apidocs-openapi
|
||||||
(throw
|
(throw
|
||||||
(ex-info
|
(ex-info
|
||||||
|
|
|
||||||
|
|
@ -67,7 +67,9 @@
|
||||||
(into
|
(into
|
||||||
(empty responses)
|
(empty responses)
|
||||||
(for [[k response] responses]
|
(for [[k response] responses]
|
||||||
[k (set/rename-keys response {:body :schema})]))})))
|
[k (-> response
|
||||||
|
(dissoc :content)
|
||||||
|
(set/rename-keys {:body :schema}))]))})))
|
||||||
;; :openapi handled in reitit.openapi/-get-apidocs-openapi
|
;; :openapi handled in reitit.openapi/-get-apidocs-openapi
|
||||||
(throw
|
(throw
|
||||||
(ex-info
|
(ex-info
|
||||||
|
|
|
||||||
|
|
@ -108,6 +108,7 @@
|
||||||
(empty responses)
|
(empty responses)
|
||||||
(for [[k response] responses]
|
(for [[k response] responses]
|
||||||
[k (as-> response $
|
[k (as-> response $
|
||||||
|
(dissoc $ :content)
|
||||||
(set/rename-keys $ {:body :schema}))]))})))
|
(set/rename-keys $ {:body :schema}))]))})))
|
||||||
;; :openapi handled in reitit.openapi/-get-apidocs-openapi
|
;; :openapi handled in reitit.openapi/-get-apidocs-openapi
|
||||||
(throw
|
(throw
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,6 @@
|
||||||
(s/def ::id (s/or :keyword keyword? :set (s/coll-of keyword? :into #{})))
|
(s/def ::id (s/or :keyword keyword? :set (s/coll-of keyword? :into #{})))
|
||||||
(s/def ::no-doc boolean?)
|
(s/def ::no-doc boolean?)
|
||||||
(s/def ::tags (s/coll-of (s/or :keyword keyword? :string string?) :kind set?))
|
(s/def ::tags (s/coll-of (s/or :keyword keyword? :string string?) :kind set?))
|
||||||
(s/def ::operationId string?)
|
|
||||||
(s/def ::summary string?)
|
(s/def ::summary string?)
|
||||||
(s/def ::description string?)
|
(s/def ::description string?)
|
||||||
(s/def ::operationId string?)
|
(s/def ::operationId string?)
|
||||||
|
|
@ -126,9 +125,15 @@
|
||||||
(if-let [endpoint (some->> c (keep transform-endpoint) (seq) (into {}))]
|
(if-let [endpoint (some->> c (keep transform-endpoint) (seq) (into {}))]
|
||||||
[(swagger-path p (r/options router)) endpoint]))
|
[(swagger-path p (r/options router)) endpoint]))
|
||||||
map-in-order #(->> % (apply concat) (apply array-map))
|
map-in-order #(->> % (apply concat) (apply array-map))
|
||||||
paths (->> router (r/compiled-routes) (filter accept-route) (map transform-path) map-in-order)]
|
paths (->> router (r/compiled-routes) (filter accept-route) (map transform-path) map-in-order)
|
||||||
|
definitions (apply merge
|
||||||
|
(for [[_path path-data] paths
|
||||||
|
[_method data] path-data]
|
||||||
|
(:definitions data)))
|
||||||
|
paths-without-definitions (update-vals paths (fn [methods]
|
||||||
|
(update-vals methods #(dissoc % :definitions))))]
|
||||||
{:status 200
|
{:status 200
|
||||||
:body (meta-merge swagger {:paths paths})}))
|
:body (meta-merge swagger {:paths paths-without-definitions :definitions definitions})}))
|
||||||
([req res raise]
|
([req res raise]
|
||||||
(try
|
(try
|
||||||
(res (create-swagger req))
|
(res (create-swagger req))
|
||||||
|
|
|
||||||
|
|
@ -37,7 +37,7 @@
|
||||||
[metosin/muuntaja "0.6.8"]
|
[metosin/muuntaja "0.6.8"]
|
||||||
[metosin/jsonista "0.3.7"]
|
[metosin/jsonista "0.3.7"]
|
||||||
[metosin/sieppari "0.0.0-alpha13"]
|
[metosin/sieppari "0.0.0-alpha13"]
|
||||||
[metosin/malli "0.11.0"]
|
[metosin/malli "0.12.0"]
|
||||||
|
|
||||||
;; https://clojureverse.org/t/depending-on-the-right-versions-of-jackson-libraries/5111
|
;; https://clojureverse.org/t/depending-on-the-right-versions-of-jackson-libraries/5111
|
||||||
[com.fasterxml.jackson.core/jackson-core "2.15.1"]
|
[com.fasterxml.jackson.core/jackson-core "2.15.1"]
|
||||||
|
|
@ -95,7 +95,7 @@
|
||||||
[metosin/muuntaja "0.6.8"]
|
[metosin/muuntaja "0.6.8"]
|
||||||
[metosin/sieppari "0.0.0-alpha13"]
|
[metosin/sieppari "0.0.0-alpha13"]
|
||||||
[metosin/jsonista "0.3.7"]
|
[metosin/jsonista "0.3.7"]
|
||||||
[metosin/malli "0.11.0"]
|
[metosin/malli "0.12.0"]
|
||||||
[lambdaisland/deep-diff "0.0-47"]
|
[lambdaisland/deep-diff "0.0-47"]
|
||||||
[meta-merge "1.0.0"]
|
[meta-merge "1.0.0"]
|
||||||
[com.bhauman/spell-spec "0.1.2"]
|
[com.bhauman/spell-spec "0.1.2"]
|
||||||
|
|
@ -126,7 +126,6 @@
|
||||||
[ring-cors "0.1.13"]
|
[ring-cors "0.1.13"]
|
||||||
|
|
||||||
[com.bhauman/rebel-readline "0.1.4"]]}
|
[com.bhauman/rebel-readline "0.1.4"]]}
|
||||||
:1.10 {:dependencies [[org.clojure/clojure "1.10.3"]]}
|
|
||||||
:perf {:jvm-opts ^:replace ["-server"
|
:perf {:jvm-opts ^:replace ["-server"
|
||||||
"-Xmx4096m"
|
"-Xmx4096m"
|
||||||
"-Dclojure.compiler.direct-linking=true"]
|
"-Dclojure.compiler.direct-linking=true"]
|
||||||
|
|
@ -152,7 +151,7 @@
|
||||||
"-XX:+PrintCompilation"
|
"-XX:+PrintCompilation"
|
||||||
"-XX:+UnlockDiagnosticVMOptions"
|
"-XX:+UnlockDiagnosticVMOptions"
|
||||||
"-XX:+PrintInlining"]}}
|
"-XX:+PrintInlining"]}}
|
||||||
:aliases {"all" ["with-profile" "dev,default:dev,default,1.10"]
|
:aliases {"all" ["with-profile" "dev,default"]
|
||||||
"perf" ["with-profile" "default,dev,perf"]
|
"perf" ["with-profile" "default,dev,perf"]
|
||||||
"test-clj" ["all" "do" ["bat-test"] ["check"]]
|
"test-clj" ["all" "do" ["bat-test"] ["check"]]
|
||||||
"test-browser" ["doo" "chrome-headless" "test"]
|
"test-browser" ["doo" "chrome-headless" "test"]
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,10 @@ set -e
|
||||||
|
|
||||||
for i in modules/*; do
|
for i in modules/*; do
|
||||||
cd $i
|
cd $i
|
||||||
clojure -J-Dclojure.main.report=stderr -Tcljdoc-analyzer analyze-local
|
if [ "$(ls -A src)" ]; then
|
||||||
|
clojure -J-Dclojure.main.report=stderr -Tcljdoc-analyzer analyze-local
|
||||||
|
else
|
||||||
|
echo "Skip $i, empty src folder"
|
||||||
|
fi
|
||||||
cd ../..
|
cd ../..
|
||||||
done
|
done
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,8 @@
|
||||||
[reitit.swagger :as swagger]
|
[reitit.swagger :as swagger]
|
||||||
[reitit.swagger-ui :as swagger-ui]
|
[reitit.swagger-ui :as swagger-ui]
|
||||||
[schema.core :as s]
|
[schema.core :as s]
|
||||||
[spec-tools.data-spec :as ds]))
|
[spec-tools.data-spec :as ds]
|
||||||
|
[malli.core :as mc]))
|
||||||
|
|
||||||
(defn- normalize
|
(defn- normalize
|
||||||
"Normalize format of swagger spec by converting it to json and back.
|
"Normalize format of swagger spec by converting it to json and back.
|
||||||
|
|
@ -22,6 +23,23 @@
|
||||||
j/write-value-as-string
|
j/write-value-as-string
|
||||||
(j/read-value j/keyword-keys-object-mapper)))
|
(j/read-value j/keyword-keys-object-mapper)))
|
||||||
|
|
||||||
|
(def malli-registry
|
||||||
|
(merge
|
||||||
|
(mc/base-schemas)
|
||||||
|
(mc/predicate-schemas)
|
||||||
|
(mc/type-schemas)
|
||||||
|
{::req-key [:or :keyword :string]
|
||||||
|
::req-val [:or map? :string]
|
||||||
|
::resp-map map?
|
||||||
|
::resp-string [:string {:min 1}]}))
|
||||||
|
|
||||||
|
|
||||||
|
(def PutReqBody
|
||||||
|
(mc/schema [:map-of ::req-key ::req-val] {:registry malli-registry}))
|
||||||
|
|
||||||
|
(def PutRespBody
|
||||||
|
(mc/schema [:or ::resp-map ::resp-string] {:registry malli-registry}))
|
||||||
|
|
||||||
(def app
|
(def app
|
||||||
(ring/ring-handler
|
(ring/ring-handler
|
||||||
(ring/router
|
(ring/router
|
||||||
|
|
@ -84,7 +102,13 @@
|
||||||
500 {:description "fail"}}
|
500 {:description "fail"}}
|
||||||
:handler (fn [{{{:keys [z]} :path
|
:handler (fn [{{{:keys [z]} :path
|
||||||
xs :body} :parameters}]
|
xs :body} :parameters}]
|
||||||
{:status 200, :body {:total (+ (reduce + xs) z)}})}}]]
|
{:status 200, :body {:total (+ (reduce + xs) z)}})}
|
||||||
|
:put {:summary "plus put with definitions"
|
||||||
|
:parameters {:body PutReqBody}
|
||||||
|
:responses {200 {:body PutRespBody}
|
||||||
|
500 {:description "fail"}}
|
||||||
|
:handler (fn [{{body :body} :parameters}]
|
||||||
|
{:status 200, :body (str "got " body)})}}]]
|
||||||
|
|
||||||
["/schema" {:coercion schema/coercion}
|
["/schema" {:coercion schema/coercion}
|
||||||
["/plus/*z"
|
["/plus/*z"
|
||||||
|
|
@ -137,6 +161,15 @@
|
||||||
expected {:x-id #{::math}
|
expected {:x-id #{::math}
|
||||||
:swagger "2.0"
|
:swagger "2.0"
|
||||||
:info {:title "my-api"}
|
:info {:title "my-api"}
|
||||||
|
:definitions {::req-key {:type "string"
|
||||||
|
:x-anyOf [{:type "string"}
|
||||||
|
{:type "string"}]}
|
||||||
|
::req-val {:type "object"
|
||||||
|
:x-anyOf [{:type "object"}
|
||||||
|
{:type "string"}]}
|
||||||
|
::resp-map {:type "object"},
|
||||||
|
::resp-string {:type "string"
|
||||||
|
:minLength 1}}
|
||||||
:paths {"/api/spec/plus/{z}" {:patch {:parameters []
|
:paths {"/api/spec/plus/{z}" {:patch {:parameters []
|
||||||
:summary "patch"
|
:summary "patch"
|
||||||
:operationId "Patch"
|
:operationId "Patch"
|
||||||
|
|
@ -246,7 +279,23 @@
|
||||||
400 {:schema {:type "string"}
|
400 {:schema {:type "string"}
|
||||||
:description "kosh"}
|
:description "kosh"}
|
||||||
500 {:description "fail"}}
|
500 {:description "fail"}}
|
||||||
:summary "plus with body"}}
|
:summary "plus with body"}
|
||||||
|
:put {:parameters [{:in "body"
|
||||||
|
:name "body"
|
||||||
|
:description ""
|
||||||
|
:required true
|
||||||
|
:schema
|
||||||
|
{:type "object"
|
||||||
|
:additionalProperties
|
||||||
|
{:$ref "#/definitions/reitit.swagger-test~1req-val"}}}]
|
||||||
|
:responses {200
|
||||||
|
{:schema
|
||||||
|
{:$ref "#/definitions/reitit.swagger-test~1resp-map"
|
||||||
|
:x-anyOf [{:$ref "#/definitions/reitit.swagger-test~1resp-map"}
|
||||||
|
{:$ref "#/definitions/reitit.swagger-test~1resp-string"}]}
|
||||||
|
:description ""}
|
||||||
|
500 {:description "fail"}}
|
||||||
|
:summary "plus put with definitions"}}
|
||||||
"/api/schema/plus/{z}" {:get {:parameters [{:description ""
|
"/api/schema/plus/{z}" {:get {:parameters [{:description ""
|
||||||
:format "int32"
|
:format "int32"
|
||||||
:in "query"
|
:in "query"
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue