Skip to content

Commit

Permalink
Server-side sessions and unified session backends (#630)
Browse files Browse the repository at this point in the history
* Initial draft for server-side sessions and unified session-middleware interface

* Implement SessionMiddleware with backends, basic server-session backends. Integrate backends with existing tests

* Initial draft for server-side sessions and unified session-middleware interface

* Implement SessionMiddleware with backends, basic server-session backends. Integrate backends with existing tests

* Initial draft for server-side sessions and unified session-middleware interface

* Implement SessionMiddleware with backends, basic server-session backends. Integrate backends with existing tests

* v1.30.0

* docs: add mookrs as a contributor for doc (#637)

* docs: update README.md [skip ci]

* docs: update .all-contributorsrc [skip ci]

Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>

* Minor code cleanup

* Improve SQLAlchemy backend, support sync/async

* Improved backwards compatibility, typing and tests

* Simplify session backend configuration

* Add expiry mechanism to FakeAsyncMemcached, improve typing

* Test all session backends

* Remove a merge artifact

* Remove identity-source support for now

* Add docstrings to session backends, improve typing

* Minor styling fixes

* Add reference docs for session middleware

* Fix type annotations

* Initial draft for server-side sessions and unified session-middleware interface

* Implement SessionMiddleware with backends, basic server-session backends. Integrate backends with existing tests

* Initial draft for server-side sessions and unified session-middleware interface

* Implement SessionMiddleware with backends, basic server-session backends. Integrate backends with existing tests

* Initial draft for server-side sessions and unified session-middleware interface

* Implement SessionMiddleware with backends, basic server-session backends. Integrate backends with existing tests

* v1.30.0

* docs: add mookrs as a contributor for doc (#637)

* docs: update README.md [skip ci]

* docs: update .all-contributorsrc [skip ci]

Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>

* Minor code cleanup

* Improved backwards compatibility, typing and tests

* Test all session backends

* Remove a merge artifact

* session docs draft

* Disable MD052 in markdownlint

MD052 messes with mkdocs material's code highlighting

* Add aiomcache and redis types to pylint dependencies

* Remove `backend` property from BaseBackendConfig.

This proved difficult to type correctly, and I was hitting python/mypy#12113 (or some variety), so I removed it for now

* Add / update reference and usage documentation + some docstrings for session middleware

* Remove unused imports

* Move session backend config to the top

* Some minor documentation adjustments

* Improve docstrings

Add missing args and returns, add missing docstrings

* Rename SessionBackend > BaseSessionBackend

* Add _sync suffix to private synchronous methods

* Move all type variables to top of the file

* Use explicit "import from" consistently

* Make FileStorageMetadataWrapper a NamedTuple

* Add `make_filename` option to FileBackendConfig

* Move fake_memcached.FakeAsyncMemcached to tests/mocks.py

* Implement MemoryBackend using SimpleCacheBackend

* Add __slots__ for session middleware

* Add support for all session backends to TestClient

* Update starlite/middleware/session/sqlalchemy_backend.py

Co-authored-by: Na'aman Hirschfeld <nhirschfeld@gmail.com>

* Update starlite/testing/test_client/client.py

Co-authored-by: Na'aman Hirschfeld <nhirschfeld@gmail.com>

* Update starlite/middleware/session/sqlalchemy_backend.py

Co-authored-by: Na'aman Hirschfeld <nhirschfeld@gmail.com>

* Update starlite/middleware/session/memcached_backend.py

Co-authored-by: Na'aman Hirschfeld <nhirschfeld@gmail.com>

* Update starlite/middleware/session/sqlalchemy_backend.py

Co-authored-by: Na'aman Hirschfeld <nhirschfeld@gmail.com>

* Update starlite/middleware/session/cookie_backend.py

Co-authored-by: Na'aman Hirschfeld <nhirschfeld@gmail.com>

* Update starlite/middleware/session/base.py

Co-authored-by: Na'aman Hirschfeld <nhirschfeld@gmail.com>

* Update starlite/testing/test_client/client.py

Co-authored-by: Na'aman Hirschfeld <nhirschfeld@gmail.com>

* Update starlite/testing/test_client/client.py

Co-authored-by: Na'aman Hirschfeld <nhirschfeld@gmail.com>

* Implement support for session backends in TestClient

* Make sqlalchemy session examples "run as-is"

* Fix lower-casing of header values. (#693)

A bug was introduced as part of #626, that would lower case header values

* Remove types-redis

* Add middleware bypassing to SessionMiddleware

Co-authored-by: Peter Schutt <peter.github@proton.me>
Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
Co-authored-by: Na'aman Hirschfeld <nhirschfeld@gmail.com>
  • Loading branch information
4 people committed Oct 27, 2022
1 parent 9d9bd6d commit 55d7389
Show file tree
Hide file tree
Showing 58 changed files with 3,010 additions and 766 deletions.
10 changes: 9 additions & 1 deletion .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,13 @@ repos:
hooks:
- id: markdownlint
args:
[--disable=MD013, --disable=MD033, --disable=MD050, --disable=MD052]
[
--disable=MD013,
--disable=MD033,
--disable=MD046,
--disable=MD050,
--disable=MD052,
]
- repo: https://github.com/PyCQA/docformatter
rev: v1.5.0
hooks:
Expand Down Expand Up @@ -167,6 +173,8 @@ repos:
starlite_multipart,
structlog,
tortoise_orm,
aiomcache,
redis,
]
- repo: https://github.com/pre-commit/mirrors-mypy
rev: "v0.982"
Expand Down
5 changes: 5 additions & 0 deletions docs/css/typo.css
Original file line number Diff line number Diff line change
Expand Up @@ -97,3 +97,8 @@ article center > p {
border-top: none;
}
}


dt {
font-weight: bolder;
}
22 changes: 0 additions & 22 deletions docs/reference/middleware/4-session-middleware.md

This file was deleted.

6 changes: 6 additions & 0 deletions docs/reference/middleware/session-middleware/0-middleware.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# Middleware

::: starlite.middleware.session.SessionMiddleware
options:
members:
- __init__
40 changes: 40 additions & 0 deletions docs/reference/middleware/session-middleware/1-base-backend.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# Base backend

::: starlite.middleware.session.base.BaseBackendConfig
options:
members:
- key
- max_age
- scopes
- path
- domain
- secure
- httponly
- samesite
- middleware

::: starlite.middleware.session.base.ServerSideSessionConfig
options:
members:
- session_id_bytes

::: starlite.middleware.session.base.BaseSessionBackend
options:
members:
- __init__
- serialise_data
- deserialise_data
- store_in_message
- load_from_connection

::: starlite.middleware.session.base.ServerSideBackend
options:
members:
- __init__
- store_in_message
- load_from_connection
- get
- set
- delete
- delete_all
- generate_session_id
16 changes: 16 additions & 0 deletions docs/reference/middleware/session-middleware/2-cookie-backend.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# Cookie Backend

::: starlite.middleware.session.cookie_backend.CookieBackendConfig
options:
members:
- secret

::: starlite.middleware.session.cookie_backend.CookieBackend
options:
members:
- __init__
- dump_data
- load_data
- get_cookie_keys
- store_in_message
- load_from_connection
17 changes: 17 additions & 0 deletions docs/reference/middleware/session-middleware/3-file-backend.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# File backend

::: starlite.middleware.session.file_backend.FileBackendConfig
options:
members:
- storage_path
- make_filename

::: starlite.middleware.session.file_backend.FileBackend
options:
members:
- __init__
- get
- set
- delete
- delete_all
- delete_expired
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# Memcached backend

::: starlite.middleware.session.memcached_backend.MemcachedBackendConfig
options:
members:
- memcached

::: starlite.middleware.session.memcached_backend.MemcachedBackend
options:
members:
- __init__
- get
- set
- delete
- delete_all
10 changes: 10 additions & 0 deletions docs/reference/middleware/session-middleware/5-memory-backend.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# Memory backend

::: starlite.middleware.session.memory_backend.MemoryBackend
options:
members:
- __init__
- get
- set
- delete
- delete_all
15 changes: 15 additions & 0 deletions docs/reference/middleware/session-middleware/6-redis-backend.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# Redis backend

::: starlite.middleware.session.redis_backend.RedisBackendConfig
options:
members:
- redis

::: starlite.middleware.session.redis_backend.RedisBackend
options:
members:
- __init__
- get
- set
- delete
- delete_all
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
# SQLAlchemy backends

::: starlite.middleware.session.sqlalchemy_backend.SQLAlchemyBackendConfig
options:
members:
- models
- plugin

::: starlite.middleware.session.sqlalchemy_backend.BaseSQLAlchemyBackend
options:
members:
- __init__
- delete_expired

::: starlite.middleware.session.sqlalchemy_backend.SQLAlchemyBackend
options:
members:
- __init__
- get
- set
- delete
- delete_all
- delete_expired

::: starlite.middleware.session.sqlalchemy_backend.AsyncSQLAlchemyBackend
options:
members:
- __init__
- get
- set
- delete
- delete_all
- delete_expired

::: starlite.middleware.session.sqlalchemy_backend.create_session_model

::: starlite.middleware.session.sqlalchemy_backend.register_session_model

::: starlite.middleware.session.sqlalchemy_backend.SessionModelMixin
options:
members:
- session_id
- data
- expires
- expired

::: starlite.middleware.session.sqlalchemy_backend.SessionModel
options:
members:
- __tablename__
- id
4 changes: 2 additions & 2 deletions docs/reference/testing/0-test-client.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@
- delete
- options
- head
- create_session_cookies
- get_session_from_cookies
- set_session_data
- get_session_data

::: starlite.testing.test_client.WebSocketTestSession
options:
Expand Down
88 changes: 11 additions & 77 deletions docs/usage/14-testing.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,92 +71,26 @@ def test_health_check(test_client: TestClient):
assert response.text == "healthy"
```

### Create Session Cookies
### Using sessions

If you are using [**Session Middleware**](./7-middleware/3-builtin-middlewares/5-session-middleware/) for session persistence
across requests then your route handlers may expect preloaded session when mocking the request. To mock request with raw session
cookies, you can use [`TestClient.create_session_cookies`][starlite.testing.test_client.TestClient.create_session_cookies]. The
session middleware will then load the session data from the session cookies that you provide.
across requests, then you might want to inject or inspect session data outside a request. For this, `TestClient` provides
two methods:

To use the same session configuration that you have used in your app for session middleware, import
[`SessionCookieConfig`][starlite.middleware.session.SessionCookieConfig] instance from your app.
- [set_session_data][starlite.testing.test_client.TestClient.set_session_data]
- [set_session_data][starlite.testing.test_client.TestClient.get_session_data]

```python title="tests/test_route_handlers.py"
import pytest
from starlite.testing import TestClient

from my_app.main import app, session_cookie_config_instance


class TestClass:

@pytest.fixture()
def test_client(self) -> TestClient:
with TestClient(app=app, base_url="example.com", session_config=session_cookie_config_instance) as client:
yield client
!!! important
The **Session Middleware** must be enabled in Starlite app provided to the TestClient to use sessions.

def test_something(self, test_client: TestClient) -> None:
cookies = test_client.create_session_cookies(session_data={"user": "test_user"})
# Set raw session cookies to the "cookies" attribute of test_client instance.
test_client.cookies = cookies
test_client.get(url="/my_route")
```py title="Setting session data"
--8<-- "examples/testing/set_session_data.py"
```

#### Set Cookies With Domain

If you have set `domain` in `SessionCookieConfig` instance, the `domain` argument here must take the same parameter. The
domain must follow the format specified in RFC 2109, that is, setting a cookie domain without a preceding dot, like,
*example.com* instead of *.example.com*, is invalid and will not set the cookie.

If you have not set `domain` in `SessionCookieConfig`, the `domain` argument here must match with the domain name in the
`base_url` argument of `TestClient` instance. See the example below.

```python
def test_something(test_client) -> None:
cookies = test_client.create_session_cookies(session_data={"user": "test_user"})
# Get domain
domain = test_client.session.config.domain or test_client.base_url.host
# Set cookies
for key, value in cookies.items():
test_client.cookies.set(key=key, value=value, domain=domain)
test_client.get(url="/my_route")
```py title="Getting session data"
--8<-- "examples/testing/get_session_data.py"
```

### Create Session from Raw Cookies

If your route handlers modify data in session, you may want to assert session data to confirm the modification. If you
are using **Session Middleware**, the response from the route handlers will include raw session cookies which are a
serialized image of the session. To assert data in session,
[`TestClient.get_session_from_cookies`][starlite.testing.test_client.TestClient.get_session_from_cookies] method deserializes
raw session cookies and creates session from them.

```python title="tests/test_route_handlers.py"
import pytest
from starlite.testing import TestClient

from my_app.main import app, session_cookie_config_instance


class TestClass:

@pytest.fixture()
def test_client(self) -> TestClient:
with TestClient(app=app, session_config=session_cookie_config_instance) as client:
yield client

def test_something(self, test_client: TestClient) -> None:
test_client.get(url="/test")
session = test_client.get_session_from_cookies()
assert "user" in session
```

!!! important
The **Session Middleware** must be enabled in Starlite app provided to the TestClient to use sessions.

!!! important
Use the test client as a context manager (i.e. with the `with`) keyword if you want to use the Starlite app's
`on_startup` and `on_shutdown`.

## Creating a Test App

Starlite also offers a helper function called [`create_test_client`][starlite.testing.create_test_client] which first creates
Expand Down
Loading

0 comments on commit 55d7389

Please sign in to comment.