Application
Description
Application is the core of the web server responsible for handling all incoming requests.
It allows you to register and manage:
- Web handlers (endpoint)
- Middleware
- Sub-applications
- Background tasks
rapidy.Rapidy is an alias for rapidy.web.Application
Application Entities
Endpoint
An endpoint is a final point of a web service that a client application interacts with to perform specific operations or retrieve data, such as /api/user/get-data.
from rapidy.http import get
@get('/')
async def handler() -> dict[str, str]:
return {'hello': 'rapidy'}
For more details on creating an endpoint, see the Handlers section.
Middleware
Middleware allows you to perform actions on a request before and after it is processed by a web handler.
from rapidy.http import middleware, Request, StreamResponse, Header
from rapidy.typedefs import CallNext
TOKEN_REGEXP = '^[Bb]earer (?P<token>[A-Za-z0-9-_=.]*)'
@middleware
async def get_bearer_middleware(
request: Request,
call_next: CallNext,
bearer_token: str = Header(alias='Authorization', pattern=TOKEN_REGEXP),
) -> StreamResponse:
# process token here...
return await call_next(request)
For more details on creating middleware, see the Middlewares section.
Applying middleware for different API versions.
from rapidy import web
from rapidy.typedefs import Handler
routes = web.RouteTableDef()
def get_token_data(token: str) -> ...:
...
def get_session_data(session: str) -> ...:
...
@web.middleware
async def keycloak_auth_middleware(
request: web.Request,
handler: Handler,
bearer_token: str = web.Header(alias='Authorization'),
) -> web.StreamResponse:
try:
parsed_token_data = get_token_data(bearer_token)
except Exception:
return web.HTTPUnauthorized(text='Failed to authenticate with bearer')
return await handler(request)
@web.middleware
async def cookie_session_auth_middleware(
request: web.Request,
handler: Handler,
session: str = web.Cookie(alias='UserSession'),
) -> web.StreamResponse:
try:
parsed_session_data = get_session_data(session)
except Exception:
return web.HTTPUnauthorized(text='Failed to authenticate with session')
return await handler(request)
@routes.get('/get_hello')
async def handler() -> dict[str, str]:
return {'hello': 'rapidy'}
v1_app = web.Application(middlewares=[cookie_session_auth_middleware])
v1_app.add_routes(routes)
v2_app = web.Application(middlewares=[keycloak_auth_middleware])
v2_app.add_routes(routes)
app = web.Application()
app.add_subapp('/v1', v1_app)
app.add_subapp('/v2', v2_app)
Routing
This section demonstrates how to organize groups of web handlers.
Example of bad practice.
It is recommended to use rapidy.http.HTTPRouter or child rapidy.web.Application instead.
HTTPRouter
Using HTTPRouter makes the code more concise and convenient.
from rapidy import Rapidy # <-- rapidy.Rapidy == rapidy.web.Application
from rapidy.http import get, HTTPRouter
@get('/get_hello')
async def handler() -> dict[str, str]:
return {'hello': 'rapidy'}
v1_app = HTTPRouter('/v1', route_handlers=[handler])
rapidy = Rapidy(http_route_handlers=[v1_app])
For more details on HTTPRouter, see the HTTPRouter section.
Sub-application (aiohttp-style)
Creating child Application:
from rapidy import web
routes = web.RouteTableDef()
@routes.get('/get_hello')
async def handler() -> dict[str, str]:
return {'hello': 'rapidy'}
v1_app = web.Application()
v1_app.add_routes(routes)
app = web.Application()
app.add_subapp('/v1', v1_app)
Using child applications in the aiohttp style for new code is not recommended.
Lifespan
Lifespan is a mechanism for managing the lifecycle of background tasks in Rapidy.
It controls tasks that should be executed: before or after the server starts, as well as tasks that should run continuously.
from contextlib import asynccontextmanager
from typing import AsyncGenerator
from rapidy import Rapidy
async def startup() -> None:
print('startup')
async def shutdown() -> None:
print('shutdown')
async def cleanup() -> None:
print('cleanup')
@asynccontextmanager
async def bg_task() -> AsyncGenerator[None, None]:
try:
print('starting background task')
yield
finally:
print('finishing background task')
rapidy = Rapidy(
on_startup=[startup],
on_shutdown=[shutdown],
on_cleanup=[cleanup],
lifespan=[bg_task()],
)
For more details on lifespan, see the Lifespan section.
Application Attributes
Additional Attributes in Rapidy
server_info_in_response
Defines whether to include server information in the Server header.
lifespan
A list of background tasks that start and stop along with the server.
on_startup
A list of tasks executed immediately after the application starts.
on_shutdown
Tasks executed when the server stops.
on_cleanup
Tasks executed after on_shutdown.
http_route_handlers
HTTP routers that can be either individual handlers or groups of HTTPRouter.
DI Attributes (dishka)
Rapidy uses the Dishka library as its dependency injection engine.
Learn more about the DI mechanism and integration details here.
di_container
An external DI container that can be passed to Rapidy.
By default, Rapidy creates and manages its own container. If you pass a container manually, you must manage its lifecycle yourself (startup and shutdown).
Rapidy will not create a new container even if other DI parameters are specified.
Dishka documentation — container.
di_providers
Providers that will be registered in the container.
A provider is an object whose members are used to build dependencies.
This parameter will be ignored if di_container is specified.
Dishka documentation — providers.
di_scopes
The Scope class that the container will use.
This parameter will be ignored if di_container is specified.
Dishka documentation — scopes.
di_context
A dictionary that allows passing additional context into already declared providers.
This parameter will be ignored if di_container is specified.
Dishka documentation — context.
di_lock_factory
A factory for creating locks that the container will use.
This parameter will be ignored if di_container is specified.
Dishka documentation — lock_factory.
import threading
container = make_container(provider, lock_factory=threading.Lock):
with container(lock_factory=threading.Lock) as nested_container:
...
import asyncio
container = make_async_container(provider, lock_factory=asyncio.Lock)
async with container(lock_factory=asyncio.Lock) as nested_container:
...
di_skip_validation
A flag indicating whether to skip validation for providers of the same type.
This parameter will be ignored if di_container is specified.
Dishka documentation — skip_validation.
from rapidy.depends import make_container, Provider, provide, Scope
class MainProvider(Provider):
# default component is used here
@provide(scope=Scope.APP)
def foo(self, a: int) -> float:
return a/10
class AdditionalProvider(Provider):
component = "X"
@provide(scope=Scope.APP)
def foo(self) -> int:
return 1
# we will get error immediately during container creation, skip validation for demo needs
container = make_container(MainProvider(), AdditionalProvider(), skip_validation=True)
# retrieve from component "X"
container.get(int, component="X") # value 1 would be returned
# retrieve from default component
container.get(float) # raises NoFactoryError because int is in another component
di_start_scope
A parameter specifying the initial Scope.
This parameter will be ignored if di_container is specified.
Dishka documentation — start_scope.
di_validation_settings
Configuration for overriding the container's validation settings.
This parameter will be ignored if di_container is specified.
Dishka documentation — alias.
Dishka documentation — from_context.
Dishka documentation — provide.
aiohttp Attributes
middlewares
A list of middleware applied to all handlers, including child applications.
client_max_size
Maximum request size in bytes.
logger
Logger for receiving logs from Application.
Running the Application
Simple Run
Copy the following code into main.py.
from rapidy import Rapidy, run_app
from rapidy.http import post
@post('/')
async def handler() -> dict[str, str]:
return {'hello': 'rapidy'}
rapidy = Rapidy()
rapidy.add_http_router(handler)
if __name__ == '__main__':
run_app(rapidy)
WSGI Run (Gunicorn)
Install gunicorn:
main.py:
from rapidy import Rapidy
from rapidy.http import post
@post('/')
async def handler() -> dict[str, str]:
return {'hello': 'rapidy'}
rapidy = Rapidy()
rapidy.add_http_router(handler)
The gunicorn main:app command refers to:
main: themain.pyfile (Python module).rapidy: the object created insidemain.pyin the linerapidy = Rapidy().--reload: restarts the server when the code changes. Use only for development.