From 588aef48a8a21cd1b440668da6cf53cc38b96a9b Mon Sep 17 00:00:00 2001 From: Adam Hopkins Date: Wed, 17 Mar 2021 22:14:18 +0200 Subject: [PATCH] Add context documentation --- src/en/guide/basics/app.md | 26 +++++++++++++-- src/en/guide/basics/request.md | 40 +++++++++++++++++++++-- src/en/guide/release-notes/v21.3.md | 50 +++++++++++++++++++++++++++++ 3 files changed, 111 insertions(+), 5 deletions(-) diff --git a/src/en/guide/basics/app.md b/src/en/guide/basics/app.md index c6079ebaf5..48dc5438ea 100644 --- a/src/en/guide/basics/app.md +++ b/src/en/guide/basics/app.md @@ -3,10 +3,7 @@ ## Instance ---:1 - - The most basic building block is the `Sanic()` instance. It is not required, but the custom is to instatiate this in a file called `server.py`. - :--:1 ```python # /path/to/server.py @@ -14,9 +11,32 @@ The most basic building block is the `Sanic()` instance. It is not required, but from sanic import Sanic app = Sanic("My Hello, world app") +``` +:--- + +## Application context +::: new NEW in v21.3 +Most applications will have the need to share/reuse data or objects across different parts of the code base. The most common example is DB connections. +::: +---:1 +In versions of Sanic prior to v21.3, this was commonly done by attaching an attribute to the application instance +:--:1 +```python +# Raises a warning as deprecated feature in 21.3 +app = Sanic("MyApp") +app.db = Database() ``` +:--- +---:1 +Because this can create potential problems with name conflicts, and to be consistent with [request context](./request.md#context) objects, v21.3 introduces application level context object. +:--:1 +```python +# Correct way to attach objects to the application +app = Sanic("MyApp") +app.ctx.db = Database() +``` :--- ## App Registry diff --git a/src/en/guide/basics/request.md b/src/en/guide/basics/request.md index 1fbfe482be..47e38d3011 100644 --- a/src/en/guide/basics/request.md +++ b/src/en/guide/basics/request.md @@ -96,12 +96,14 @@ Most of the time you will want to use the `.get()` method can be used to access ## Context +### Request context + The `request.ctx` object is your playground to store whatever information you need to about the request. This is often used to store items like authenticated user details. We will get more into [middleware](./middleware.md) later, but here is a simple example. ```python -@app.middleware("request") +@app.on_request async def run_before_handler(request): request.ctx.user = await fetch_user_by_token(request.token) @@ -114,10 +116,44 @@ A typical use case would be to store the user object acquired from database in a Custom context is reserved for applications and extensions. Sanic itself makes no use of it. -## Parameters +### Connection context ---:1 +::: new NEW in v21.3 +Often times your API will need to serve multiple concurrent (or consecutive) requests to the same client. This happens, for example, very often with progressive web apps that need to query multiple endpoints to get data. + +The HTTP protocol calls for an easing of overhead time caused by the connection with the use of [keep alive headers](../deployment/configuration.md#keep-alive-timeout). +When multiple requests share a single connection, Sanic provides a context object to allow those requests to share state. +::: +:--:1 +```python +@app.on_request +async def increment_foo(request): + if not hasattr(request.conn_info.ctx, "foo"): + request.conn_info.ctx.foo = 0 + request.conn_info.ctx.foo += 1 + +@app.get("/") +async def count_foo(request): + return text(f"{request.conn_info.ctx.foo=}") +``` + +```bash +$ curl localhost:8000 localhost:8000 localhost:8000 +request.conn_info.ctx.foo=1 +request.conn_info.ctx.foo=2 +request.conn_info.ctx.foo=3 +``` +:--- + +::: warning +Connection level context is an experimental feature, and should be finalized in v21.6. +::: + +## Parameters + +---:1 Values that are extracted from the path are injected into the handler as parameters, or more specifically as keyword arguments. There is much more detail about this in the [Routing section](./routing.md). :--:1 ```python diff --git a/src/en/guide/release-notes/v21.3.md b/src/en/guide/release-notes/v21.3.md index 5283a17611..f65dbf47cc 100644 --- a/src/en/guide/release-notes/v21.3.md +++ b/src/en/guide/release-notes/v21.3.md @@ -178,6 +178,56 @@ Sanic internal testing client has been removed. It is now located in its own rep If you have `sanic-testing` installed, it will be available and usable on your `Sanic()` application instances as before. So, the **only** change you will need to make is to add `sanic-testing` to your test suite requirements. +### Application and connection level context (`ctx`) objects + +Version 19.9 [added ](https://github.com/sanic-org/sanic/pull/1666/files) the `request.ctx` API. This helpful construct easily allows for attaching properties and data to a request object (for example, in middleware), and reusing the information elsewhere int he application. + +Similarly, this concept is being extended in two places: + +1. the application instance, and +2. a transport connection. + +#### Application context + +A common use case is to attach properties to the app instance. For the sake of consistency, and to avoid the issue of name collision with Sanic properties, the `ctx` object now exists on `Sanic` instances. + +```python +@app.before_server_startup +async def startup_db(app, _): + # WRONG + app.db = await connect_to_db() + + # CORRECT + app.ctx.db = await connect_to_db() +``` + +#### Connection context + +When a client sends a keep alive header, Sanic will attempt to keep the transport socket [open for a period of time](../deployment/configuration.md#keep-alive-timeout). That transport object now has a `ctx` object available on it. This effectively means that multiple requests from a single client (where the transport layer is being reused) may share state. + +```python +@app.on_request +async def increment_foo(request): + if not hasattr(request.conn_info.ctx, "foo"): + request.conn_info.ctx.foo = 0 + request.conn_info.ctx.foo += 1 + +@app.get("/") +async def count_foo(request): + return text(f"{request.conn_info.ctx.foo=}") +``` + +```bash +$ curl localhost:8000 localhost:8000 localhost:8000 +request.conn_info.ctx.foo=1 +request.conn_info.ctx.foo=2 +request.conn_info.ctx.foo=3 +``` + +::: warning +Connection level context is an experimental feature, and should be finalized in v21.6. +::: + ## News