This decorator defines custom route for both class and methods in the view.
        It behaves the same way as Flask's @app.route

        on class:
            It takes the following args
                - rule: the root route of the endpoint
                - decorators: a list of decorators to run on each method

        on methods:
            along with the rule, it takes kwargs
                - endpoint
                - defaults
                - ...

        :param rule:
        :param kwargs:
        :return:

def route(cls, rule=None, **kwargs):
        """
        This decorator defines custom route for both class and methods in the view.
        It behaves the same way as Flask's @app.route

        on class:
            It takes the following args
                - rule: the root route of the endpoint
                - decorators: a list of decorators to run on each method

        on methods:
            along with the rule, it takes kwargs
                - endpoint
                - defaults
                - ...

        :param rule:
        :param kwargs:
        :return:
        """

        _restricted_keys = ["route", "decorators"]

        def decorator(f):
            if inspect.isclass(f):
                kwargs.setdefault("route", rule)
                kwargs["decorators"] = kwargs.get("decorators", []) + f.decorators
                setattr(f, "_route_extends__", kwargs)
                setattr(f, "base_route", kwargs.get("route"))
                setattr(f, "decorators", kwargs.get("decorators", []))
            else:
                if not rule:
                    raise ValueError("'rule' is missing in @route ")

                for k in _restricted_keys:
                    if k in kwargs:
                        del kwargs[k]

                Mocha._bind_route_rule_cache(f, rule=rule, **kwargs)
            return f

        return decorator