Skip to content

Commit e96e13c

Browse files
authored
Support OpenAPI 3.1.0 JsonSchemas (#5)
1 parent a8199a6 commit e96e13c

File tree

3 files changed

+98
-37
lines changed

3 files changed

+98
-37
lines changed

deps.edn

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
; license that can be found in the LICENSE file or at
55
; https://opensource.org/licenses/MIT.
66

7-
{:deps {io.swagger.parser.v3/swagger-parser {:mvn/version "2.1.18"}}
7+
{:deps {io.swagger.parser.v3/swagger-parser {:mvn/version "2.1.22"}}
88
:aliases {:test {:extra-deps {lambdaisland/kaocha {:mvn/version "1.87.1366"}
99
org.clojure/test.check {:mvn/version "1.1.1"}}
1010
:main-opts ["-m" "kaocha.runner" "--reporter" "kaocha.report.progress/report"]}}}

src/navi/core.clj

Lines changed: 37 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,7 @@
66

77
(ns navi.core
88
(:import [java.util Map$Entry]
9-
[io.swagger.v3.oas.models.media StringSchema
10-
IntegerSchema
11-
ObjectSchema
12-
ArraySchema
13-
NumberSchema
14-
BooleanSchema
15-
UUIDSchema
16-
MediaType]
9+
[io.swagger.v3.oas.models.media MediaType Schema]
1710
[io.swagger.v3.oas.models.parameters PathParameter
1811
HeaderParameter
1912
QueryParameter
@@ -34,6 +27,19 @@
3427
(contains? m k)
3528
(update-in [k] #(into [:map] %))))
3629

30+
(defn schema->spec [^Schema schema]
31+
(let [types (.getTypes schema)]
32+
(if (= 1 (count types))
33+
(spec schema)
34+
(try
35+
(->> (map (fn [type]
36+
(.setTypes schema #{type})
37+
(spec schema))
38+
types)
39+
(into [:or]))
40+
(finally
41+
(.setTypes schema types))))))
42+
3743
;; TODO: Better
3844
(defn ->prop-schema
3945
"Given a property and a required keys set, returns a malli spec.
@@ -47,7 +53,7 @@
4753
(conj key-schema
4854
(-> property
4955
.getValue
50-
spec))))
56+
schema->spec))))
5157

5258
(defn ->param-schema
5359
"Given a param applies the similar logic as prop to schema
@@ -62,38 +68,43 @@
6268
(conj key-spec
6369
(-> param
6470
.getSchema
65-
spec))))
71+
schema->spec))))
6672

67-
(defmulti spec class)
73+
(defmulti spec
74+
(fn [^Schema schema]
75+
(first (.getTypes schema))))
6876

6977
(defmethod spec
70-
StringSchema
71-
[_]
72-
string?)
78+
"string"
79+
[^Schema schema]
80+
(if (= "uuid" (.getFormat schema))
81+
uuid?
82+
string?))
7383

7484
(defmethod spec
75-
IntegerSchema
85+
"integer"
7686
[_]
7787
int?)
7888

79-
(defmethod spec
80-
NumberSchema
89+
(defmethod spec
90+
"number"
8191
[_]
8292
number?)
8393

8494
(defmethod spec
85-
BooleanSchema
95+
"boolean"
8696
[_]
8797
boolean?)
8898

99+
; Added in OpenAPI 3.1.0
89100
(defmethod spec
90-
UUIDSchema
101+
"null"
91102
[_]
92-
uuid?)
103+
nil?)
93104

94105
(defmethod spec
95-
ObjectSchema
96-
[^ObjectSchema schema]
106+
"object"
107+
[^Schema schema]
97108
(let [required (->> schema
98109
.getRequired
99110
(into #{}))
@@ -104,13 +115,13 @@
104115
(into [:map {:closed false}] schemas)))
105116

106117
(defmethod spec
107-
ArraySchema
108-
[^ArraySchema schema]
118+
"array"
119+
[^Schema schema]
109120
(let [items (.getItems schema)]
110121
[:sequential
111122
(if (nil? items)
112123
any?
113-
(spec items))]))
124+
(schema->spec items))]))
114125

115126
(defmulti param->data class)
116127

@@ -142,7 +153,7 @@
142153
.get)
143154
body-spec (-> content
144155
.getSchema
145-
spec)]
156+
schema->spec)]
146157
{:body (if (.getRequired param)
147158
body-spec
148159
[:or nil? body-spec])}))

test/navi/core_test.clj

