Skip to content

Commit 90d064e

Browse files
authored
Add support for Falcon Resource suffixes (#19)
1 parent 9e48608 commit 90d064e

File tree

3 files changed

+77
-12
lines changed

3 files changed

+77
-12
lines changed

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,3 +108,7 @@ venv.bak/
108108
.vscode
109109
.envrc
110110
todo.md
111+
112+
# PYCharm
113+
.idea/
114+

falcon_apispec/falcon_plugin.py

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
import re
33
from apispec import BasePlugin, yaml_utils
44
from apispec.exceptions import APISpecError
5-
import falcon
65

76

87
class FalconPlugin(BasePlugin):
@@ -20,7 +19,17 @@ def _generate_resource_uri_mapping(app):
2019
for route in routes_to_check:
2120
uri = route.uri_template
2221
resource = route.resource
23-
mapping[resource] = uri
22+
mapping[resource] = {
23+
"uri": uri,
24+
"methods": {}
25+
}
26+
27+
if route.method_map:
28+
for method_name, method_handler in route.method_map.items():
29+
if method_handler.__dict__.get("__module__") == "falcon.responders":
30+
continue
31+
mapping[resource]["methods"][method_name.lower()] = method_handler
32+
2433
routes_to_check.extend(route.children)
2534
return mapping
2635

@@ -32,19 +41,17 @@ def path_helper(self, operations, resource, base_path=None, **kwargs):
3241
raise APISpecError("Could not find endpoint for resource {0}".format(resource))
3342

3443
operations.update(yaml_utils.load_operations_from_docstring(resource.__doc__) or {})
35-
path = resource_uri_mapping[resource]
44+
path = resource_uri_mapping[resource]["uri"]
3645

3746
if base_path is not None:
3847
# make sure base_path accept either with or without leading slash
3948
# swagger 2 usually come with leading slash but not in openapi 3.x.x
4049
base_path = '/' + base_path.strip('/')
4150
path = re.sub(base_path, "", path, 1)
4251

43-
for method in falcon.constants.HTTP_METHODS:
44-
http_verb = method.lower()
45-
method_name = "on_" + http_verb
46-
if getattr(resource, method_name, None) is not None:
47-
method = getattr(resource, method_name)
48-
docstring_yaml = yaml_utils.load_yaml_from_docstring(method.__doc__)
49-
operations[http_verb] = docstring_yaml or dict()
52+
methods = resource_uri_mapping[resource]["methods"]
53+
54+
for method_name, method_handler in methods.items():
55+
docstring_yaml = yaml_utils.load_yaml_from_docstring(method_handler.__doc__)
56+
operations[method_name] = docstring_yaml or dict()
5057
return path

tests/falcon_test.py

Lines changed: 56 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
1-
import pytest
2-
31
import falcon
2+
import pytest
43
from apispec import APISpec
4+
from apispec.exceptions import APISpecError
5+
56
from falcon_apispec import FalconPlugin
67

78

@@ -137,3 +138,56 @@ def on_get(self, req, resp):
137138
spec.path(resource=hello_resource, base_path=base_path)
138139

139140
assert spec._paths["/foo/v1"]["get"] == expected
141+
142+
def test_path_with_suffix(self, app, spec_factory):
143+
class HelloResource:
144+
def on_get_hello(self):
145+
"""A greeting endpoint.
146+
---
147+
description: get a greeting
148+
responses:
149+
200:
150+
description: said hi
151+
"""
152+
return "dummy"
153+
154+
def on_get(self):
155+
"""An invalid method.
156+
---
157+
description: this should not pass
158+
responses:
159+
200:
160+
description: said hi
161+
"""
162+
return "invalid"
163+
164+
expected = {
165+
"description": "get a greeting",
166+
"responses": {"200": {"description": "said hi"}},
167+
}
168+
169+
hello_resource_with_suffix = HelloResource()
170+
app.add_route("/hi", hello_resource_with_suffix, suffix="hello")
171+
172+
spec = spec_factory(app)
173+
spec.path(resource=hello_resource_with_suffix)
174+
175+
assert spec._paths["/hi"]["get"] == expected
176+
177+
def test_resource_without_endpoint(self, app, spec_factory):
178+
class HelloResource:
179+
def on_get(self, req, resp):
180+
"""A greeting endpoint.
181+
---
182+
description: get a greeting
183+
responses:
184+
200:
185+
description: said hi
186+
"""
187+
return "dummy"
188+
189+
hello_resource = HelloResource()
190+
spec = spec_factory(app)
191+
192+
with pytest.raises(APISpecError):
193+
spec.path(resource=hello_resource)

0 commit comments

Comments
 (0)