feat(api): set_default_route as a catch-all route
A default route which is triggered when no route is found for a request. The change simplifies implementing a proxy-like app.
This commit is contained in:
@@ -37,7 +37,8 @@ class API(object):
|
||||
|
||||
"""
|
||||
|
||||
__slots__ = ('_after', '_before', '_media_type', '_routes')
|
||||
__slots__ = ('_after', '_before', '_media_type', '_routes',
|
||||
'_default_route')
|
||||
|
||||
def __init__(self, media_type=DEFAULT_MEDIA_TYPE, before=None, after=None):
|
||||
"""Initialize a new Falcon API instances
|
||||
@@ -57,6 +58,7 @@ class API(object):
|
||||
"""
|
||||
|
||||
self._routes = []
|
||||
self._default_route = None
|
||||
self._media_type = media_type
|
||||
|
||||
self._before = helpers.prepare_global_hooks(before)
|
||||
@@ -212,6 +214,21 @@ class API(object):
|
||||
# adds (will cause the last one to win).
|
||||
self._routes.insert(0, (path_template, method_map, na_responder))
|
||||
|
||||
def set_default_route(self, default_resource):
|
||||
"""Route all the unrouted requests to a default resource
|
||||
|
||||
Args:
|
||||
default_resource: Object which works like an HTTP/REST resource.
|
||||
Falcon will pass "GET" requests to on_get, "PUT" requests to
|
||||
on_put, etc. If you want to exclude some HTTP method from the
|
||||
default routing, just simply don't define the corresponding
|
||||
request handlers.
|
||||
|
||||
"""
|
||||
|
||||
self._default_route = helpers.create_http_method_map(
|
||||
default_resource, set(), self._before, self._after)
|
||||
|
||||
#----------------------------------------------------------------------------
|
||||
# Helpers
|
||||
#----------------------------------------------------------------------------
|
||||
@@ -242,8 +259,18 @@ class API(object):
|
||||
|
||||
break
|
||||
else:
|
||||
responder = falcon.responders.path_not_found
|
||||
params = {}
|
||||
na_responder = falcon.responders.create_method_not_allowed([])
|
||||
|
||||
if self._default_route is not None:
|
||||
method_map, na_responder = self._default_route
|
||||
|
||||
try:
|
||||
responder = method_map[method]
|
||||
except KeyError:
|
||||
responder = falcon.responders.bad_request
|
||||
|
||||
else:
|
||||
responder = falcon.responders.path_not_found
|
||||
na_responder = falcon.responders.create_method_not_allowed([])
|
||||
|
||||
return (responder, params, na_responder)
|
||||
|
||||
57
falcon/tests/test_default_routing.py
Normal file
57
falcon/tests/test_default_routing.py
Normal file
@@ -0,0 +1,57 @@
|
||||
from testtools.matchers import Contains
|
||||
|
||||
import falcon
|
||||
import falcon.testing as testing
|
||||
|
||||
|
||||
class HumanResource(object):
|
||||
def on_delete(self, req, resp, name):
|
||||
resp.status = falcon.HTTP_204
|
||||
|
||||
def on_get(self, req, resp, name):
|
||||
resp.status = falcon.HTTP_402
|
||||
|
||||
|
||||
class UndeadResource(object):
|
||||
def on_get(self, req, resp):
|
||||
resp.status = falcon.HTTP_200
|
||||
|
||||
|
||||
class TestDefaultRouting(testing.TestBase):
|
||||
|
||||
def before(self):
|
||||
self.default_resource = UndeadResource()
|
||||
self.resource = HumanResource()
|
||||
|
||||
def test_default_only(self):
|
||||
self.api.set_default_route(self.default_resource)
|
||||
|
||||
self.simulate_request('/')
|
||||
self.assertEquals(self.srmock.status, falcon.HTTP_200)
|
||||
|
||||
self.simulate_request('/any')
|
||||
self.assertEquals(self.srmock.status, falcon.HTTP_200)
|
||||
|
||||
def test_routing_prioritise(self):
|
||||
self.api.set_default_route(self.default_resource)
|
||||
self.api.add_route('/people/{name}', self.resource)
|
||||
|
||||
self.simulate_request('/people/asuka')
|
||||
self.assertEquals(self.srmock.status, falcon.HTTP_402)
|
||||
|
||||
self.simulate_request('/person/asuka')
|
||||
self.assertEquals(self.srmock.status, falcon.HTTP_200)
|
||||
|
||||
self.simulate_request('/people/asuka', method='DELETE')
|
||||
self.assertEquals(self.srmock.status, falcon.HTTP_204)
|
||||
|
||||
self.simulate_request('/person/asuka', method='DELETE')
|
||||
self.assertEquals(self.srmock.status, falcon.HTTP_405)
|
||||
|
||||
headers = self.srmock.headers
|
||||
allow_header = ('Allow', 'GET, OPTIONS')
|
||||
|
||||
self.assertThat(headers, Contains(allow_header))
|
||||
|
||||
self.simulate_request('/person/asuka', method=self.getUniqueString())
|
||||
self.assertEquals(self.srmock.status, falcon.HTTP_400)
|
||||
Reference in New Issue
Block a user