Skip to content

Commit 3fabb61

Browse files
john-shafferlispyclouds
authored andcommitted
Improve error messages when op conversion fails
- Wrap errors during operation processing in an ex-info. The message contains the operation name and the ex-data contains the source operation. - Throw ex-infos with a "missing schema" message instead of NPEs when a necessary schema is null. This turns errors that previously looked like: `java.lang.NullPointerException: Cannot invoke "io.swagger.v3.oas.models.media.Schema.getTypes()" because "schema" is null` into this: `clojure.lang.ExceptionInfo: Exception processing operation "TestOp": Missing schema`
1 parent f81a15f commit 3fabb61

File tree

2 files changed

+81
-29
lines changed

2 files changed

+81
-29
lines changed

src/navi/core.clj

Lines changed: 39 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -41,17 +41,19 @@
4141
m)))
4242

4343
(defn schema->spec [^Schema schema]
44-
(let [types (.getTypes schema)]
45-
(if (= 1 (count types))
46-
(spec schema)
47-
(try
48-
(->> (map (fn [type]
49-
(.setTypes schema #{type})
50-
(spec schema))
51-
types)
52-
(into [:or]))
53-
(finally
54-
(.setTypes schema types))))))
44+
(if schema
45+
(let [types (.getTypes schema)]
46+
(if (= 1 (count types))
47+
(spec schema)
48+
(try
49+
(->> (map (fn [type]
50+
(.setTypes schema #{type})
51+
(spec schema))
52+
types)
53+
(into [:or]))
54+
(finally
55+
(.setTypes schema types)))))
56+
(throw (ex-info "Missing schema" {}))))
5557

5658
;; TODO: Better
5759
(defn ->prop-schema
@@ -192,7 +194,9 @@
192194
(defn media-type->data
193195
"Convert a Java Schema's MediaType to a spec that Reitit will accept."
194196
[^MediaType mt]
195-
{:schema (spec (.getSchema mt))})
197+
(if-let [schema (some-> mt .getSchema spec)]
198+
{:schema schema}
199+
(throw (ex-info "MediaType has no schema" {:media-type mt}))))
196200

197201
(defn handle-media-type-key
198202
"If the media type is \"default\", then return it as a keyword, otherwise pass through."
@@ -220,22 +224,29 @@
220224
"Converts a Java Operation to a map of parameters, responses, schemas and handler
221225
that conforms to reitit."
222226
[^Operation op handlers]
223-
(let [params (into [] (.getParameters op))
224-
request-body (.getRequestBody op)
225-
params (if (nil? request-body)
226-
params
227-
(conj params request-body))
228-
schemas (->> params
229-
(map param->data)
230-
(apply merge-with into)
231-
(wrap-map :path)
232-
(wrap-map :query)
233-
(wrap-map :header))
234-
responses (-> (.getResponses op)
235-
(update-kvs handle-response-key response->data))]
236-
(cond-> {:handler (get handlers (.getOperationId op))}
237-
(seq schemas) (assoc :parameters schemas)
238-
(seq responses) (assoc :responses responses))))
227+
(try
228+
(let [params (into [] (.getParameters op))
229+
request-body (.getRequestBody op)
230+
params (if (nil? request-body)
231+
params
232+
(conj params request-body))
233+
schemas (->> params
234+
(map param->data)
235+
(apply merge-with into)
236+
(wrap-map :path)
237+
(wrap-map :query)
238+
(wrap-map :header))
239+
responses (-> (.getResponses op)
240+
(update-kvs handle-response-key response->data))]
241+
(cond-> {:handler (get handlers (.getOperationId op))}
242+
(seq schemas) (assoc :parameters schemas)
243+
(seq responses) (assoc :responses responses)))
244+
(catch Exception e
245+
(throw (ex-info (str "Exception processing operation "
246+
(pr-str (.getOperationId op))
247+
": "(ex-message e))
248+
{:operation op}
249+
e)))))
239250

240251
(defn path-item->data
241252
"Converts a path to its corresponding vector of method and the operation map"

test/navi/core_test.clj

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@
77
(ns navi.core-test
88
(:require [clojure.test :refer [deftest testing is]]
99
[navi.core :as core])
10-
(:import [io.swagger.v3.oas.models Operation PathItem]
10+
(:import [clojure.lang ExceptionInfo]
11+
[io.swagger.v3.oas.models Operation PathItem]
1112
[io.swagger.v3.oas.models.media Content StringSchema IntegerSchema JsonSchema
1213
NumberSchema ObjectSchema ArraySchema MediaType UUIDSchema Schema]
1314
[io.swagger.v3.oas.models.parameters Parameter PathParameter HeaderParameter QueryParameter RequestBody]
@@ -228,6 +229,30 @@
228229
:responses {200 {:content {"application/json" {:schema [:map {:closed false}]}}}}}
229230
(core/operation->data operation handlers))))))
230231

232+
(deftest openapi-operation-to-malli-spec-missing-schema
233+
(testing "Missing response schema results in an informative error"
234+
(let [param (doto (PathParameter.)
235+
(.setName "x")
236+
(.setSchema (IntegerSchema.)))
237+
hparam (doto (HeaderParameter.)
238+
(.setName "y")
239+
(.setSchema (StringSchema.)))
240+
response (doto (ApiResponse.)
241+
(.setContent (doto (Content.)
242+
(.put "application/json" (MediaType.)))))
243+
responses (doto (ApiResponses.)
244+
(.put "200" response))
245+
operation (doto (Operation.)
246+
(.setParameters [param hparam])
247+
(.setResponses responses)
248+
(.setOperationId "TestOp"))
249+
handlers {"TestOp" "a handler"}]
250+
(is (thrown-with-msg?
251+
ExceptionInfo
252+
#".*TestOp.*schema"
253+
(core/operation->data operation handlers))
254+
"Error message contains operation name and mentions the missing schema"))))
255+
231256
(deftest openapi-path-to-malli-spec
232257
(testing "OpenAPI path to reitit route"
233258
(let [param (doto (PathParameter.)
@@ -242,3 +267,19 @@
242267
(is (= {:get {:handler "a handler"
243268
:parameters {:path [:map [:x int?]]}}}
244269
(core/path-item->data path-item handlers))))))
270+
271+
(deftest openapi-path-to-malli-spec-missing-schema
272+
(testing "Missing path parameter schema results in an informative error"
273+
(let [param (doto (PathParameter.)
274+
(.setName "x"))
275+
operation (doto (Operation.)
276+
(.setParameters [param])
277+
(.setOperationId "TestOp"))
278+
handlers {"TestOp" "a handler"}
279+
path-item (doto (PathItem.)
280+
(.setGet operation))]
281+
(is (thrown-with-msg?
282+
ExceptionInfo
283+
#".*TestOp.*schema"
284+
(core/path-item->data path-item handlers))
285+
"Error message contains operation name and mentions the missing schema"))))

0 commit comments

Comments
 (0)