mirror of
https://github.com/metosin/reitit.git
synced 2025-12-20 09:31:11 +00:00
read openapi metadata into openapi description
This commit is contained in:
parent
226ca889b6
commit
adef7ad06e
3 changed files with 75 additions and 11 deletions
|
|
@ -105,6 +105,10 @@
|
||||||
(or (-> request-or-response :content :default :schema)
|
(or (-> request-or-response :content :default :schema)
|
||||||
(:body request-or-response)))
|
(:body request-or-response)))
|
||||||
|
|
||||||
|
(defn get-default [request-or-response]
|
||||||
|
(or (-> request-or-response :content :default)
|
||||||
|
(some->> request-or-response :body (assoc {} :schema))))
|
||||||
|
|
||||||
(defn content-request-coercer [coercion {:keys [content body]} {::keys [extract-request-format serialize-failed-result]
|
(defn content-request-coercer [coercion {:keys [content body]} {::keys [extract-request-format serialize-failed-result]
|
||||||
:or {extract-request-format extract-request-format-default}}]
|
:or {extract-request-format extract-request-format-default}}]
|
||||||
(when coercion
|
(when coercion
|
||||||
|
|
|
||||||
|
|
@ -133,13 +133,22 @@
|
||||||
;; malli options
|
;; malli options
|
||||||
:options nil})
|
:options nil})
|
||||||
|
|
||||||
|
;; TODO: this is now seems like a generic transforming function that could be used in all of malli, spec, schema
|
||||||
|
;; ... just tranform the schemas in place
|
||||||
|
;; also, this has internally massive amount of duplicate code, could be simplified
|
||||||
|
;; ... tests too
|
||||||
(defn -get-apidocs-openapi
|
(defn -get-apidocs-openapi
|
||||||
[_ {:keys [request parameters responses content-types] :or {content-types ["application/json"]}} options]
|
[_ {:keys [request parameters responses content-types] :or {content-types ["application/json"]}} options]
|
||||||
(let [{:keys [body multipart]} parameters
|
(let [{:keys [body multipart]} parameters
|
||||||
parameters (dissoc parameters :request :body :multipart)
|
parameters (dissoc parameters :request :body :multipart)
|
||||||
->schema-object (fn [schema opts]
|
->schema-object (fn [schema opts]
|
||||||
(let [current-opts (merge options opts)]
|
(let [current-opts (merge options opts)]
|
||||||
(json-schema/transform schema current-opts)))]
|
(json-schema/transform schema current-opts)))
|
||||||
|
->content (fn [data schema]
|
||||||
|
(merge
|
||||||
|
{:schema schema}
|
||||||
|
(select-keys data [:description :examples])
|
||||||
|
(:openapi data)))]
|
||||||
(merge
|
(merge
|
||||||
(when (seq parameters)
|
(when (seq parameters)
|
||||||
{:parameters
|
{:parameters
|
||||||
|
|
@ -168,20 +177,21 @@
|
||||||
;; request allow to different :requestBody per content-type
|
;; request allow to different :requestBody per content-type
|
||||||
{:requestBody
|
{:requestBody
|
||||||
{:content (merge
|
{:content (merge
|
||||||
(when-let [default (coercion/get-default-schema request)]
|
(select-keys request [:description])
|
||||||
|
(when-let [{:keys [schema] :as data} (coercion/get-default request)]
|
||||||
(into {}
|
(into {}
|
||||||
(map (fn [content-type]
|
(map (fn [content-type]
|
||||||
(let [schema (->schema-object default {:in :requestBody
|
(let [schema (->schema-object schema {:in :requestBody
|
||||||
:type :schema
|
:type :schema
|
||||||
:content-type content-type})]
|
:content-type content-type})]
|
||||||
[content-type {:schema schema}])))
|
[content-type (->content data schema)])))
|
||||||
content-types))
|
content-types))
|
||||||
(into {}
|
(into {}
|
||||||
(map (fn [[content-type {:keys [schema]}]]
|
(map (fn [[content-type {:keys [schema] :as data}]]
|
||||||
(let [schema (->schema-object schema {:in :requestBody
|
(let [schema (->schema-object schema {:in :requestBody
|
||||||
:type :schema
|
:type :schema
|
||||||
:content-type content-type})]
|
:content-type content-type})]
|
||||||
[content-type {:schema schema}])))
|
[content-type (->content data schema)])))
|
||||||
(:content request)))}})
|
(:content request)))}})
|
||||||
(when multipart
|
(when multipart
|
||||||
{:requestBody
|
{:requestBody
|
||||||
|
|
@ -203,15 +213,15 @@
|
||||||
(let [schema (->schema-object default {:in :responses
|
(let [schema (->schema-object default {:in :responses
|
||||||
:type :schema
|
:type :schema
|
||||||
:content-type content-type})]
|
:content-type content-type})]
|
||||||
[content-type {:schema schema}])))
|
[content-type (->content nil schema)])))
|
||||||
content-types))
|
content-types))
|
||||||
(when content
|
(when content
|
||||||
(into {}
|
(into {}
|
||||||
(map (fn [[content-type {:keys [schema]}]]
|
(map (fn [[content-type {:keys [schema] :as data}]]
|
||||||
(let [schema (->schema-object schema {:in :responses
|
(let [schema (->schema-object schema {:in :responses
|
||||||
:type :schema
|
:type :schema
|
||||||
:content-type content-type})]
|
:content-type content-type})]
|
||||||
[content-type {:schema schema}])))
|
[content-type (->content data schema)])))
|
||||||
content)))
|
content)))
|
||||||
(dissoc :default))]
|
(dissoc :default))]
|
||||||
[status (merge (select-keys response [:description])
|
[status (merge (select-keys response [:description])
|
||||||
|
|
|
||||||
|
|
@ -774,3 +774,53 @@
|
||||||
spec))
|
spec))
|
||||||
(testing "spec is valid"
|
(testing "spec is valid"
|
||||||
(is (nil? (validate spec))))))
|
(is (nil? (validate spec))))))
|
||||||
|
|
||||||
|
(deftest openapi-malli-tests
|
||||||
|
(let [app (ring/ring-handler
|
||||||
|
(ring/router
|
||||||
|
[["/openapi.json"
|
||||||
|
{:get {:no-doc true
|
||||||
|
:handler (openapi/create-openapi-handler)}}]
|
||||||
|
|
||||||
|
["/malli" {:coercion malli/coercion}
|
||||||
|
["/plus" {:post {:summary "plus with body"
|
||||||
|
:request {:description "body description"
|
||||||
|
:content {"application/json" {:schema {:x int?, :y int?}
|
||||||
|
:examples {"1+1" {:x 1, :y 1}
|
||||||
|
"1+2" {:x 1, :y 2}}
|
||||||
|
:openapi {:example {:x 2, :y 2}}}}}
|
||||||
|
:responses {200 {:description "success"
|
||||||
|
:content {"application/json" {:schema {:total int?}
|
||||||
|
:examples {"2" {:total 2}
|
||||||
|
"3" {:total 3}}
|
||||||
|
:openapi {:example {:total 4}}}}}}
|
||||||
|
:handler (fn [request]
|
||||||
|
(let [{:keys [x y]} (-> request :parameters :body)]
|
||||||
|
{:status 200, :body {:total (+ x y)}}))}}]]]
|
||||||
|
|
||||||
|
{:validate reitit.ring.spec/validate
|
||||||
|
:data {:middleware [openapi/openapi-feature
|
||||||
|
rrc/coerce-exceptions-middleware
|
||||||
|
rrc/coerce-request-middleware
|
||||||
|
rrc/coerce-response-middleware]}}))]
|
||||||
|
(is (= {"/malli/plus" {:post {:requestBody {:content {:description "body description",
|
||||||
|
"application/json" {:schema {:type "object",
|
||||||
|
:properties {:x {:type "integer"},
|
||||||
|
:y {:type "integer"}},
|
||||||
|
:required [:x :y],
|
||||||
|
:additionalProperties false},
|
||||||
|
:examples {"1+1" {:x 1, :y 1}, "1+2" {:x 1, :y 2}},
|
||||||
|
:example {:x 2, :y 2}}}},
|
||||||
|
:responses {200 {:description "success",
|
||||||
|
:content {"application/json" {:schema {:type "object",
|
||||||
|
:properties {:total {:type "integer"}},
|
||||||
|
:required [:total],
|
||||||
|
:additionalProperties false},
|
||||||
|
:examples {"2" {:total 2}, "3" {:total 3}},
|
||||||
|
:example {:total 4}}}}},
|
||||||
|
:summary "plus with body"}}})
|
||||||
|
(-> {:request-method :get
|
||||||
|
:uri "/openapi.json"}
|
||||||
|
(app)
|
||||||
|
:body
|
||||||
|
:paths))))
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue