diff --git a/src/apispec/core.py b/src/apispec/core.py index f1b877d7..f227d8d0 100644 --- a/src/apispec/core.py +++ b/src/apispec/core.py @@ -30,17 +30,17 @@ def __init__(self, plugins, openapi_version): self._plugins = plugins self.openapi_version = openapi_version self._schemas = {} - self._examples = {} - self._parameters = {} self._responses = {} + self._parameters = {} + self._examples = {} self._security_schemes = {} def to_dict(self): subsections = { - "example": self._examples, "schema": self._schemas, - "parameter": self._parameters, "response": self._responses, + "parameter": self._parameters, + "example": self._examples, "security_scheme": self._security_schemes, } return { @@ -49,21 +49,6 @@ def to_dict(self): if v != {} } - def example(self, name, component, **kwargs): - """Add an example which can be referenced - - :param str name: identifier by which example may be referenced. - :param dict component: example fields. - - https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.1.md#exampleObject - """ - if name in self._examples: - raise DuplicateComponentNameError( - 'Another example with name "{}" is already registered.'.format(name) - ) - self._examples[name] = component - return self - def schema(self, name, component=None, **kwargs): """Add a new schema to the spec. @@ -100,6 +85,30 @@ def schema(self, name, component=None, **kwargs): self._schemas[name] = ret return self + def response(self, component_id, component=None, **kwargs): + """Add a response which can be referenced. + + :param str component_id: ref_id to use as reference + :param dict component: response fields + :param dict kwargs: plugin-specific arguments + """ + if component_id in self._responses: + raise DuplicateComponentNameError( + 'Another response with name "{}" is already registered.'.format( + component_id + ) + ) + component = component or {} + ret = component.copy() + # Execute all helpers from plugins + for plugin in self._plugins: + try: + ret.update(plugin.response_helper(component, **kwargs) or {}) + except PluginMethodNotImplementedError: + continue + self._responses[component_id] = ret + return self + def parameter(self, component_id, location, component=None, **kwargs): """ Add a parameter which can be referenced. @@ -132,28 +141,19 @@ def parameter(self, component_id, location, component=None, **kwargs): self._parameters[component_id] = ret return self - def response(self, component_id, component=None, **kwargs): - """Add a response which can be referenced. + def example(self, name, component, **kwargs): + """Add an example which can be referenced - :param str component_id: ref_id to use as reference - :param dict component: response fields - :param dict kwargs: plugin-specific arguments + :param str name: identifier by which example may be referenced. + :param dict component: example fields. + + https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.1.md#exampleObject """ - if component_id in self._responses: + if name in self._examples: raise DuplicateComponentNameError( - 'Another response with name "{}" is already registered.'.format( - component_id - ) + 'Another example with name "{}" is already registered.'.format(name) ) - component = component or {} - ret = component.copy() - # Execute all helpers from plugins - for plugin in self._plugins: - try: - ret.update(plugin.response_helper(component, **kwargs) or {}) - except PluginMethodNotImplementedError: - continue - self._responses[component_id] = ret + self._examples[name] = component return self def security_scheme(self, component_id, component): diff --git a/src/apispec/plugin.py b/src/apispec/plugin.py index 460f9dcc..c04bcb9b 100644 --- a/src/apispec/plugin.py +++ b/src/apispec/plugin.py @@ -22,14 +22,6 @@ def schema_helper(self, name, definition, **kwargs): """ raise PluginMethodNotImplementedError - def parameter_helper(self, parameter, **kwargs): - """May return parameter component description as a dict. - - :param dict parameter: Parameter fields - :param dict kwargs: All additional keywords arguments sent to `APISpec.parameter()` - """ - raise PluginMethodNotImplementedError - def response_helper(self, response, **kwargs): """May return response component description as a dict. @@ -38,6 +30,14 @@ def response_helper(self, response, **kwargs): """ raise PluginMethodNotImplementedError + def parameter_helper(self, parameter, **kwargs): + """May return parameter component description as a dict. + + :param dict parameter: Parameter fields + :param dict kwargs: All additional keywords arguments sent to `APISpec.parameter()` + """ + raise PluginMethodNotImplementedError + def path_helper(self, path=None, operations=None, parameters=None, **kwargs): """May return a path as string and mutate operations dict and parameters list. diff --git a/src/apispec/utils.py b/src/apispec/utils.py index 7e413dc2..11757428 100644 --- a/src/apispec/utils.py +++ b/src/apispec/utils.py @@ -12,15 +12,15 @@ COMPONENT_SUBSECTIONS = { 2: { "schema": "definitions", - "parameter": "parameters", "response": "responses", + "parameter": "parameters", "security_scheme": "securityDefinitions", }, 3: { - "example": "examples", "schema": "schemas", - "parameter": "parameters", "response": "responses", + "parameter": "parameters", + "example": "examples", "security_scheme": "securitySchemes", }, } diff --git a/tests/test_core.py b/tests/test_core.py index f6743d1f..3978632b 100644 --- a/tests/test_core.py +++ b/tests/test_core.py @@ -138,47 +138,40 @@ class TestComponents: "name": {"type": "string", "example": "doggie"}, } - # Referenced examples are only supported in OAS 3.x - @pytest.mark.parametrize("spec", ("3.0.0",), indirect=True) - def test_example(self, spec): - spec.components.example("PetExample", {"value": {"a": "b"}}) - defs = get_examples(spec) - assert defs["PetExample"]["value"] == {"a": "b"} - def test_schema(self, spec): spec.components.schema("Pet", {"properties": self.properties}) - defs = get_schemas(spec) - assert "Pet" in defs - assert defs["Pet"]["properties"] == self.properties + schemas = get_schemas(spec) + assert "Pet" in schemas + assert schemas["Pet"]["properties"] == self.properties def test_schema_is_chainable(self, spec): spec.components.schema("Pet", {"properties": {}}).schema( "Plant", {"properties": {}} ) - defs = get_schemas(spec) - assert "Pet" in defs - assert "Plant" in defs + schemas = get_schemas(spec) + assert "Pet" in schemas + assert "Plant" in schemas def test_schema_description(self, spec): model_description = "An animal which lives with humans." spec.components.schema( "Pet", {"properties": self.properties, "description": model_description} ) - defs = get_schemas(spec) - assert defs["Pet"]["description"] == model_description + schemas = get_schemas(spec) + assert schemas["Pet"]["description"] == model_description def test_schema_stores_enum(self, spec): enum = ["name", "photoUrls"] spec.components.schema("Pet", {"properties": self.properties, "enum": enum}) - defs = get_schemas(spec) - assert defs["Pet"]["enum"] == enum + schemas = get_schemas(spec) + assert schemas["Pet"]["enum"] == enum def test_schema_discriminator(self, spec): spec.components.schema( "Pet", {"properties": self.properties, "discriminator": "name"} ) - defs = get_schemas(spec) - assert defs["Pet"]["discriminator"] == "name" + schemas = get_schemas(spec) + assert schemas["Pet"]["discriminator"] == "name" def test_schema_duplicate_name(self, spec): spec.components.schema("Pet", {"properties": self.properties}) @@ -188,6 +181,26 @@ def test_schema_duplicate_name(self, spec): ): spec.components.schema("Pet", properties=self.properties) + def test_response(self, spec): + response = {"description": "Pet not found"} + spec.components.response("NotFound", response) + responses = get_responses(spec) + assert responses["NotFound"] == response + + def test_response_is_chainable(self, spec): + spec.components.response("resp1").response("resp2") + responses = get_responses(spec) + assert "resp1" in responses + assert "resp2" in responses + + def test_response_duplicate_name(self, spec): + spec.components.response("test_response") + with pytest.raises( + DuplicateComponentNameError, + match='Another response with name "test_response" is already registered.', + ): + spec.components.response("test_response") + def test_parameter(self, spec): parameter = {"format": "int64", "type": "integer"} spec.components.parameter("PetId", "path", parameter) @@ -214,25 +227,28 @@ def test_parameter_duplicate_name(self, spec): ): spec.components.parameter("test_parameter", "path") - def test_response(self, spec): - response = {"description": "Pet not found"} - spec.components.response("NotFound", response) - responses = get_responses(spec) - assert responses["NotFound"] == response + # Referenced examples are only supported in OAS 3.x + @pytest.mark.parametrize("spec", ("3.0.0",), indirect=True) + def test_example(self, spec): + spec.components.example("test_example", {"value": {"a": "b"}}) + examples = get_examples(spec) + assert examples["test_example"]["value"] == {"a": "b"} - def test_response_is_chainable(self, spec): - spec.components.response("resp1").response("resp2") - responses = get_responses(spec) - assert "resp1" in responses - assert "resp2" in responses + @pytest.mark.parametrize("spec", ("3.0.0",), indirect=True) + def test_example_is_chainable(self, spec): + spec.components.example("test_example_1", {}).example("test_example_2", {}) + examples = get_examples(spec) + assert "test_example_1" in examples + assert "test_example_2" in examples - def test_response_duplicate_name(self, spec): - spec.components.response("test_response") + @pytest.mark.parametrize("spec", ("3.0.0",), indirect=True) + def test_example_duplicate_name(self, spec): + spec.components.example("test_example", {}) with pytest.raises( DuplicateComponentNameError, - match='Another response with name "test_response" is already registered.', + match='Another example with name "test_example" is already registered.', ): - spec.components.response("test_response") + spec.components.example("test_example", {}) def test_security_scheme(self, spec): sec_scheme = {"type": "apiKey", "in": "header", "name": "X-API-Key"} diff --git a/tests/utils.py b/tests/utils.py index d7ed6253..79b79763 100644 --- a/tests/utils.py +++ b/tests/utils.py @@ -3,26 +3,26 @@ from apispec.utils import build_reference -def get_examples(spec): - return spec.to_dict()["components"]["examples"] - - def get_schemas(spec): if spec.openapi_version.major < 3: return spec.to_dict()["definitions"] return spec.to_dict()["components"]["schemas"] +def get_responses(spec): + if spec.openapi_version.major < 3: + return spec.to_dict()["responses"] + return spec.to_dict()["components"]["responses"] + + def get_parameters(spec): if spec.openapi_version.major < 3: return spec.to_dict()["parameters"] return spec.to_dict()["components"]["parameters"] -def get_responses(spec): - if spec.openapi_version.major < 3: - return spec.to_dict()["responses"] - return spec.to_dict()["components"]["responses"] +def get_examples(spec): + return spec.to_dict()["components"]["examples"] def get_security_schemes(spec):