Skip to content

Commit

Permalink
Support OpenAPI 3.1.0 JsonSchemas (#5)
Browse files Browse the repository at this point in the history
  • Loading branch information
john-shaffer committed Apr 26, 2024
1 parent a8199a6 commit e96e13c
Show file tree
Hide file tree
Showing 3 changed files with 98 additions and 37 deletions.
2 changes: 1 addition & 1 deletion deps.edn
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
; license that can be found in the LICENSE file or at
; https://opensource.org/licenses/MIT.

{:deps {io.swagger.parser.v3/swagger-parser {:mvn/version "2.1.18"}}
{:deps {io.swagger.parser.v3/swagger-parser {:mvn/version "2.1.22"}}
:aliases {:test {:extra-deps {lambdaisland/kaocha {:mvn/version "1.87.1366"}
org.clojure/test.check {:mvn/version "1.1.1"}}
:main-opts ["-m" "kaocha.runner" "--reporter" "kaocha.report.progress/report"]}}}
63 changes: 37 additions & 26 deletions src/navi/core.clj
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,7 @@

(ns navi.core
(:import [java.util Map$Entry]
[io.swagger.v3.oas.models.media StringSchema
IntegerSchema
ObjectSchema
ArraySchema
NumberSchema
BooleanSchema
UUIDSchema
MediaType]
[io.swagger.v3.oas.models.media MediaType Schema]
[io.swagger.v3.oas.models.parameters PathParameter
HeaderParameter
QueryParameter
Expand All @@ -34,6 +27,19 @@
(contains? m k)
(update-in [k] #(into [:map] %))))

(defn schema->spec [^Schema schema]
(let [types (.getTypes schema)]
(if (= 1 (count types))
(spec schema)
(try
(->> (map (fn [type]
(.setTypes schema #{type})
(spec schema))
types)
(into [:or]))
(finally
(.setTypes schema types))))))

;; TODO: Better
(defn ->prop-schema
"Given a property and a required keys set, returns a malli spec.
Expand All @@ -47,7 +53,7 @@
(conj key-schema
(-> property
.getValue
spec))))
schema->spec))))

(defn ->param-schema
"Given a param applies the similar logic as prop to schema
Expand All @@ -62,38 +68,43 @@
(conj key-spec
(-> param
.getSchema
spec))))
schema->spec))))

(defmulti spec class)
(defmulti spec
(fn [^Schema schema]
(first (.getTypes schema))))

(defmethod spec
StringSchema
[_]
string?)
"string"
[^Schema schema]
(if (= "uuid" (.getFormat schema))
uuid?
string?))

(defmethod spec
IntegerSchema
"integer"
[_]
int?)

(defmethod spec
NumberSchema
(defmethod spec
"number"
[_]
number?)

(defmethod spec
BooleanSchema
"boolean"
[_]
boolean?)

; Added in OpenAPI 3.1.0
(defmethod spec
UUIDSchema
"null"
[_]
uuid?)
nil?)

(defmethod spec
ObjectSchema
[^ObjectSchema schema]
"object"
[^Schema schema]
(let [required (->> schema
.getRequired
(into #{}))
Expand All @@ -104,13 +115,13 @@
(into [:map {:closed false}] schemas)))

(defmethod spec
ArraySchema
[^ArraySchema schema]
"array"
[^Schema schema]
(let [items (.getItems schema)]
[:sequential
(if (nil? items)
any?
(spec items))]))
(schema->spec items))]))

(defmulti param->data class)

Expand Down Expand Up @@ -142,7 +153,7 @@
.get)
body-spec (-> content
.getSchema
spec)]
schema->spec)]
{:body (if (.getRequired param)
body-spec
[:or nil? body-spec])}))
Expand Down
70 changes: 60 additions & 10 deletions test/navi/core_test.clj
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@
[navi.core :as core])
(:import [java.util Map LinkedHashMap]
[io.swagger.v3.oas.models Operation PathItem]
[io.swagger.v3.oas.models.media Content StringSchema IntegerSchema ObjectSchema ArraySchema MediaType UUIDSchema]
[io.swagger.v3.oas.models.media Content StringSchema IntegerSchema JsonSchema
NumberSchema ObjectSchema ArraySchema MediaType UUIDSchema Schema]
[io.swagger.v3.oas.models.parameters Parameter PathParameter HeaderParameter QueryParameter RequestBody]))

(deftest map-to-malli-spec
Expand Down Expand Up @@ -48,33 +49,82 @@
(deftest openapi-schema-to-malli-spec
(testing "string"
(is (= string?
(core/spec (StringSchema.)))))
(core/schema->spec (StringSchema.))))
(is (= string?
(core/schema->spec (doto (Schema.)
(.addType "string"))))))
(testing "integer"
(is (= int?
(core/spec (IntegerSchema.)))))
(core/schema->spec (IntegerSchema.))))
(is (= int?
(core/schema->spec (doto (Schema.)
(.addType "integer"))))))
(testing "number"
(is (= number?
(core/schema->spec (NumberSchema.))))
(is (= number?
(core/schema->spec (doto (Schema.)
(.addType "number"))))))
(testing "null"
(is (= nil?
(core/schema->spec (doto (Schema.)
(.addType "null"))))))
(testing "empty object"
(is (= [:map {:closed false}]
(core/spec (ObjectSchema.)))))
(core/schema->spec (ObjectSchema.))))
(is (= [:map {:closed false}]
(core/schema->spec (doto (Schema.)
(.addType "object"))))))
(testing "object"
(let [props (doto (LinkedHashMap.)
(.put "x" (IntegerSchema.))
(.put "y" (StringSchema.)))
obj (doto (ObjectSchema.)
(.setRequired ["y" "x"])
(.setProperties props))]
(.setProperties props))
props-json (doto (LinkedHashMap.)
(.put "x" (doto (Schema.)
(.addType "integer")))
(.put "y" (doto (Schema.)
(.addType "string"))))
obj-json (doto (Schema.)
(.addType "object")
(.setRequired ["y" "x"])
(.setProperties props-json))]
(is (= [:map {:closed false} [:x int?] [:y string?]]
(core/schema->spec obj)))
(is (= [:map {:closed false} [:x int?] [:y string?]]
(core/spec obj)))))
(core/schema->spec obj-json)))))
(testing "empty array"
(is (= [:sequential any?]
(core/spec (ArraySchema.)))))
(core/schema->spec (ArraySchema.))))
(is (= [:sequential any?]
(core/schema->spec (doto (Schema.)
(.addType "array"))))))
(testing "array"
(let [arr (doto (ArraySchema.)
(.setItems (StringSchema.)))]
(.setItems (StringSchema.)))
arr-json (doto (Schema.)
(.addType "array")
(.setItems (doto (Schema.)
(.addType "string"))))]
(is (= [:sequential string?]
(core/schema->spec arr)))
(is (= [:sequential string?]
(core/spec arr)))))
(core/schema->spec arr-json)))))
(testing "uuid"
(is (= uuid?
(core/spec (UUIDSchema.))))))
(core/schema->spec (UUIDSchema.))))
(is (= uuid?
(core/schema->spec (doto (Schema.)
(.addType "string")
(.setFormat "uuid"))))))

(testing "jsonschemas with multiple types"
(let [strint (-> (JsonSchema.)
(.types #{"string" "integer"}))]
(is (#{[:or string? int?] [:or int? string?]}
(core/schema->spec strint))))))

(deftest parameters-to-malli-spec
(testing "path"
Expand Down

0 comments on commit e96e13c

Please sign in to comment.