mirror of
https://github.com/metosin/reitit.git
synced 2026-02-06 04:03:11 +00:00
Merge pull request #610 from metosin/openapi-examples
document & test OpenAPI multiple examples
This commit is contained in:
commit
6d9d7a09b0
3 changed files with 117 additions and 0 deletions
|
|
@ -31,6 +31,29 @@ Coercion keys also contribute to the docs:
|
||||||
|
|
||||||
Use `:request` parameter coercion (instead of `:body`) to unlock per-content-type coercions. See [Coercion](coercion.md).
|
Use `:request` parameter coercion (instead of `:body`) to unlock per-content-type coercions. See [Coercion](coercion.md).
|
||||||
|
|
||||||
|
## Custom OpenAPI data
|
||||||
|
|
||||||
|
The `:openapi` route data key can be used to add top-level or
|
||||||
|
route-level information to the generated OpenAPI spec. This is useful
|
||||||
|
for providing `"securitySchemes"`, `"examples"` or other OpenAPI keys
|
||||||
|
that are not generated automatically by reitit.
|
||||||
|
|
||||||
|
```clj
|
||||||
|
["/foo"
|
||||||
|
{:post {:parameters {:body {:name string? :age int?}}
|
||||||
|
:openapi {:requestBody
|
||||||
|
{:content
|
||||||
|
{"application/json"
|
||||||
|
{:examples {"Pyry" {:summary "Pyry, 45y"
|
||||||
|
:value {:name "Pyry" :age 45}}
|
||||||
|
"Cat" {:summary "Cat, 8y"
|
||||||
|
:value {:name "Cat" :age 8}}}}}}}
|
||||||
|
...}}]
|
||||||
|
```
|
||||||
|
|
||||||
|
See [the http-swagger example](../../examples/http-swagger) for a
|
||||||
|
working examples of `"securitySchemes"` and `"examples"`.
|
||||||
|
|
||||||
## OpenAPI spec
|
## OpenAPI spec
|
||||||
|
|
||||||
Serving the OpenAPI specification is handled by `reitit.openapi/create-openapi-handler`. It takes no arguments and returns a ring handler which collects at request-time data from all routes and returns an OpenAPI specification as Clojure data, to be encoded by a response formatter.
|
Serving the OpenAPI specification is handled by `reitit.openapi/create-openapi-handler`. It takes no arguments and returns a ring handler which collects at request-time data from all routes and returns an OpenAPI specification as Clojure data, to be encoded by a response formatter.
|
||||||
|
|
|
||||||
|
|
@ -112,6 +112,22 @@
|
||||||
{:status 200
|
{:status 200
|
||||||
:body {:total (+ x y)}})}
|
:body {:total (+ x y)}})}
|
||||||
:post {:summary "plus with data-spec body parameters"
|
:post {:summary "plus with data-spec body parameters"
|
||||||
|
;; OpenAPI3 named examples for request & response
|
||||||
|
:openapi {:requestBody
|
||||||
|
{:content
|
||||||
|
{"application/json"
|
||||||
|
{:examples {"add-one-one" {:summary "1+1"
|
||||||
|
:value {:x 1 :y 1}}
|
||||||
|
"add-one-two" {:summary "1+2"
|
||||||
|
:value {:x 1 :y 2}}}}}}
|
||||||
|
:responses
|
||||||
|
{200
|
||||||
|
{:content
|
||||||
|
{"application/json"
|
||||||
|
{:examples {"two" {:summary "2"
|
||||||
|
:value {:total 2}}
|
||||||
|
"three" {:summary "3"
|
||||||
|
:value {:total 3}}}}}}}}
|
||||||
:parameters {:body {:x int?, :y int?}}
|
:parameters {:body {:x int?, :y int?}}
|
||||||
:responses {200 {:body {:total int?}}}
|
:responses {200 {:body {:total int?}}}
|
||||||
:handler (fn [{{{:keys [x y]} :body} :parameters}]
|
:handler (fn [{{{:keys [x y]} :body} :parameters}]
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,7 @@
|
||||||
[reitit.swagger-ui :as swagger-ui]
|
[reitit.swagger-ui :as swagger-ui]
|
||||||
[schema.core :as s]
|
[schema.core :as s]
|
||||||
[schema-tools.core]
|
[schema-tools.core]
|
||||||
|
[spec-tools.core :as st]
|
||||||
[spec-tools.data-spec :as ds]))
|
[spec-tools.data-spec :as ds]))
|
||||||
|
|
||||||
(defn validate
|
(defn validate
|
||||||
|
|
@ -432,6 +433,83 @@
|
||||||
(testing "spec is valid"
|
(testing "spec is valid"
|
||||||
(is (nil? (validate spec))))))))
|
(is (nil? (validate spec))))))))
|
||||||
|
|
||||||
|
(deftest examples-test
|
||||||
|
(doseq [[coercion ->schema]
|
||||||
|
[[#'malli/coercion (fn [nom] [:map
|
||||||
|
{:json-schema/example {nom "EXAMPLE2"}}
|
||||||
|
[nom [:string {:json-schema/example "EXAMPLE"}]]])]
|
||||||
|
[#'schema/coercion (fn [nom] (schema-tools.core/schema
|
||||||
|
{nom (schema-tools.core/schema s/Str {:openapi/example "EXAMPLE"})}
|
||||||
|
{:openapi/example {nom "EXAMPLE2"}}))]
|
||||||
|
[#'spec/coercion (fn [nom]
|
||||||
|
(assoc
|
||||||
|
(ds/spec ::foo {nom (st/spec string? {:openapi/example "EXAMPLE"})})
|
||||||
|
:openapi/example {nom "EXAMPLE2"}))]]]
|
||||||
|
(testing coercion
|
||||||
|
(let [app (ring/ring-handler
|
||||||
|
(ring/router
|
||||||
|
[["/examples"
|
||||||
|
{:post {:decription "examples"
|
||||||
|
:coercion @coercion
|
||||||
|
:parameters {:query (->schema :q)
|
||||||
|
:request {:body (->schema :b)}}
|
||||||
|
:responses {200 {:description "success"
|
||||||
|
:body (->schema :ok)}}
|
||||||
|
:openapi {:requestBody
|
||||||
|
{:content
|
||||||
|
{"application/json"
|
||||||
|
{:examples
|
||||||
|
{"named-example" {:description "a named example"
|
||||||
|
:value {:b "named"}}}}}}
|
||||||
|
:responses
|
||||||
|
{200
|
||||||
|
{:content
|
||||||
|
{"application/json"
|
||||||
|
{:examples
|
||||||
|
{"response-example" {:value {:ok "response"}}}}}}}}
|
||||||
|
:handler identity}}]
|
||||||
|
["/openapi.json"
|
||||||
|
{:get {:handler (openapi/create-openapi-handler)
|
||||||
|
:openapi {:info {:title "" :version "0.0.1"}}
|
||||||
|
:no-doc true}}]]
|
||||||
|
{:data {:middleware [openapi/openapi-feature]}}))
|
||||||
|
spec (-> {:request-method :get
|
||||||
|
:uri "/openapi.json"}
|
||||||
|
app
|
||||||
|
:body)]
|
||||||
|
(testing "query parameter"
|
||||||
|
(is (match? [{:in "query"
|
||||||
|
:name "q"
|
||||||
|
:required true
|
||||||
|
:schema {:type "string"
|
||||||
|
:example "EXAMPLE"}}]
|
||||||
|
(-> spec
|
||||||
|
(get-in [:paths "/examples" :post :parameters])
|
||||||
|
normalize))))
|
||||||
|
(testing "body parameter"
|
||||||
|
(is (match? {:schema {:type "object"
|
||||||
|
:properties {:b {:type "string"
|
||||||
|
:example "EXAMPLE"}}
|
||||||
|
:required ["b"]
|
||||||
|
:example {:b "EXAMPLE2"}}
|
||||||
|
:examples {:named-example {:description "a named example"
|
||||||
|
:value {:b "named"}}}}
|
||||||
|
(-> spec
|
||||||
|
(get-in [:paths "/examples" :post :requestBody :content "application/json"])
|
||||||
|
normalize))))
|
||||||
|
(testing "body response"
|
||||||
|
(is (match? {:schema {:type "object"
|
||||||
|
:properties {:ok {:type "string"
|
||||||
|
:example "EXAMPLE"}}
|
||||||
|
:required ["ok"]
|
||||||
|
:example {:ok "EXAMPLE2"}}
|
||||||
|
:examples {:response-example {:value {:ok "response"}}}}
|
||||||
|
(-> spec
|
||||||
|
(get-in [:paths "/examples" :post :responses 200 :content "application/json"])
|
||||||
|
normalize))))
|
||||||
|
(testing "spec is valid"
|
||||||
|
(is (nil? (validate spec))))))))
|
||||||
|
|
||||||
(deftest multipart-test
|
(deftest multipart-test
|
||||||
(doseq [[coercion file-schema string-schema]
|
(doseq [[coercion file-schema string-schema]
|
||||||
[[#'malli/coercion
|
[[#'malli/coercion
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue