HTTP Session

HTTP sessions are a convenient way to store user data between requests. In most cases they are backed by a persistent store where their data is stored and can be accessed across requests.

Expanse provides by default a few session stores that can be used out of the box, like databases, files or in-memory stores. They are all exposed through a common interface, so you can easily switch between them when needed.

Configuration

The settings related to the session are stored in the config/session.py application configuration file. By default, it's configured to use the database store.

The store setting defines which store the session will be used to store its data. The available stores are:

  • file: store the session data in files.
  • database: store the session data in a relational database table.
  • dict: store the session data in memory.
  • null: do not store the session data. This can be used to disable the session feature.

The dict store is only recommended for testing purposes, as it will store the session data in memory and will be lost when the application is restarted.

Database

When using the database store, you must have a dedicated table to store the session data. This will typically be the sessions table that will be created automatically when you first set up your Expanse application. However, if you do not have the table already you can add a database migration to create it using the make session-table command.

./beam make session-table
./beam db migrate

You can configure the database connection used by the session store by using the SESSION_STORES__DATABASE__CONNECTION environment variable.

SESSION_STORES__DATABASE__CONNECTION=my-connection

The connection used must match one of the configured database connections.

The database store requires configuring the database to be compatible with both synchronous and asynchronous implementations of the backend used by the configured connection.

This mostly means that you will need to install the necessary asynchronous DBAPI packages: for instance if you use an SQLite database, you will need to install the aiosqlite package.

Using the session

The session can be retrieved from the current Request instance.

from expanse.http.request import Request
from expanse.http.response import Response


class MyController:

    async def index(self, request: Request) -> Response:
        session = request.session
        value = session["key"]

        ...

Retrieving data from the session

The session behaves like a dictionary, so retrieving data can be done through standard key access.

from expanse.http.request import Request
from expanse.http.response import Response


class MyController:

    async def index(self, request: Request) -> Response:
        session = request.session
        value = session["key"]

        ...

Like the application configuration, the session support dot notation to access nested data stored in it.

You may also use the get() method to retrieve a value from the session, providing a default value to return if the key does not exist.

from expanse.http.request import Request
from expanse.http.response import Response


class MyController:

    async def index(self, request: Request) -> Response:
        session = request.session
        value = session.get("key", "default")

        ...

If you need to retrieve all the data stored in the session, you can use the all() method.

data = request.session.all()

You may also check if a key exists in the session using the has() method or by using a more standard key in session statement.

if "key" in request.session:
    ...

if request.session.has("key"):
    ...

The pop() method may be used to retrieve a value from the session and remove it at the same time.

value = request.session.pop("key", "default")

Storing data in the session

You may store data in the session by using the set() method or by using a dict-like approach.

request.session["key"] = "value"
request.session.set("key", "value")

If you wish to append values to an existing key that holds a list, you may use the append() method.

request.session.append("article.tags", "value")

Flashing data to the session

Flashing data is a way to store data in the session that will only be available for the next request. This is achieved by using the flash() method. This will make the data available immediately as well as in the next request. After that the data will automatically be discarded. This is useful for displaying messages to the user after a form submission for instance.

request.session.flash("status", "Successfully saved the article.")

If you need to keep the data for an additional request, you may use the reflash() method. If only some of the data should be kept, you can specify it via the only keyword argument.

request.session.reflash()
request.session.reflash(only=["status"])

Removing data from the session

You may remove data from the session by using the remove() method or by using the del statement.

del request.session["key"]
request.session.remove("key")

Regenerating the session

Regenerating the session will create a new session ID and keep the existing data. This would typically be done when a user authenticates to prevent session fixation attacks.

request.session.regenerate()

If, instead, you want to regenerate the session ID and clear all the data, you may use the invalidate() method.

request.session.invalidate()