Lines changed: 60 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@
99
[navi.core :as core])
1010
(:import [java.util Map LinkedHashMap]
1111
[io.swagger.v3.oas.models Operation PathItem]
12-
[io.swagger.v3.oas.models.media Content StringSchema IntegerSchema ObjectSchema ArraySchema MediaType UUIDSchema]
12+
[io.swagger.v3.oas.models.media Content StringSchema IntegerSchema JsonSchema
13+
NumberSchema ObjectSchema ArraySchema MediaType UUIDSchema Schema]
1314
[io.swagger.v3.oas.models.parameters Parameter PathParameter HeaderParameter QueryParameter RequestBody]))
1415

1516
(deftest map-to-malli-spec
@@ -48,33 +49,82 @@
4849
(deftest openapi-schema-to-malli-spec
4950
(testing "string"
5051
(is (= string?
51-
(core/spec (StringSchema.)))))
52+
(core/schema->spec (StringSchema.))))
53+
(is (= string?
54+
(core/schema->spec (doto (Schema.)
55+
(.addType "string"))))))
5256
(testing "integer"
5357
(is (= int?
54-
(core/spec (IntegerSchema.)))))
58+
(core/schema->spec (IntegerSchema.))))
59+
(is (= int?
60+
(core/schema->spec (doto (Schema.)
61+
(.addType "integer"))))))
62+
(testing "number"
63+
(is (= number?
64+
(core/schema->spec (NumberSchema.))))
65+
(is (= number?
66+
(core/schema->spec (doto (Schema.)
67+
(.addType "number"))))))
68+
(testing "null"
69+
(is (= nil?
70+
(core/schema->spec (doto (Schema.)
71+
(.addType "null"))))))
5572
(testing "empty object"
5673
(is (= [:map {:closed false}]
57-
(core/spec (ObjectSchema.)))))
74+
(core/schema->spec (ObjectSchema.))))
75+
(is (= [:map {:closed false}]
76+
(core/schema->spec (doto (Schema.)
77+
(.addType "object"))))))
5878
(testing "object"
5979
(let [props (doto (LinkedHashMap.)
6080
(.put "x" (IntegerSchema.))
6181
(.put "y" (StringSchema.)))
6282
obj (doto (ObjectSchema.)
6383
(.setRequired ["y" "x"])
64-
(.setProperties props))]
84+
(.setProperties props))
85+
props-json (doto (LinkedHashMap.)
86+
(.put "x" (doto (Schema.)
87+
(.addType "integer")))
88+
(.put "y" (doto (Schema.)
89+
(.addType "string"))))
90+
obj-json (doto (Schema.)
91+
(.addType "object")
92+
(.setRequired ["y" "x"])
93+
(.setProperties props-json))]
94+
(is (= [:map {:closed false} [:x int?] [:y string?]]
95+
(core/schema->spec obj)))
6596
(is (= [:map {:closed false} [:x int?] [:y string?]]
66-
(core/spec obj)))))
97+
(core/schema->spec obj-json)))))
6798
(testing "empty array"
6899
(is (= [:sequential any?]
69-
(core/spec (ArraySchema.)))))
100+
(core/schema->spec (ArraySchema.))))
101+
(is (= [:sequential any?]
102+
(core/schema->spec (doto (Schema.)
103+
(.addType "array"))))))
70104
(testing "array"
71105
(let [arr (doto (ArraySchema.)
72-
(.setItems (StringSchema.)))]
106+
(.setItems (StringSchema.)))
107+
arr-json (doto (Schema.)
108+
(.addType "array")
109+
(.setItems (doto (Schema.)
110+
(.addType "string"))))]
111+
(is (= [:sequential string?]
112+
(core/schema->spec arr)))
73113
(is (= [:sequential string?]
74-
(core/spec arr)))))
114+
(core/schema->spec arr-json)))))
75115
(testing "uuid"
76116
(is (= uuid?
77-
(core/spec (UUIDSchema.))))))
117+
(core/schema->spec (UUIDSchema.))))
118+
(is (= uuid?
119+
(core/schema->spec (doto (Schema.)
120+
(.addType "string")
121+
(.setFormat "uuid"))))))
122+
123+
(testing "jsonschemas with multiple types"
124+
(let [strint (-> (JsonSchema.)
125+
(.types #{"string" "integer"}))]
126+
(is (#{[:or string? int?] [:or int? string?]}
127+
(core/schema->spec strint))))))
78128

79129
(deftest parameters-to-malli-spec
80130
(testing "path"

0 commit comments

Comments
 (0)