mirror of
https://github.com/metosin/reitit.git
synced 2025-12-17 00:11:11 +00:00
malli + swagger docs
This commit is contained in:
parent
10be520a0d
commit
93f947831d
2 changed files with 130 additions and 30 deletions
|
|
@ -1,7 +1,9 @@
|
|||
(ns reitit.coercion.malli
|
||||
(:require [reitit.coercion :as coercion]
|
||||
[malli.transform :as mt]
|
||||
[malli.core :as m]))
|
||||
[malli.swagger :as swagger]
|
||||
[malli.core :as m]
|
||||
[clojure.set :as set]))
|
||||
|
||||
(defrecord Coercer [decoder encoder validator explainer])
|
||||
|
||||
|
|
@ -17,6 +19,29 @@
|
|||
(defmulti coerce-response? identity :default ::default)
|
||||
(defmethod coerce-response? ::default [_] true)
|
||||
|
||||
(defmulti extract-parameter (fn [in _] in))
|
||||
|
||||
(defmethod extract-parameter :body [_ schema]
|
||||
(let [swagger-schema (swagger/transform schema {:in :body, :type :parameter})]
|
||||
[{:in "body"
|
||||
:name (:title swagger-schema "")
|
||||
:description (:description swagger-schema "")
|
||||
:required (not= :maybe (m/name schema))
|
||||
:schema swagger-schema}]))
|
||||
|
||||
(defmethod extract-parameter :default [in schema]
|
||||
(let [{:keys [properties required]} (swagger/transform schema {: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)))
|
||||
|
||||
(def default-options
|
||||
{:coerce-response? coerce-response?
|
||||
:transformers {:body {:default default-transformer
|
||||
|
|
@ -29,31 +54,30 @@
|
|||
(reify coercion/Coercion
|
||||
(-get-name [_] :malli)
|
||||
(-get-options [_] opts)
|
||||
(-get-apidocs [this specification {:keys [parameters responses]}]
|
||||
;; TODO: this looks identical to spec, refactor when schema is done.
|
||||
#_(case specification
|
||||
:swagger (swagger/swagger-spec
|
||||
(merge
|
||||
(if parameters
|
||||
{:swagger/parameters
|
||||
(into
|
||||
(empty parameters)
|
||||
(for [[k v] parameters]
|
||||
[k (coercion/-compile-model this v nil)]))})
|
||||
(if responses
|
||||
{:swagger/responses
|
||||
(into
|
||||
(empty responses)
|
||||
(for [[k response] responses]
|
||||
[k (as-> response $
|
||||
(set/rename-keys $ {:body :schema})
|
||||
(if (:schema $)
|
||||
(update $ :schema #(coercion/-compile-model this % nil))
|
||||
$))]))})))
|
||||
(throw
|
||||
(ex-info
|
||||
(str "Can't produce Schema apidocs for " specification)
|
||||
{:type specification, :coercion :schema}))))
|
||||
(-get-apidocs [_ specification {:keys [parameters responses]}]
|
||||
(case specification
|
||||
:swagger (merge
|
||||
(if parameters
|
||||
{:parameters
|
||||
(->> (for [[in schema] parameters
|
||||
parameter (extract-parameter in schema)]
|
||||
parameter)
|
||||
(into []))})
|
||||
(if responses
|
||||
{:responses
|
||||
(into
|
||||
(empty responses)
|
||||
(for [[status response] responses]
|
||||
[status (as-> response $
|
||||
(set/rename-keys $ {:body :schema})
|
||||
(update $ :description (fnil identity ""))
|
||||
(if (:schema $)
|
||||
(update $ :schema swagger/transform {:type :schema})
|
||||
$))]))}))
|
||||
(throw
|
||||
(ex-info
|
||||
(str "Can't produce Schema apidocs for " specification)
|
||||
{:type specification, :coercion :schema}))))
|
||||
(-compile-model [_ model _] (m/schema model))
|
||||
(-open-model [_ schema] schema)
|
||||
(-encode-error [_ error] error)
|
||||
|
|
|
|||
|
|
@ -5,9 +5,11 @@
|
|||
[reitit.swagger-ui :as swagger-ui]
|
||||
[reitit.ring.coercion :as rrc]
|
||||
[reitit.coercion.spec :as spec]
|
||||
[reitit.coercion.malli :as malli]
|
||||
[reitit.coercion.schema :as schema]
|
||||
[schema.core :refer [Int]]
|
||||
[muuntaja.core :as m]))
|
||||
[muuntaja.core :as m]
|
||||
[spec-tools.data-spec :as ds]))
|
||||
|
||||
(def app
|
||||
(ring/ring-handler
|
||||
|
|
@ -33,7 +35,7 @@
|
|||
{:keys [z]} :path} :parameters}]
|
||||
{:status 200, :body {:total (+ x y z)}})}
|
||||
:post {:summary "plus with body"
|
||||
:parameters {:body [int?]
|
||||
:parameters {:body (ds/maybe [int?])
|
||||
:path {:z int?}}
|
||||
:swagger {:responses {400 {:schema {:type "string"}
|
||||
:description "kosh"}}}
|
||||
|
|
@ -43,6 +45,29 @@
|
|||
xs :body} :parameters}]
|
||||
{:status 200, :body {:total (+ (reduce + xs) z)}})}}]]
|
||||
|
||||
["/malli" {:coercion malli/coercion}
|
||||
["/plus/*z"
|
||||
{:get {:summary "plus"
|
||||
:parameters {:query [:map [:x int?] [:y int?]]
|
||||
:path [:map [:z int?]]}
|
||||
:swagger {:responses {400 {:schema {:type "string"}
|
||||
:description "kosh"}}}
|
||||
:responses {200 {:body [:map [:total int?]]}
|
||||
500 {:description "fail"}}
|
||||
:handler (fn [{{{:keys [x y]} :query
|
||||
{:keys [z]} :path} :parameters}]
|
||||
{:status 200, :body {:total (+ x y z)}})}
|
||||
:post {:summary "plus with body"
|
||||
:parameters {:body [:maybe [:vector int?]]
|
||||
:path [:map [:z int?]]}
|
||||
:swagger {:responses {400 {:schema {:type "string"}
|
||||
:description "kosh"}}}
|
||||
:responses {200 {:body [:map [:total int?]]}
|
||||
500 {:description "fail"}}
|
||||
:handler (fn [{{{:keys [z]} :path
|
||||
xs :body} :parameters}]
|
||||
{:status 200, :body {:total (+ (reduce + xs) z)}})}}]]
|
||||
|
||||
["/schema" {:coercion schema/coercion}
|
||||
["/plus/*z"
|
||||
{:get {:summary "plus"
|
||||
|
|
@ -115,6 +140,56 @@
|
|||
:description "kosh"}
|
||||
500 {:description "fail"}}
|
||||
:summary "plus"}}
|
||||
"/api/malli/plus/{z}" {:get {:parameters [{:description ""
|
||||
:format "int64"
|
||||
:in "query"
|
||||
:name :x
|
||||
:required true
|
||||
:type "integer"}
|
||||
{:description ""
|
||||
:format "int64"
|
||||
:in "query"
|
||||
:name :y
|
||||
:required true
|
||||
:type "integer"}
|
||||
{:in "path"
|
||||
:name :z
|
||||
:description ""
|
||||
:type "integer"
|
||||
:required true
|
||||
:format "int64"}]
|
||||
:responses {200 {:description ""
|
||||
:schema {:properties {:total {:format "int64"
|
||||
:type "integer"}}
|
||||
:required [:total]
|
||||
:type "object"}}
|
||||
400 {:schema {:type "string"}
|
||||
:description "kosh"}
|
||||
500 {:description "fail"}}
|
||||
:summary "plus"}
|
||||
:post {:parameters [{:in "body",
|
||||
:name "",
|
||||
:description "",
|
||||
:required false,
|
||||
:schema {:type "array",
|
||||
:items {:type "integer",
|
||||
:format "int64"}
|
||||
:x-nullable true}}
|
||||
{:in "path"
|
||||
:name :z
|
||||
:description ""
|
||||
:type "integer"
|
||||
:required true
|
||||
:format "int64"}]
|
||||
:responses {200 {:description ""
|
||||
:schema {:properties {:total {:format "int64"
|
||||
:type "integer"}}
|
||||
:required [:total]
|
||||
:type "object"}}
|
||||
400 {:schema {:type "string"}
|
||||
:description "kosh"}
|
||||
500 {:description "fail"}}
|
||||
:summary "plus with body"}}
|
||||
"/api/spec/plus/{z}" {:get {:parameters [{:description ""
|
||||
:format "int64"
|
||||
:in "query"
|
||||
|
|
@ -145,10 +220,11 @@
|
|||
:post {:parameters [{:in "body",
|
||||
:name "",
|
||||
:description "",
|
||||
:required true,
|
||||
:required false,
|
||||
:schema {:type "array",
|
||||
:items {:type "integer",
|
||||
:format "int64"}}}
|
||||
:format "int64"}
|
||||
:x-nullable true}}
|
||||
{:in "path"
|
||||
:name "z"
|
||||
:description ""
|
||||
|
|
|
|||
Loading…
Reference in a new issue