def add_route(self, uri_template, resource, *args, **kwargs): """Associates a templatized URI path with a resource. Falcon routes incoming requests to resources based on a set of URI templates. If the path requested by the client matches the template for a given route, the request is then passed on to the associated resource for processing. If no route matches the request, control then passes to a default responder that simply raises an instance of :class:`~.HTTPNotFound`. (See also: :ref:`Routing <routing>`) Args: uri_template (str): A templatized URI. Care must be taken to ensure the template does not mask any sink patterns, if any are registered. (See also: :meth:`~.add_sink`) resource (instance): Object which represents a REST resource. Falcon will pass "GET" requests to on_get, "PUT" requests to on_put, etc. If any HTTP methods are not supported by your resource, simply don't define the corresponding request handlers, and Falcon will do the right thing. Note: Any additional args and kwargs not defined above are passed through to the underlying router's ``add_route()`` method. The default router does not expect any additional arguments, but custom routers may take advantage of this feature to receive additional options when setting up routes. """ # NOTE(richardolsson): Doing the validation here means it doesn't have # to be duplicated in every future router implementation. if not isinstance(uri_template, six.string_types): raise TypeError('uri_template is not a string') if not uri_template.startswith('/'): raise ValueError("uri_template must start with '/'") if '//' in uri_template: raise ValueError("uri_template may not contain '//'") method_map = routing.map_http_methods(resource) routing.set_default_responders(method_map) self._router.add_route(uri_template, method_map, resource, *args, **kwargs)
def add_route(self, uri_template, resource, *args, **kwargs): """Associate a templatized URI path with a resource. Falcon routes incoming requests to resources based on a set of URI templates. If the path requested by the client matches the template for a given route, the request is then passed on to the associated resource for processing. If no route matches the request, control then passes to a default responder that simply raises an instance of :class:`~.HTTPNotFound`. (See also: :ref:`Routing <routing>`) Args: uri_template (str): A templatized URI. Care must be taken to ensure the template does not mask any sink patterns, if any are registered. (See also: :meth:`~.add_sink`) resource (instance): Object which represents a REST resource. Falcon will pass "GET" requests to on_get, "PUT" requests to on_put, etc. If any HTTP methods are not supported by your resource, simply don't define the corresponding request handlers, and Falcon will do the right thing. Note: Any additional args and kwargs not defined above are passed through to the underlying router's ``add_route()`` method. The default router does not expect any additional arguments, but custom routers may take advantage of this feature to receive additional options when setting up routes. """ # NOTE(richardolsson): Doing the validation here means it doesn't have # to be duplicated in every future router implementation. if not isinstance(uri_template, six.string_types): raise TypeError('uri_template is not a string') if not uri_template.startswith('/'): raise ValueError("uri_template must start with '/'") if '//' in uri_template: raise ValueError("uri_template may not contain '//'") method_map = routing.map_http_methods(resource) routing.set_default_responders(method_map) self._router.add_route(uri_template, method_map, resource, *args, **kwargs)
def add_route(self, uri_template, resource, custom_map=None, **kwargs): if not isinstance(uri_template, six.string_types): raise TypeError('uri_template is not a string') if not uri_template.startswith('/'): raise ValueError("uri_template must start with '/'") if '//' in uri_template: raise ValueError("uri_template may not contain '//'") method_map = self.map_http_methods(resource, custom_map) routing.set_default_responders(method_map) self._router.add_route(uri_template, method_map, resource, **kwargs)
def __init__(self, file_path='', raw_json='', raw_yaml=''): super().__init__() (self.openapi, self.base_path) = self.__load_spec(file_path, raw_json, raw_yaml) for path, http_methods in self.openapi['paths'].items(): path = self.base_path + path openapi_map = {} for http_method, definition in http_methods.items(): try: ( dest_module, dest_method, dest_class, dest_file, ) = self.__get_destination_info(definition, http_method) except: continue http_method = http_method.upper() class_name = dest_module + dest_class if class_name not in openapi_map: mod_spec = spec_from_file_location(dest_module, dest_file) module = module_from_spec(mod_spec) mod_spec.loader.exec_module(module) Class = getattr(module, dest_class)() openapi_map[class_name] = {} openapi_map[class_name]['class'] = Class openapi_map[class_name]['method_map'] = {} method_map = openapi_map[class_name]['method_map'] Class = openapi_map[class_name]['class'] Method = getattr(Class, dest_method) method_map[http_method] = Method for router_map in openapi_map.values(): Class = router_map['class'] method_map = router_map['method_map'] routing.set_default_responders(method_map) self.add_route(path, method_map, Class)
def add_route(self, uri_template, resource, *args, **kwargs): """Associate a templatized URI path with a resource. Falcon routes incoming requests to resources based on a set of URI templates. If the path requested by the client matches the template for a given route, the request is then passed on to the associated resource for processing. If no route matches the request, control then passes to a default responder that simply raises an instance of :class:`~.HTTPNotFound`. (See also: :ref:`Routing <routing>`) Args: uri_template (str): A templatized URI. Care must be taken to ensure the template does not mask any sink patterns, if any are registered. (See also: :meth:`~.add_sink`) resource (instance): Object which represents a REST resource. Falcon will pass GET requests to ``on_get()``, PUT requests to ``on_put()``, etc. If any HTTP methods are not supported by your resource, simply don't define the corresponding request handlers, and Falcon will do the right thing. Keyword Args: suffix (str): Optional responder name suffix for this route. If a suffix is provided, Falcon will map GET requests to ``on_get_{suffix}()``, POST requests to ``on_post_{suffix}()``, etc. In this way, multiple closely-related routes can be mapped to the same resource. For example, a single resource class can use suffixed responders to distinguish requests for a single item vs. a collection of those same items. Another class might use a suffixed responder to handle a shortlink route in addition to the regular route for the resource. Note: Any additional args and kwargs not defined above are passed through to the underlying router's ``add_route()`` method. The default router does not expect any additional arguments, but custom routers may take advantage of this feature to receive additional options when setting up routes. """ # NOTE(richardolsson): Doing the validation here means it doesn't have # to be duplicated in every future router implementation. if not isinstance(uri_template, six.string_types): raise TypeError('uri_template is not a string') if not uri_template.startswith('/'): raise ValueError("uri_template must start with '/'") if '//' in uri_template: raise ValueError("uri_template may not contain '//'") # NOTE(santeyio): This is a not very nice way to catch the suffix # keyword. In python 3 it can be specified explicitly in the function # definition, e.g. # `add_route(self, uri_template, resource, *args, suffix=None, **kwargs)` # but python 2 won't accept args like this. suffix = kwargs.pop('suffix', None) method_map = routing.map_http_methods(resource, suffix=suffix) routing.set_default_responders(method_map) self._router.add_route(uri_template, method_map, resource, *args, **kwargs)
def find(self, uri, req=None): segments = uri.split(SLASH) # Since the path is always rooted at /, skip the first segment, which # will always be the empty string. segments.pop(0) this_segment = segments.pop(0) resource = self._root context = {} while True: # Plumb the API through to all child resources. api = getattr(resource, 'api', None) # See if any of the resource's child links match the next segment. for name in dir(resource): if name.startswith('__') and name.endswith('__'): continue attribute = getattr(resource, name, MISSING) assert attribute is not MISSING, name matcher = getattr(attribute, '__matcher__', MISSING) if matcher is MISSING: continue result = None if isinstance(matcher, str): # Is the matcher string a regular expression or plain # string? If it starts with a caret, it's a regexp. if matcher.startswith('^'): cre = re.compile(matcher) # Search against the entire remaining path. tmp_segments = segments[:] tmp_segments.insert(0, this_segment) remaining_path = SLASH.join(tmp_segments) mo = cre.match(remaining_path) if mo: result = attribute(context, segments, **mo.groupdict()) elif matcher == this_segment: result = attribute(context, segments) else: # The matcher is a callable. It returns None if it # doesn't match, and if it does, it returns a 3-tuple # containing the positional arguments, the keyword # arguments, and the remaining segments. The attribute is # then called with these arguments. Note that the matcher # wants to see the full remaining path components, which # includes the current hop. tmp_segments = segments[:] tmp_segments.insert(0, this_segment) matcher_result = matcher(tmp_segments) if matcher_result is not None: positional, keyword, segments = matcher_result result = attribute(context, segments, *positional, **keyword) # The attribute could return a 2-tuple giving the resource and # remaining path segments, or it could just return the result. # Of course, if the result is None, then the matcher did not # match. if result is None: continue elif isinstance(result, tuple): resource, segments = result else: resource = result # See if the context set an API and set it on the next # resource in the chain, falling back to the parent resource's # API if there is one. resource.api = context.pop('api', api) # The method could have truncated the remaining segments, # meaning, it's consumed all the path segments, or this is the # last path segment. In that case the resource we're left at # is the responder. if len(segments) == 0: # We're at the end of the path, so the root must be the # responder. method_map = map_http_methods(resource) set_default_responders(method_map) return resource, method_map, context this_segment = segments.pop(0) break else: # None of the attributes matched this path component, so the # response is a 404. return None, None, None
def add_route(self, uri_template, resource, suffix=None, **kwargs): """Associate a templatized URI path with a resource. Falcon routes incoming requests to resources based on a set of URI templates. If the path requested by the client matches the template for a given route, the request is then passed on to the associated resource for processing. If no route matches the request, control then passes to a default responder that simply raises an instance of :class:`~.HTTPNotFound`. (See also: :ref:`Routing <routing>`) Args: uri_template (str): A templatized URI. Care must be taken to ensure the template does not mask any sink patterns, if any are registered. (See also: :meth:`~.add_sink`) resource (instance): Object which represents a REST resource. Falcon will pass GET requests to ``on_get()``, PUT requests to ``on_put()``, etc. If any HTTP methods are not supported by your resource, simply don't define the corresponding request handlers, and Falcon will do the right thing. Keyword Args: suffix (str): Optional responder name suffix for this route. If a suffix is provided, Falcon will map GET requests to ``on_get_{suffix}()``, POST requests to ``on_post_{suffix}()``, etc. In this way, multiple closely-related routes can be mapped to the same resource. For example, a single resource class can use suffixed responders to distinguish requests for a single item vs. a collection of those same items. Another class might use a suffixed responder to handle a shortlink route in addition to the regular route for the resource. Note: Any additional keyword arguments not defined above are passed through to the underlying router's ``add_route()`` method. The default router ignores any additional keyword arguments, but custom routers may take advantage of this feature to receive additional options when setting up routes. Custom routers MUST accept such arguments using the variadic pattern (``**kwargs``), and ignore any keyword arguments that they don't support. """ # NOTE(richardolsson): Doing the validation here means it doesn't have # to be duplicated in every future router implementation. if not isinstance(uri_template, six.string_types): raise TypeError('uri_template is not a string') if not uri_template.startswith('/'): raise ValueError("uri_template must start with '/'") if '//' in uri_template: raise ValueError("uri_template may not contain '//'") method_map = routing.map_http_methods(resource, suffix=suffix) routing.set_default_responders(method_map) self._router.add_route(uri_template, method_map, resource, **kwargs)
def add_route(self, uri_template, resource, *args, **kwargs): """Associate a templatized URI path with a resource. .. note:: this is the Falcon2 ported code with a small customization. Instead of using Falcon2 map_http_methods function, we start using our own customized function. Falcon routes incoming requests to resources based on a set of URI templates. If the path requested by the client matches the template for a given route, the request is then passed on to the associated resource for processing. If no route matches the request, control then passes to a default responder that simply raises an instance of :class:`~.HTTPNotFound`. .. seealso::`Routing <routing>` :param uri_template: A templatized URI. Care must be taken to ensure the template does not mask any sink patterns, if any are registered. :type uri_template: str .. seealso::`~.add_sink` :param resource: Object which represents a REST resource. Falcon will pass "GET" requests to on_get, "PUT" requests to on_put, etc. If any HTTP methods are not supported by your resource, simply don't define the corresponding request handlers, and Falcon will do the right thing. :type resource: instance .. note:: Any additional args and kwargs not defined above are passed through to the underlying router's ``add_route()`` method. The default router does not expect any additional arguments, but custom routers may take advantage of this feature to receive additional options when setting up routes. """ # NOTE(richardolsson): Doing the validation here means it doesn't have # to be duplicated in every future router implementation. if FALCON_VERSION == 2: super().add_route(uri_template, resource, *args, **kwargs) return if not isinstance(uri_template, str): raise TypeError('uri_template is not a string') if not uri_template.startswith('/'): raise ValueError("uri_template must start with '/'") if '//' in uri_template: raise ValueError("uri_template may not contain '//'") method_map = map_http_methods( resource, kwargs.pop("suffix", None), self._suffix_method_caller ) routing.set_default_responders(method_map) self._router.add_route(uri_template, method_map, resource, *args, **kwargs)