docs: def route(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 = ["extends", "route", "decorators"]
      def decorator(f):
          if inspect.isclass(f):
              extends = kwargs.pop("extends", None)
              if extends and hasattr(extends, self.view_key):
                  for k, v in getattr(extends, self.view_key).items():
                      kwargs.setdefault(k, v)
  
              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]
  
              # Put the rule cache on the method itself instead of globally
              if not hasattr(f, '_rule_cache') or f._rule_cache is None:
                  f._rule_cache = {f.__name__: [(rule, kwargs)]}
              elif not f.__name__ in f._rule_cache:
                  f._rule_cache[f.__name__] = [(rule, kwargs)]
              else:
                  f._rule_cache[f.__name__].append((rule, kwargs))
          return f
  
      return decorator