As the codebase grew, Batman wanted to have a way to organise the code. Robyn told him that he had the super power to organise the code in a better way. He told him about the concept of views and subrouters.

Views

To organise your code in a better way - either to group by responsibility or for code splitting, you can use views.

A view, simply is a function with a collection of other closures. e.g.

Request

GET
/hello_world
def sample_view():
  def get():
      return "Hello, world!"

  def post(request):
      body = request.body
      return Response({"status_code": 200, "description": body, "headers": {}})

The above view contains two closures for the get and the post request.

You can serve views in two ways:

Using an @app.view decorator.

Request

GET
/hello_world
@app.view("/sync/view/decorator")
def sync_decorator_view():
 def get():
     return "Hello, world!"

 def post(request):
     body = request.body
     return body

Using the app.add_view method.

Request

GET
/hello_world
  from .views import sample_view

  ...
  ...

  app.add_view("/", sample_view)

Subrouters

Batman can create subrouters in Robyn. This is useful when you want to group routes together.

Subrouters can be used for both normal routes and web sockets. They are basically a mini version of the main router and can be used in the same way.

The only thing to remember is that you need to add the subrouter to the main router.

Request

GET
/hello_world
from robyn import Robyn, SubRouter

app = Robyn(__file__)

sub_router = SubRouter("/sub_router")

@sub_router.get("/hello")
def hello():
    return "Hello, world"

web_socket = SubRouter("/web_socket")

@web_socket.message()
async def hello():
    return "Hello, world"

app.include_router(sub_router)

Authentication on Subrouters

Batman asked Robyn how to secure his routes. Robyn explained that authentication can be added to subrouters in three ways, giving developers flexibility to decide the scope and precedence of the authentication.

Important: If any of these methods are used, the authentication for the endpoint is set to False unless explicitly overridden.

1. Authentication at the Endpoint Level

Authentication can be applied directly to a specific endpoint using the decorator for that endpoint. This method has the highest precedence, meaning it overrides any authentication settings defined at the router or subrouter level.

Request

GET
/secured , /unsecured
from robyn import Robyn, SubRouter

app = Robyn(__file__)

sub_router = SubRouter("/auth_example")

@sub_router.get("/secured", auth_required=True)
def secured(request):
    return "This endpoint is secured with authentication!"

@sub_router.get("/unsecured", auth_required=False)
def unsecured(request):
    return "This endpoint does not require authentication!"

app.include_router(sub_router)

2. Authentication via include_router

When including a subrouter into the main router, you can specify an authentication flag. This setting applies to all endpoints in the subrouter unless overridden at the endpoint level.

Request

GET
/default_secured
from robyn import Robyn, SubRouter

app = Robyn(__file__)

sub_router = SubRouter("/auth_example")

@sub_router.get("/default_secured")
def default_secured(request):
    return "Authentication is set by include_router!"

app.include_router(sub_router, auth_required=True)

3. Authentication at SubRouter Instantiation

Finally, you can define authentication at the time of the SubRouter instantiation. This acts as the default authentication setting for all endpoints in the subrouter unless overridden by the endpoint decorator or during inclusion into the main router.

Request

GET
/inherited_auth
from robyn import Robyn, SubRouter

app = Robyn(__file__)

sub_router = SubRouter("/auth_example", auth_required=True)

@sub_router.get("/inherited_auth")
def inherited_auth(request):
    return "Authentication is inherited from the SubRouter!"

app.include_router(sub_router)

Precedence Rules

Authentication precedence in Robyn follows this order:

  1. Endpoint-level decorator: If an endpoint explicitly sets auth_required=True or auth_required=False, this takes priority.
  2. include_router method: The auth_required parameter in app.include_router applies to all endpoints in the included subrouter unless overridden.
  3. SubRouter instantiation: The auth_required setting during SubRouter creation acts as the default for all its endpoints unless overridden at the endpoint or include_router level.

What's next?

Now, that Batman knows how to organise his code, he wants to know how to add dependencies to his code. Robyn tells him that he can add dependencies at the global level, router level and the view level.