Repository: marshmallow-code/apispec
Pull request #651 (2021-03-30 12:39:08)

Resolve example references in parameters / request bodies / responses


Patch:
diff --git a/src/apispec/core.py b/src/apispec/core.py
index dd37fa7..16b1d23 100644
--- a/src/apispec/core.py
+++ b/src/apispec/core.py
@@ -340,6 +340,11 @@ class APISpec:
                     if "schema" in content:
                         content["schema"] = self.get_ref("schema", content["schema"])
 
+    def _resolve_examples(self, obj):
+        """Replace example reference as string with a $ref"""
+        for name, example in obj.get("examples", {}).items():
+            obj["examples"][name] = self.get_ref("example", example)
+
     def clean_parameters(self, parameters):
         """Ensure that all parameters with "in" equal to "path" are also required
         as required by the OpenAPI specification, as well as normalizing any
@@ -374,6 +379,8 @@ class APISpec:
             if parameter["in"] == "path":
                 parameter["required"] = True
 
+            self._resolve_examples(parameter)
+
         return [self.get_ref("parameter", p) for p in parameters]
 
     def clean_operations(self, operations):
@@ -401,6 +408,9 @@ class APISpec:
             # OAS 3
             if "requestBody" in operation:
                 self._resolve_schema(operation["requestBody"])
+                for media_type in operation["requestBody"]["content"].values():
+                    self._resolve_examples(media_type)
+
             if "responses" in operation:
                 responses = OrderedDict()
                 for code, response in operation["responses"].items():
@@ -413,5 +423,7 @@ class APISpec:
                     response = self.get_ref("response", response)
                     for name, header in response.get("headers", {}).items():
                         response["headers"][name] = self.get_ref("header", header)
+                    for media_type in response.get("content", {}).values():
+                        self._resolve_examples(media_type)
                     responses[str(code)] = response
                 operation["responses"] = responses


Test patch:
diff --git a/tests/test_core.py b/tests/test_core.py
index 0ecca86..94bd5cb 100644
--- a/tests/test_core.py
+++ b/tests/test_core.py
@@ -686,6 +686,41 @@ class TestPath:
         header_1 = resp["headers"]["header_1"]
         assert header_1 == build_ref(spec, "header", "Header_1")
 
+    # "examples" components section only exists in OAS 3
+    @pytest.mark.parametrize("spec", ("3.0.0",), indirect=True)
+    def test_path_resolve_response_examples(self, spec):
+        response = {
+            "content": {"application/json": {"examples": {"example_1": "Example_1"}}}
+        }
+        spec.path("/pet/{petId}", operations={"get": {"responses": {"200": response}}})
+        resp = get_paths(spec)["/pet/{petId}"]["get"]["responses"]["200"]
+        example_1 = resp["content"]["application/json"]["examples"]["example_1"]
+        assert example_1 == build_ref(spec, "example", "Example_1")
+
+    # "examples" components section only exists in OAS 3
+    @pytest.mark.parametrize("spec", ("3.0.0",), indirect=True)
+    def test_path_resolve_request_body_examples(self, spec):
+        request_body = {
+            "content": {"application/json": {"examples": {"example_1": "Example_1"}}}
+        }
+        spec.path("/pet/{petId}", operations={"get": {"requestBody": request_body}})
+        reqbdy = get_paths(spec)["/pet/{petId}"]["get"]["requestBody"]
+        example_1 = reqbdy["content"]["application/json"]["examples"]["example_1"]
+        assert example_1 == build_ref(spec, "example", "Example_1")
+
+    # "examples" components section only exists in OAS 3
+    @pytest.mark.parametrize("spec", ("3.0.0",), indirect=True)
+    def test_path_resolve_parameter_examples(self, spec):
+        parameter = {
+            "name": "test",
+            "in": "query",
+            "examples": {"example_1": "Example_1"},
+        }
+        spec.path("/pet/{petId}", operations={"get": {"parameters": [parameter]}})
+        param = get_paths(spec)["/pet/{petId}"]["get"]["parameters"][0]
+        example_1 = param["examples"]["example_1"]
+        assert example_1 == build_ref(spec, "example", "Example_1")
+
 
 class TestPlugins:
     @staticmethod