Skip to content

Commit

Permalink
json-schema produces string references
Browse files Browse the repository at this point in the history
  • Loading branch information
ikitommi committed Jan 4, 2024
1 parent c452388 commit fe635e9
Show file tree
Hide file tree
Showing 3 changed files with 42 additions and 47 deletions.
23 changes: 10 additions & 13 deletions src/malli/json_schema.cljc
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
(ns malli.json-schema
(:require [clojure.set :as set]
[clojure.string :as str]
[malli.core :as m]))

(declare -transform)
Expand All @@ -8,20 +9,16 @@
(-accept [this children options] "transforms schema to JSON Schema"))

(defn -ref [schema {::keys [transform definitions] :as options}]
(let [x (m/-ref schema)]
(when-not (contains? @definitions x)
(let [ref (as-> (m/-ref schema) $
(cond (var? $) (str (.toSymbol $))
(qualified-ident? $) (str (namespace $) "/" (name $))
:else (str $)))]
(when-not (contains? @definitions ref)
(let [child (m/deref schema)]
(swap! definitions assoc x ::recursion-stopper)
(swap! definitions assoc x (transform child options))))
{:$ref (apply str "#/definitions/"
(cond
;; / must be encoded as ~1 in JSON Schema
;; https://json-schema.org/draft/2019-09/relative-json-pointer.html
;; https://www.rfc-editor.org/rfc/rfc6901
(qualified-keyword? x) [(namespace x) "~1"
(name x)]
(keyword? x) [(name x)]
:else [x]))}))
(swap! definitions assoc ref ::recursion-stopper)
(swap! definitions assoc ref (transform child options))))
;; '/' must be encoded as '~1' in JSON Schema - https://www.rfc-editor.org/rfc/rfc6901
{:$ref (apply str "#/definitions/" (str/replace ref #"/" "~1"))}))

(defn -schema [schema {::keys [transform] :as options}]
(if (m/-ref schema)
Expand Down
18 changes: 8 additions & 10 deletions test/malli/experimental/time/json_schema_test.cljc
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,15 @@
(t/deftest time-formats
(t/is
(= {:type "object",
:properties
{:date {:$ref "#/definitions/time~1local-date"},
:time {:$ref "#/definitions/time~1offset-time"},
:date-time {:$ref "#/definitions/time~1offset-date-time"},
:duration {:$ref "#/definitions/time~1duration"}},
:properties {:date {:$ref "#/definitions/time~1local-date"},
:time {:$ref "#/definitions/time~1offset-time"},
:date-time {:$ref "#/definitions/time~1offset-date-time"},
:duration {:$ref "#/definitions/time~1duration"}},
:required [:date :time :date-time :duration],
:definitions
#:time{:local-date {:type "string", :format "date"},
:offset-time {:type "string", :format "time"},
:offset-date-time {:type "string", :format "date-time"},
:duration {:type "string", :format "duration"}}}
:definitions {"time/local-date" {:type "string", :format "date"},
"time/offset-time" {:type "string", :format "time"},
"time/offset-date-time" {:type "string", :format "date-time"},
"time/duration" {:type "string", :format "duration"}}}
(json/transform
[:map
[:date :time/local-date]
Expand Down
48 changes: 24 additions & 24 deletions test/malli/swagger_test.cljc
Original file line number Diff line number Diff line change
Expand Up @@ -313,7 +313,7 @@
(testing "generates swagger for ::parameters w/ basic schema + registry"
(let [registry (merge (m/type-schemas)
{::body [:string {:min 1}]})]
(is (= {:definitions {::body {:minLength 1, :type "string"}}
(is (= {:definitions {"malli.swagger-test/body" {:minLength 1, :type "string"}}
:parameters [{:description ""
:in "body"
:name "body"
Expand All @@ -327,9 +327,9 @@
(let [registry (merge (m/base-schemas) (m/type-schemas)
{::success [:map-of :keyword :string]
::error [:string {:min 1}]})]
(is (= {:definitions {::error {:minLength 1, :type "string"}
::success {:additionalProperties {:type "string"}
:type "object"}}
(is (= {:definitions {"malli.swagger-test/error" {:minLength 1, :type "string"}
"malli.swagger-test/success" {:additionalProperties {:type "string"}
:type "object"}}
:responses {200 {:description ""
:schema {:$ref "#/definitions/malli.swagger-test~1success"}}
400 {:description ""
Expand All @@ -345,11 +345,11 @@
{::req-body [:map-of :keyword :any]
::success-resp [:map [:it [:= "worked"]]]
::error-resp [:string {:min 1}]})]
(is (= {:definitions {::error-resp {:minLength 1, :type "string"}
::req-body {:additionalProperties {}, :type "object"}
::success-resp {:properties {:it {:const "worked"}}
:required [:it]
:type "object"}}
(is (= {:definitions {"malli.swagger-test/error-resp" {:minLength 1, :type "string"}
"malli.swagger-test/req-body" {:additionalProperties {}, :type "object"}
"malli.swagger-test/success-resp" {:properties {:it {:const "worked"}}
:required [:it]
:type "object"}}
:parameters [{:description ""
:in "body"
:name "body"
Expand Down Expand Up @@ -391,21 +391,21 @@
::req-body [:map [:a ::a]]
::success-resp [:map-of :keyword :string]
::error-resp :string})]
(is (= {:definitions {::a {:type "string"
:x-anyOf [{:type "string"}
{:$ref "#/definitions/malli.swagger-test~1b"}]}
::b {:type "string"
:x-anyOf [{:type "string"}
{:$ref "#/definitions/malli.swagger-test~1c"}]}
::c {:type "string"
:x-anyOf [{:type "string"}
{:$ref "#/definitions/malli.swagger-test~1a"}]}
::error-resp {:type "string"}
::req-body {:properties {:a {:$ref "#/definitions/malli.swagger-test~1a"}}
:required [:a]
:type "object"}
::success-resp {:additionalProperties {:type "string"}
:type "object"}}
(is (= {:definitions {"malli.swagger-test/a" {:type "string"
:x-anyOf [{:type "string"}
{:$ref "#/definitions/malli.swagger-test~1b"}]}
"malli.swagger-test/b" {:type "string"
:x-anyOf [{:type "string"}
{:$ref "#/definitions/malli.swagger-test~1c"}]}
"malli.swagger-test/c" {:type "string"
:x-anyOf [{:type "string"}
{:$ref "#/definitions/malli.swagger-test~1a"}]}
"malli.swagger-test/error-resp" {:type "string"}
"malli.swagger-test/req-body" {:properties {:a {:$ref "#/definitions/malli.swagger-test~1a"}}
:required [:a]
:type "object"}
"malli.swagger-test/success-resp" {:additionalProperties {:type "string"}
:type "object"}}
:parameters [{:description ""
:in "body"
:name "body"
Expand Down

0 comments on commit fe635e9

Please sign in to comment.