aiohttp subapps: Create Modular Web Applications

Subapps in aiohttp allow you to modularize your application.

In this tutorial, you’ll learn how to create, configure, and use subapps in your aiohttp projects.

 

 

Create and Configure Subapps

To create a subapp, you’ll use the web.Application() function.

Here’s how you can create and configure a simple subapp:

from aiohttp import web
async def handle(request):
    return web.Response(text="Hello from subapp!")
subapp = web.Application()
subapp.add_routes([web.get('/', handle)])
main_app = web.Application()
main_app.add_subapp('/subapp/', subapp)
web.run_app(main_app)

Output:

======== Running on http://0.0.0.0:8080 ========
(Press CTRL+C to quit)

This code creates a subapp with a single route and adds it to the main application.

When you run this, the subapp will be accessible at http://localhost:8080/subapp/.

 

Nested Subapps and Routing

You can nest subapps within other subapps. Here’s an example:

from aiohttp import web
async def handle_admin(request):
    return web.Response(text="Admin panel")

async def handle_users(request):
    return web.Response(text="User management")
admin_app = web.Application()
admin_app.add_routes([
    web.get('/', handle_admin),
    web.get('/users', handle_users)
])
api_app = web.Application()
api_app.add_subapp('/admin/', admin_app)
main_app = web.Application()
main_app.add_subapp('/api/', api_app)
web.run_app(main_app)

This code creates a nested structure where the admin subapp is nested within the api subapp.

You can access the routes at http://localhost:8080/api/admin/ and http://localhost:8080/api/admin/users.

 

Subapp-specific middleware

You can apply middleware specifically to a subapp:

from aiohttp import web

@web.middleware
async def subapp_middleware(request, handler):
    print("Subapp middleware: Before request")
    response = await handler(request)
    print("Subapp middleware: After request")
    return response
async def handle(request):
    return web.Response(text="Hello from subapp!")
subapp = web.Application(middlewares=[subapp_middleware])
subapp.add_routes([web.get('/', handle)])
main_app = web.Application()
main_app.add_subapp('/subapp/', subapp)
web.run_app(main_app)

Output:

Subapp middleware: Before request
Subapp middleware: After request

This middleware will only be executed for requests to the subapp.

 

Interaction between Main App and Subapps

You can access the main app from within a subapp using the app['__main_app__'] attribute.

Here’s an example:

from aiohttp import web
async def handle_main(request):
    return web.Response(text="Main app")
async def handle_sub(request):
    main_app = request.app['__main_app__']
    return web.Response(text=f"Subapp, main app routes: {list(main_app.router.routes())}")
main_app = web.Application()
main_app.add_routes([web.get('/', handle_main)])
subapp = web.Application()
subapp.add_routes([web.get('/', handle_sub)])
main_app.add_subapp('/sub/', subapp)
web.run_app(main_app)

This code allows the subapp to access information about the main app’s routes.

 

Share Resources

You can share resources by setting them on the main app and accessing them from subapps:

from aiohttp import web
async def init_db():
    return {"users": ["Alice", "Bob"]}
async def handle_main(request):
    db = request.app['db']
    return web.Response(text=f"Main app users: {db['users']}")
async def handle_sub(request):
    db = request.app['__main_app__']['db']
    return web.Response(text=f"Subapp users: {db['users']}")
async def init_app():
    app = web.Application()
    app['db'] = await init_db()
    app.add_routes([web.get('/', handle_main)])
    subapp = web.Application()
    subapp.add_routes([web.get('/', handle_sub)])
    app.add_subapp('/sub/', subapp)
    return app
web.run_app(init_app())

This code initializes a database in the main app and shares it with the subapp.

Handle sessions and cookies

You can use aiohttp_session to handle sessions across subapps:

from aiohttp import web
from aiohttp_session import setup, get_session
from aiohttp_session.cookie_storage import EncryptedCookieStorage
async def handle_main(request):
    session = await get_session(request)
    session['visits'] = session.get('visits', 0) + 1
    return web.Response(text=f"Main app visits: {session['visits']}")
async def handle_sub(request):
    session = await get_session(request)
    return web.Response(text=f"Subapp visits: {session['visits']}")
async def init_app():
    app = web.Application()
    setup(app, EncryptedCookieStorage(b'Thirty  two  length  bytes  key.'))
    app.add_routes([web.get('/', handle_main)])
    subapp = web.Application()
    subapp.add_routes([web.get('/', handle_sub)])
    app.add_subapp('/sub/', subapp)
    return app
web.run_app(init_app())

This code sets up session handling for both the main app and subapp.

Manage shared configuration and settings

You can create a shared configuration and pass it to subapps:

from aiohttp import web
async def handle_main(request):
    config = request.app['config']
    return web.Response(text=f"Main app config: {config}")
async def handle_sub(request):
    config = request.app['__main_app__']['config']
    return web.Response(text=f"Subapp config: {config}")
async def init_app():
    config = {
        'debug': True,
        'database_url': 'postgresql://user:pass@localhost/dbname'
    }
    app = web.Application()
    app['config'] = config
    app.add_routes([web.get('/', handle_main)])
    subapp = web.Application()
    subapp.add_routes([web.get('/', handle_sub)])
    app.add_subapp('/sub/', subapp)
    return app
web.run_app(init_app())

This code creates a shared configuration that both the main app and subapp can access.

Pass data between subapps

You can use the main app as a central point to pass data between subapps:

from aiohttp import web
async def handle_sub1(request):
    main_app = request.app['__main_app__']
    main_app['shared_data'] = "Data from subapp1"
    return web.Response(text="Data set in subapp1")
async def handle_sub2(request):
    main_app = request.app['__main_app__']
    shared_data = main_app.get('shared_data', 'No data')
    return web.Response(text=f"Data in subapp2: {shared_data}")
async def init_app():
    app = web.Application()
    subapp1 = web.Application()
    subapp1.add_routes([web.get('/', handle_sub1)])
    app.add_subapp('/sub1/', subapp1)
    subapp2 = web.Application()
    subapp2.add_routes([web.get('/', handle_sub2)])
    app.add_subapp('/sub2/', subapp2)
    return app
web.run_app(init_app())

This code shows how to pass data from one subapp to another using the main app as an intermediary.

Leave a Reply

Your email address will not be published. Required fields are marked *