Repository: oliyh/martian
Pull request #147 (2022-02-13 22:52:36)

Handle responses that are $refs.
This partially addresses #145


Patch:
diff --git a/core/src/martian/openapi.cljc b/core/src/martian/openapi.cljc
index 84a388b..57f7151 100644
--- a/core/src/martian/openapi.cljc
+++ b/core/src/martian/openapi.cljc
@@ -135,6 +135,12 @@
      (lookup-ref components ref)
      param))
 
+;; After martian is updated to use Clojure 1.11.0+ then replace this and the uses with update-vals.
+(defn update-vals-future
+  "An implementation of `update-vals` that is in Clojure 1.11.0+."
+  [m f]
+  (zipmap (keys m) (map f (vals m))))
+
 (defn openapi->handlers [openapi-json content-types]
   (let [openapi-spec (keywordize-keys openapi-json)
         components (:components openapi-spec)]
@@ -149,7 +155,9 @@
                                                                 (map (partial resolve-ref components)
                                                                      (:parameters definition))))
                 body       (process-body (:requestBody definition) components (:encodes content-types))
-                responses  (process-responses (:responses definition) components (:decodes content-types))]]
+                responses  (process-responses (update-vals-future (:responses definition)
+                                                                  (partial resolve-ref components))
+                                              components (:decodes content-types))]]
       {:path-parts         (vec (tokenise-path url))
        :method             method
        :path-schema        (process-parameters (:path parameters) components)


Test patch:
diff --git a/core/test/martian/openapi_test.cljc b/core/test/martian/openapi_test.cljc
index c3c4a42..0d959ce 100644
--- a/core/test/martian/openapi_test.cljc
+++ b/core/test/martian/openapi_test.cljc
@@ -124,3 +124,39 @@
             :path-schema {:model_id s/Str
                           :version s/Str}}
            (select-keys handler [:path-parts :path-schema])))))
+
+(deftest reffed-responses-test
+  (let [openapi-json
+        {:paths {(keyword "/models")
+                 {:get {:operationId "list-models"
+                        :summary "Lists models"
+                        :responses {:401 {:$ref "#/components/responses/Unauthorized"}
+                                    :404 {:$ref "#/components/responses/NotFound"}}}}}
+         :components {:responses {:NotFound
+                                  {:description "The requested resource was not found."
+                                   :content
+                                   {:application/json
+                                    {:schema {:$ref "#/components/schemas/Error"}}}}
+                                  :Unauthorized
+                                  {:description "Unauthorized."
+                                   :content
+                                   {:application/json
+                                    {:schema {:$ref "#/components/schemas/Error"}}}}}
+                      :schemas {:Error
+                                {:type "object"
+                                 :properties
+                                 {:code
+                                  {:description "An enumerated error for machine use.",
+                                   :type "integer",
+                                   :readOnly true},
+                                  :details
+                                  {:description "A human-readable description of the error.",
+                                   :type "string",
+                                   :readOnly true}}}}}}
+        [handler] (openapi->handlers openapi-json {:encodes ["application/json"]
+                                                   :decodes ["application/json"]})]
+    (is (= [{:status (s/eq 401)
+             :body {(s/optional-key :code) s/Int (s/optional-key :details) s/Str}}
+            {:status (s/eq 404)
+             :body {(s/optional-key :code) s/Int (s/optional-key :details) s/Str}}]
+           (:response-schemas handler)))))