Addons#
uapi ships with several useful addons.
Redis Async Sessions#
Note
This addon handles server-side sessions, which are anonymous by default. If you’re looking for login functionality, see uapi.login which builds on top of sessions.
The uapi.sessions.redis.configure_async_sessions()
addon enables the use of cookie sessions using Redis as the session store.
This addon requires the use of an aioredis 1.3 connection pool.
First, configure the addon by giving it your app
instance and optionally overridding parameters:
from aioredis import create_pool
from uapi.sessions.redis import configure_async_sessions
session_store = configure_async_sessions(app, await create_pool(...))
Once configured, handlers may declare a parameter of type uapi.sessions.redis.AsyncSession
.
The session object is a dict[str, str]
subclass, and it needs to have the uapi.sessions.redis.AsyncSession.update_session()
coroutine called to actually store the session.
async def my_session_handler(session: AsyncSession) -> None:
session['my_key'] = 'value'
await session.update_session()
Multiple sessions using multiple cookies can be configured in parallel.
If this is the case, the session_arg_param_name
argument can be used to customize the name of the session parameter being injected.
another_session_store = configure_async_sessions(
app,
redis,
cookie_name="another_session_cookie",
session_arg_param_name="another_session",
)
async def a_different_handler(another_session: AsyncSession) -> None:
session['my_key'] = 'value'
await another_session.update_session()
uapi.login#
The uapi.login.configure_async_login()
addon enables login/logout for uapi apps.
The login addon requires a configured session store. Then, assuming our user IDs are ints:
from uapi.login import configure_async_login
login_manager = configure_async_login(app, int, session_store)
You’ll need a login endpoint:
from uapi.login import AsyncLoginSession
async def login(login_session: AsyncLoginSession) -> Ok[None]:
if login_session.user_id is not None:
# Looks like this session is already associated with a user.
return Ok(None)
# Check credentials, like a password or token
return Ok(None, await login_session.login_and_return(user_id))
Now your app’s handlers can declare the current_user_id
parameter for dependency injection:
async def requires_logged_in_user(current_user_id: int) -> None:
pass
An unauthenticated request will be denied with a Forbidden
response.
A user can be logged out using uapi.login.AsyncLoginManager.logout()
.
async def logout_user() -> None:
await login_manager.logout(user_id)