Skip to content

Commit 6793c7a

Browse files
authored
Handle schemas with no type. (#148)
* Handle schemas with no type. If a schema has no "type" key, and ONLY has a "properties" key, then we can reasonably assume that the type is "object". See OAI/OpenAPI-Specification#1657 Excerpt: A particularly common form of this is a schema that omits type, but specifies properties. Strictly speaking, this does not mean that the value must be an object. It means that if the value is an object, and it includes any of those properties, the property values must conform to the corresponding property subschemas. In reality, this construct almost always means that the user intends type: object, and I think it would be reasonable for a code generator to assume this, maybe with a validation: strict|lax config option to control that behavior. * Improve code as per @oliyh's suggestion.
1 parent 1689a49 commit 6793c7a

File tree

2 files changed

+44
-1
lines changed

2 files changed

+44
-1
lines changed

core/src/martian/openapi.cljc

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,23 @@
5353
components
5454
(conj seen-set reference)))
5555
(wrap schema
56-
(condp = (:type schema)
56+
(condp = (if-let [typ (:type schema)]
57+
typ
58+
;; If a schema has no :type key, and the only key it contains is a :properties key,
59+
;; then the :type can reasonably be inferred as "object".
60+
;;
61+
;; See https://github.com/OAI/OpenAPI-Specification/issues/1657
62+
;;
63+
;; Excerpt:
64+
;; A particularly common form of this is a schema that omits type, but specifies properties.
65+
;; Strictly speaking, this does not mean that the value must be an object.
66+
;; It means that if the value is an object, and it includes any of those properties,
67+
;; the property values must conform to the corresponding property subschemas.
68+
;;
69+
;; In reality, this construct almost always means that the user intends type: object,
70+
;; and I think it would be reasonable for a code generator to assume this,
71+
;; maybe with a validation: strict|lax config option to control that behavior.
72+
(when (= #{:properties} (set (keys schema))) "object"))
5773
"array" [(openapi->schema (:items schema) components seen-set)]
5874
"object" (let [required? (set (:required schema))]
5975
(into {}

core/test/martian/openapi_test.cljc

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,3 +160,30 @@
160160
{:status (s/eq 404)
161161
:body {(s/optional-key :code) s/Int (s/optional-key :details) s/Str}}]
162162
(:response-schemas handler)))))
163+
164+
(deftest schemas-without-type-test
165+
(let [openapi-json
166+
{:paths {(keyword "/models")
167+
{:get {:operationId "list-models"
168+
:summary "Lists models"
169+
:responses {:404 {:$ref "#/components/responses/NotFound"}}}}}
170+
:components {:responses {:NotFound
171+
{:description "The requested resource was not found."
172+
:content
173+
{:application/json
174+
{:schema {:$ref "#/components/schemas/Error"}}}}}
175+
:schemas {:Error
176+
{:properties
177+
{:code
178+
{:description "An enumerated error for machine use.",
179+
:type "integer",
180+
:readOnly true},
181+
:details
182+
{:description "A human-readable description of the error.",
183+
:type "string",
184+
:readOnly true}}}}}}
185+
[handler] (openapi->handlers openapi-json {:encodes ["application/json"]
186+
:decodes ["application/json"]})]
187+
(is (= [{:status (s/eq 404)
188+
:body {(s/optional-key :code) s/Int (s/optional-key :details) s/Str}}]
189+
(:response-schemas handler)))))

0 commit comments

Comments
 (0)