malli + swagger docs

This commit is contained in:
Tommi Reiman 2019-12-02 10:07:29 +02:00
parent 10be520a0d
commit 93f947831d
2 changed files with 130 additions and 30 deletions

View file

@ -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)

View file

@ -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 ""