Source code for eynnyd.routes_builder

import inspect

from eynnyd.internal.routing.route_tree_builder import RouteTeeBuilder
from eynnyd.exceptions import DuplicateHandlerRoutesException, RouteBuildException, NonCallableInterceptor, \
    NonCallableHandler, CallbackIncorrectNumberOfParametersException
from eynnyd.internal.utils.uri_components_converter import URIComponentsConverter


[docs]class RoutesBuilder: """ A builder for registering request interceptors, handlers, and response interceptors. """
[docs] def __init__(self): self._route_tree_builder = RouteTeeBuilder()
[docs] def add_request_interceptor(self, uri_path, interceptor): """ Adds a request interceptor to be run (before handler execution) given a uri path for when to execute it :param uri_path: The path dictating what requests this interceptor is run against :param interceptor: A function which takes a request parameter and returns a request :return: This builder to allow fluent design """ if not hasattr(interceptor, '__call__'): raise NonCallableInterceptor( "Request Interceptor for path {u} is not callable.".format(u=uri_path)) if 1 != len(inspect.signature(interceptor).parameters): raise CallbackIncorrectNumberOfParametersException( "Request Interceptor {n} for path {u} does not take exactly 1 argument (the request)" .format(u=uri_path, n=interceptor.__name__)) components = URIComponentsConverter.from_uri(uri_path) RoutesBuilder._validate_path_has_unique_parameter_names_or_raise(components) self._route_tree_builder.add_request_interceptor(components, interceptor) return self
[docs] def add_response_interceptor(self, uri_path, interceptor): """ Adds a response interceptor to be run (after handler execution) given a uri path for when to execute it :param uri_path: The path dictating what requests this interceptor is run against :param interceptor: A function which takes a request and a response and returns a response :return: This builder to allow for fluent design """ if not hasattr(interceptor, '__call__'): raise NonCallableInterceptor( "Response Interceptor for path {u} is not callable.".format(u=uri_path)) if 2 != len(inspect.signature(interceptor).parameters): raise CallbackIncorrectNumberOfParametersException( "Response Interceptor {n} for path {u} does not take exactly 2 argument (the request and response)" .format(u=uri_path, n=interceptor.__name__)) components = URIComponentsConverter.from_uri(uri_path) RoutesBuilder._validate_path_has_unique_parameter_names_or_raise(components) self._route_tree_builder.add_response_interceptor(components, interceptor) return self
[docs] def add_handler(self, http_method, uri_path, handler): """ Adds a handler to be run (after request interceptors and before response interceptors) given a http method and uri path for when to execute it :param http_method: the method to match to execute this handler against a request :param uri_path: The path dictating what requests this handler is run against :param handler: A function taking a request and returning a response :return: This handler to allow for fluent design """ if not hasattr(handler, '__call__'): raise NonCallableHandler( "Handler for method {m} on path {u} is not callable.".format(m=http_method, u=uri_path)) if 1 != len(inspect.signature(handler).parameters): raise CallbackIncorrectNumberOfParametersException( "Handler {n} for method {m} on path {u} does not take exactly 1 argument (the request)" .format(u=uri_path, n=handler.__name__, m=http_method)) components = URIComponentsConverter.from_uri(uri_path) RoutesBuilder._validate_path_has_unique_parameter_names_or_raise(components) try: self._route_tree_builder.add_handler(http_method, components, handler) except DuplicateHandlerRoutesException as e: raise RouteBuildException( "Error while trying to add handler to route {u}, method: {m}".format(u=uri_path, m=http_method), e) return self
[docs] def build(self): """ Builds out the route tree for processing requests into responses. :return: The route tree for usage in the Eynnyd WebAppBuilder """ return self._route_tree_builder.build()
@staticmethod def _validate_path_has_unique_parameter_names_or_raise(uri_components): path_parameter_names = set() for path_component in uri_components: if path_component in path_parameter_names: raise RouteBuildException("Multiple uses of same path parameter name in uri: {u}".format(u="/" + "/".join(uri_components))) if path_component.startswith("{") and path_component.endswith("}"): path_parameter_names.add(path_component)