# Technical Documentation: sanic-org/sanic

> ℹ️ **Provenance:** Multi-Tier Ingestion · [CodeWiki Reference](https://codewiki.google/github.com/sanic-org/sanic)

### Guide Content En Index (`guide/content/en/index.md`)

---
title: The lightning-fast asynchronous Python web framework
layout: home
features:
- title: Simple and lightweight
  details: Intuitive API with smart defaults and no bloat allows you to get straight to work building your app.
- title: Unopinionated and flexible
  details: Build the way you want to build without letting your tooling constrain you.
- title: Performant and scalable
  details: Built from the ground up with speed and scalability as a main concern. It is ready to power web applications big and small.
- title: Production ready
  details: Out of the box, it comes bundled with a web server ready to power your web applications.
- title: Trusted by millions
  details: Sanic is one of the overall most popular frameworks on PyPI, and the top async enabled framework
- title: Community driven
  details: The project is maintained and run by the community for the community.
---

### ⚡ The lightning-fast asynchronous Python web framework

.. attrs::
    :class: columns is-multiline mt-6

    .. attrs::
        :class: column is-4

        #### Simple and lightweight

        Intuitive API with smart defaults and no bloat allows you to get straight to work building your app.

    .. attrs::
        :class: column is-4

        #### Unopinionated and flexible

        Build the way you want to build without letting your tooling constrain you.

    .. attrs::
        :class: column is-4

        #### Performant and scalable

        Built from the ground up with speed and scalability as a main concern. It is ready to power web applications big and small.

    .. attrs::
        :class: column is-4

        #### Production ready

        Out of the box, it comes bundled with a web server ready to power your web applications.

    .. attrs::
        :class: column is-4

        #### Trusted by millions

        Sanic is one of the overall most popular frameworks on PyPI, and the top async enabled framework

    .. attrs::
        :class: column is-4

        #### Community driven

        The project is maintained and run by the community for the community.


.. attrs::
    :class: is-size-3 mt-6

    **With the features and tools you'd expect.**

.. attrs::
    :class: is-size-3 ml-6
    
    **And some {span:has-text-primary:you wouldn't believe}.**

.. tab:: Production-grade
    
    After installing, Sanic has all the tools you need for a scalable, production-grade server—out of the box!

    Including [full TLS support](/en/guide/how-to/tls.md).

    ```python
    from sanic import Sanic
    from sanic.response import text

    app = Sanic("MyHelloWorldApp")

    @app.get("/")
    async def hello_world(request):
        return text("Hello, world.")
    ```

    ```sh
    sanic path.to.server:app
    [2023-01-31 12:34:56 +0000] [999996] [INFO] Sanic v22.12.0
    [2023-01-31 12:34:56 +0000] [999996] [INFO] Goin' Fast @ http://127.0.0.1:8000
    [2023-01-31 12:34:56 +0000] [999996] [INFO] mode: production, single worker
    [2023-01-31 12:34:56 +0000] [999996] [INFO] server: sanic, HTTP/1.1
    [2023-01-31 12:34:56 +0000] [999996] [INFO] python: 3.10.9
    [2023-01-31 12:34:56 +0000] [999996] [INFO] platform: SomeOS-9.8.7
    [2023-01-31 12:34:56 +0000] [999996] [INFO] packages: sanic-routing==22.8.0
    [2023-01-31 12:34:56 +0000] [999997] [INFO] Starting worker [999997]
    ```

.. tab:: TLS server
    
    Running Sanic with TLS enabled is as simple as passing it the file paths...
    ```sh
    sanic path.to.server:app --cert=/path/to/bundle.crt --key=/path/to/privkey.pem
    ```

    ... or the a directory containing `fullchain.pem` and `privkey.pem`

    ```sh
    sanic path.to.server:app --tls=/path/to/certs
    ```

    **Even better**, while you are developing, let Sanic handle setting up local TLS certificates so you can access your site over TLS at [https://localhost:8443](https://localhost:8443)

    ```sh
    sanic path.to.server:app --dev --auto-tls
    ```

.. tab:: Websockets

    Up and running with websockets in no time using the [websockets](https://websockets.readthedocs.io) package.
    ```python
    from sanic import Request, Websocket

    @app.websocket("/feed")
    async def feed(request: Request, ws: Websocket):
        async for msg in ws:
            await ws.send(msg)
    ```

.. tab:: Static files

    Serving static files is of course intuitive and easy. Just name an endpoint and either a file or directory that should be served.

    ```python
    app.static("/", "/path/to/index.html")
    app.static("/uploads/", "/path/to/uploads/")
    ```

    Moreover, serving a directory has two additional features: automatically serving an index, and automatically serving a file browser.
    
    Sanic can automatically serve `index.html` (or any other named file) as an index page in a directory or its subdirectories.
    
    ```python
    app.static(
        "/uploads/",
        "/path/to/uploads/",
        index="index.html"
    )
    ```

    And/or, setup Sanic to display a file browser.

    
    

    ```python
    app.static(
        "/uploads/",
        "/path/to/uploads/",
        directory_view=True
    )
    ```

.. tab:: Lifecycle

    Beginning or ending a route with functionality is as simple as adding a decorator.

    ```python
    @app.on_request
    async def add_key(request):
        request.ctx.foo = "bar"

    @app.on_response
    async def custom_banner(request, response):
        response.headers["X-Foo"] = request.ctx.foo
    ```

    Same with server events.

    ```python
    @app.before_server_start
    async def setup_db(app):
        app.ctx.db_pool = await db_setup()

    @app.after_server_stop
    async def setup_db(app):
        await app.ctx.db_pool.shutdown()
    ```

    But, Sanic also allows you to tie into a bunch of built-in events (called signals), or create and dispatch your own.

    ```python
    @app.signal("http.lifecycle.complete")  # built-in
    async def my_signal_handler(conn_info):
        print("Connection has been closed")

    @app.signal("something.happened.ohmy")  # custom
    async def my_signal_handler():
        print("something happened")

    await app.dispatch("something.happened.ohmy")
    ```

.. tab:: Smart error handling

    Raising errors will intuitively result in proper HTTP errors:

    ```python
    raise sanic.exceptions.NotFound  # Automatically responds with HTTP 404
    ```

    Or, make your own:

    ```python
    from sanic.exceptions import SanicException

    class TeapotError(SanicException):
        status_code = 418
        message = "Sorry, I cannot brew coffee"

    raise TeapotError
    ```

    And, when an error does happen, Sanic's beautiful DEV mode error page will help you drill down to the bug quickly.

    

    Regardless, Sanic comes with an algorithm that attempts to respond with HTML, JSON, or text-based errors as appropriate. Don't worry, it is super easy to setup and customize your error handling to your exact needs.

.. tab:: App Inspector

    Check in on your live, running applications (whether local or remote).
    ```
/* Detailed source-code truncated for AI context efficiency. */
```

    And, issue commands like `reload`, `shutdown`, `scale`...

    ```sh
    sanic inspect scale 4
    ```

    ... or even create your own!

    ```sh
    sanic inspect migrations
    ```

.. tab:: Extendable

    In addition to the tools that Sanic comes with, the officially supported [Sanic Extensions](./plugins/sanic-ext/getting-started.md) provides lots of extra goodies to make development easier.

    - **CORS** protection
    - Template rendering with **Jinja**
    - **Dependency injection** into route handlers
    - OpenAPI documentation with **Redoc** and/or **Swagger**
    - Predefined, endpoint-specific response **serializers**
    - Request query arguments and body input **validation**
    - **Auto create** HEAD, OPTIONS, and TRACE endpoints
    - Live **health monitor**

.. tab:: Developer Experience

    Sanic is **built for building**.

    From the moment it is installed, Sanic includes helpful tools to help the developer get their job done.

    - **One server** - Develop locally in DEV mode on the same server that will run your PRODUCTION application
    - **Auto reload** - Reload running applications every time you save a Python file, but also auto-reload **on any arbitrary directory** like HTML template directories
    - **Debugging tools** - Super helpful (and beautiful) [error pages](/en/guide/best-practices/exceptions) that help you traverse the trace stack easily
    - **Auto TLS** - Running a localhost website with `https` can be difficult, [Sanic makes it easy](/en/guide/how-to/tls.md)
    - **Streamlined testing** - Built-in testing capabilities, making it easier for developers to create and run tests, ensuring the quality and reliability of their services
    - **Modern Python** - Thoughtful use of type hints to help the developer IDE experience

---

### Guide Content En Guide Getting Started (`guide/content/en/guide/getting-started.md`)

# Getting Started

Before we begin, make sure you are running Python 3.9 or higher. Currently, Sanic is works with Python versions 3.9 – 3.13.

## Install

```sh
pip install sanic
```

## Hello, world application

.. column::

    If you have ever used one of the many decorator based frameworks, this probably looks somewhat familiar to you.

    

    .. note:: 

        If you are coming from Flask or another framework, there are a few important things to point out. Remember, Sanic aims for performance, flexibility, and ease of use. These guiding principles have tangible impact on the API and how it works.

.. column::

    ```python
    from sanic import Sanic
    from sanic.response import text

    app = Sanic("MyHelloWorldApp")

    @app.get("/")
    async def hello_world(request):
        return text("Hello, world.")
    ```

### Important to note

- Every request handler can either be sync (`def hello_world`) or async (`async def hello_world`). Unless you have a clear reason for it, always go with `async`.
- The `request` object is always the first argument of your handler. Other frameworks pass this around in a context variable to be imported. In the `async` world, this would not work so well and it is far easier (not to mention cleaner and more performant) to be explicit about it. 
- You **must** use a response type. MANY other frameworks allow you to have a return value like this: `return "Hello, world."` or this: `return {"foo": "bar"}`. But, in order to do this implicit calling, somewhere in the chain needs to spend valuable time trying to determine what you meant. So, at the expense of this ease, Sanic has decided to require an explicit call.

### Running

.. column::

    Let's save the above file as `server.py`. And launch it.

.. column::

    ```sh
    sanic server
    ```

.. note:: 

    This **another** important distinction. Other frameworks come with a built in development server and explicitly say that it is _only_ intended for development use. The opposite is true with Sanic. 

    **The packaged server is production ready.**


## Sanic Extensions

Sanic intentionally aims for a clean and unopinionated feature list. The project does not want to require you to build your application in a certain way, and tries to avoid prescribing specific development patterns. There are a number of third-party plugins that are built and maintained by the community to add additional features that do not otherwise meet the requirements of the core repository.

However, in order **to help API developers**, the Sanic organization maintains an official plugin called [Sanic Extensions](../plugins/sanic-ext/getting-started.md) to provide all sorts of goodies, including:

- **OpenAPI** documentation with Redoc and/or Swagger
- **CORS** protection
- **Dependency injection** into route handlers
- Request query arguments and body input **validation**
- Auto create `HEAD`, `OPTIONS`, and `TRACE` endpoints
- Predefined, endpoint-specific response serializers

The preferred method to set it up is to install it along with Sanic, but you can also install the packages on their own.

.. column::

    ```sh
    pip install sanic[ext]
    ```

.. column::

    ```sh
    pip install sanic sanic-ext
    ```

Starting in v21.12, Sanic will automatically setup Sanic Extensions if it is in the same environment. You will also have access to two additional application properties:

- `app.extend()` - used to configure Sanic Extensions
- `app.ext` - the `Extend` instance attached to the application

See [the plugin documentation](../plugins/sanic-ext/getting-started.md) for more information about how to use and work with the plugin

---

### Guide Content En Plugins Sanic Ext Getting Started (`guide/content/en/plugins/sanic-ext/getting-started.md`)

---
title: Sanic Extensions - Getting Started
---

# Getting Started

Sanic Extensions is an *officially supported* plugin developed, and maintained by the SCO. The primary goal of this project is to add additional features to help Web API and Web application development easier.

## Features

- CORS protection
- Template rendering with Jinja
- Dependency injection into route handlers
- OpenAPI documentation with Redoc and/or Swagger
- Predefined, endpoint-specific response serializers
- Request query arguments and body input validation
- Auto create `HEAD`, `OPTIONS`, and `TRACE` endpoints

## Minimum requirements

- **Python**: 3.8+
- **Sanic**: 21.9+

## Install

The best method is to just install Sanic Extensions along with Sanic itself:

```bash
pip install sanic[ext]
```

You can of course also just install it by itself.

```bash
pip install sanic-ext
```

## Extend your application

Out of the box, Sanic Extensions will enable a bunch of features for you. 

.. column::

    To setup Sanic Extensions (v21.12+), you need to do: **nothing**. If it is installed in the environment, it is setup and ready to go.

    This code is the Hello, world app in the [Sanic Getting Started page](../../guide/getting-started.md) _without any changes_, but using Sanic Extensions with `sanic-ext` installed in the background.

.. column::

    ```python
    from sanic import Sanic
    from sanic.response import text

    app = Sanic("MyHelloWorldApp")

    @app.get("/")
    async def hello_world(request):
        return text("Hello, world.")
    ```


.. column::

    **_OLD DEPRECATED SETUP_**

    In v21.9, the easiest way to get started is to instantiate it with `Extend`.

    If you look back at the Hello, world app in the [Sanic Getting Started page](../../guide/getting-started.md), you will see the only additions here are the two highlighted lines.

.. column::

    ```python
    from sanic import Sanic
    from sanic.response import text
    from sanic_ext import Extend

    app = Sanic("MyHelloWorldApp")
    Extend(app)

    @app.get("/")
    async def hello_world(request):
        return text("Hello, world.")
    ```

Regardless of how it is setup, you should now be able to view the OpenAPI documentation and see some of the functionality in action: [http://localhost:8000/docs](http://localhost:8000/docs).

---

### Guide Content En Plugins Sanic Testing Getting Started (`guide/content/en/plugins/sanic-testing/getting-started.md`)

---
title: Sanic Testing - Getting Started
---

# Getting Started

Sanic Testing is the *official* testing client for Sanic. Its primary use is to power the tests of the Sanic project itself. However, it is also meant as an easy-to-use client for getting your API tests up and running quickly.

## Minimum requirements

- **Python**: 3.7+
- **Sanic**: 21.3+

Versions of Sanic older than 21.3 have this module integrated into Sanic itself as `sanic.testing`.

## Install

Sanic Testing can be installed from PyPI:

```
pip install sanic-testing
```

## Basic Usage

As long as the `sanic-testing` package is in the environment, there is nothing you need to do to start using it.

### Writing a sync test

In order to use the test client, you just need to access the property `test_client` on your application instance:

```python
import pytest
from sanic import Sanic, response

@pytest.fixture
def app():
    sanic_app = Sanic("TestSanic")

    @sanic_app.get("/")
    def basic(request):
        return response.text("foo")

    return sanic_app

def test_basic_test_client(app):
    request, response = app.test_client.get("/")

    assert request.method.lower() == "get"
    assert response.body == b"foo"
    assert response.status == 200
```

### Writing an async test

In order to use the async test client in `pytest`, you should install the `pytest-asyncio` plugin.

```
pip install pytest-asyncio
```

You can then create an async test and use the ASGI client:

```python
import pytest
from sanic import Sanic, response

@pytest.fixture
def app():
    sanic_app = Sanic(__name__)

    @sanic_app.get("/")
    def basic(request):
        return response.text("foo")

    return sanic_app

@pytest.mark.asyncio
async def test_basic_asgi_client(app):
    request, response = await app.asgi_client.get("/")

    assert request.method.lower() == "get"
    assert response.body == b"foo"
    assert response.status == 200
```

---

### Index (`docs/index.rst`)

.. include:: ../README.rst

User Guide
==========

To learn about using Sanic, checkout the `User Guide <https://sanicframework.org/guide/>`__.

API
===

.. toctree::
   :maxdepth: 3

   👥 User Guide <https://sanicframework.org/guide/>
   sanic/api_reference
   💻 Source code <https://github.com/sanic-org/sanic/>
   sanic/changelog
   sanic/contributing
   ❓ Support <https://community.sanicframework.org/>
   💬 Chat <https://discord.gg/FARQzAEMAA>


Module Documentation
====================

.. toctree::

* :ref:`genindex`
* :ref:`modindex`

---

### Guide Requirements (`guide/requirements.txt`)

sanic>=23.12
sanic-ext>=23.12
msgspec
python-frontmatter
pygments
docstring-parser
libsass
mistune

---

### Sanic Api Reference (`docs/sanic/api_reference.rst`)

📑 API Reference
================

.. toctree::
   :maxdepth: 2

   api/app
   api/blueprints
   api/core
   api/exceptions
   api/router
   api/server
   api/utility

---

### Sanic Changelog (`docs/sanic/changelog.rst`)

📜 Changelog
============

| 🔶 Current release
| 🔷 In support release
|

.. mdinclude:: ./releases/23/23.6.md
.. mdinclude:: ./releases/23/23.3.md
.. mdinclude:: ./releases/22/22.12.md
.. mdinclude:: ./releases/22/22.9.md
.. mdinclude:: ./releases/22/22.6.md
.. mdinclude:: ./releases/22/22.3.md
.. mdinclude:: ./releases/21/21.12.md
.. mdinclude:: ./releases/21/21.9.md
.. include:: ../../CHANGELOG.rst

---

### Sanic Contributing (`docs/sanic/contributing.rst`)

♥️ Contributing
===============

.. include:: ../../CONTRIBUTING.rst

---

### Sanic Api App (`docs/sanic/api/app.rst`)

Application
===========

sanic.app
---------

.. automodule:: sanic.app
    :members:
    :show-inheritance:
    :inherited-members:

sanic.config
------------

.. automodule:: sanic.config
    :members:
    :show-inheritance:

sanic.application.constants
---------------------------

.. automodule:: sanic.application.constants
    :exclude-members: StrEnum
    :members:
    :show-inheritance:
    :inherited-members:

sanic.application.state
-----------------------

.. automodule:: sanic.application.state
    :members:
    :show-inheritance:

---

### Sanic Api Blueprints (`docs/sanic/api/blueprints.rst`)

Blueprints
==========

sanic.blueprints
----------------

.. automodule:: sanic.blueprints
    :members:
    :show-inheritance:
    :inherited-members:

sanic.blueprint_group
---------------------

.. automodule:: sanic.blueprint_group
    :members:
    :special-members:

---

### Sanic Api Core (`docs/sanic/api/core.rst`)

Core
====

sanic.cookies
-------------

.. automodule:: sanic.cookies
    :members:
    :show-inheritance:


sanic.handlers
--------------

.. automodule:: sanic.handlers
    :members:
    :show-inheritance:


sanic.headers
--------------

.. automodule:: sanic.headers
    :members:
    :show-inheritance:


sanic.request
-------------

.. automodule:: sanic.request
    :members:
    :show-inheritance:

sanic.response
--------------

.. automodule:: sanic.response
    :members:
    :show-inheritance:


sanic.views
-----------

.. automodule:: sanic.views
    :members:
    :show-inheritance:

---

### Sanic Api Exceptions (`docs/sanic/api/exceptions.rst`)

Exceptions
==========

sanic.errorpages
----------------

.. automodule:: sanic.errorpages
    :members:
    :show-inheritance:

sanic.exceptions
----------------

.. automodule:: sanic.exceptions
    :members:
    :show-inheritance:

---

### Sanic Api Router (`docs/sanic/api/router.rst`)

Routing
=======

sanic_routing models
--------------------

.. autoclass:: sanic_routing.route::Route
    :members:

.. autoclass:: sanic_routing.group::RouteGroup
    :members:

sanic.router
------------

.. automodule:: sanic.router
    :members:
    :show-inheritance:

---

### Sanic Api Server (`docs/sanic/api/server.rst`)

Sanic Server
============

sanic.http
----------

.. automodule:: sanic.http
    :members:
    :show-inheritance:


sanic.server
------------

.. automodule:: sanic.server
    :members:
    :show-inheritance:

---

### Sanic Api Utility (`docs/sanic/api/utility.rst`)

Utility
=======

sanic.compat
------------

.. automodule:: sanic.compat
    :members:
    :show-inheritance:

sanic.log
---------

.. automodule:: sanic.log
    :members:
    :show-inheritance:

---

### Guide Config En Navbar.Yaml (`guide/config/en/navbar.yaml`)

root:
    - label: Home
      path: index.html
    - label: Community
      items:
          - label: Forums
            href: https://community.sanicframework.org
          - label: Discord
            href: https://discord.gg/FARQzAEMAA
          - label: Twitter
            href: https://twitter.com/sanicframework
    - label: Help
      path: ./help.html
    - label: GitHub
      href: https://github.com/sanic-org/sanic

---

### Guide Config En Sidebar.Yaml (`guide/config/en/sidebar.yaml`)

root:
    - label: User Guide
      items:
          - label: General
            items:
                - label: Introduction
                  path: guide/introduction.html
                - label: Getting Started
                  path: guide/getting-started.html
          - label: Basics
            items:
                - label: Sanic Application
                  path: guide/basics/app.html
                - label: Handlers
                  path: guide/basics/handlers.html
                - label: Request
                  path: guide/basics/request.html
                - label: Response
                  path: guide/basics/response.html
                - label: Routing
                  path: guide/basics/routing.html
                - label: Listeners
                  path: guide/basics/listeners.html
                - label: Middleware
                  path: guide/basics/middleware.html
                - label: Headers
                  path: guide/basics/headers.html
                - label: Cookies
                  path: guide/basics/cookies.html
                - label: Background Tasks
                  path: guide/basics/tasks.html
          - label: Advanced
            items:
                - label: Class Based Views
                  path: guide/advanced/class-based-views.html
                - label: Proxy Configuration
                  path: guide/advanced/proxy-headers.html
                - label: Streaming
                  path: guide/advanced/streaming.html
                - label: Websockets
                  path: guide/advanced/websockets.html
                - label: Versioning
                  path: guide/advanced/versioning.html
                - label: Signals
                  path: guide/advanced/signals.html
                - label: Custom CLI Commands
                  path: guide/advanced/commands.html
          - label: Best Practices
            items:
                - label: Blueprints
                  path: guide/best-practices/blueprints.html
                - label: Exceptions
                  path: guide/best-practices/exceptions.html
                - label: Decorators
                  path: guide/best-practices/decorators.html
                - label: Logging
                  path: guide/best-practices/logging.html
                - label: Testing
                  path: guide/best-practices/testing.html
          - label: Running Sanic
            items:
                - label: Configuration
                  path: guide/running/configuration.html
                - label: Development
                  path: guide/running/development.html
                - label: Running Sanic
                  path: guide/running/running.html
                - label: Worker Manager
                  path: guide/running/manager.html
                - label: Dynamic Applications
                  path: guide/running/app-loader.html
                - label: Inspector
                  path: guide/running/inspector.html
          - label: Deployment
            items:
                - label: Caddy
                  path: guide/deployment/caddy.html
                - label: Nginx
                  path: guide/deployment/nginx.html
                - label: Docker
                  path: guide/deployment/docker.html
          - label: How to ...
            items:
                - label: Table of Contents
                  path: guide/how-to/table-of-contents.html
                - label: Application Mounting
                  path: guide/how-to/mounting.html
                - label: Authentication
                  path: guide/how-to/authentication.html
                - label: Autodiscovery
                  path: guide/how-to/autodiscovery.html
                - label: CORS
                  path: guide/how-to/cors.html
                - label: ORM
                  path: guide/how-to/orm.html
                - label: Static Redirects
                  path: guide/how-to/static-redirects.html
                - label: TLS/SSL/HTTPS
                  path: guide/how-to/tls.html
    - label: Plugins
      items:
          - label: Sanic Extensions
            items:
                - label: Getting Started
                  path: plugins/sanic-ext/getting-started.html
                - label: HTTP - Methods
                  path: plugins/sanic-ext/http/methods.html
                - label: HTTP - CORS Protection
                  path: plugins/sanic-ext/http/cors.html
                - label: OpenAPI - Basics
                  path: plugins/sanic-ext/openapi/basics.html
                - label: OpenAPI - UI
                  path: plugins/sanic-ext/openapi/ui.html
                - label: OpenAPI - Decorators
                  path: plugins/sanic-ext/openapi/decorators.html
                # - label: OpenAPI - Advanced
                #   path: plugins/sanic-ext/openapi/advanced.html
                - label: OpenAPI - Auto Documentation
                  path: plugins/sanic-ext/openapi/autodoc.html
                - label: OpenAPI - Security
                  path: plugins/sanic-ext/openapi/security.html
                - label: Convenience
                  path: plugins/sanic-ext/convenience.html
                - label: Templating - Jinja
                  path: plugins/sanic-ext/templating/jinja.html
                - label: Templating - html5tagger
                  path: plugins/sanic-ext/templating/html5tagger.html
                - label: Dependency Injection
                  path: plugins/sanic-ext/injection.html
                - label: Validation
                  path: plugins/sanic-ext/validation.html
                - label: Health Monitor
                  path: plugins/sanic-ext/health-monitor.html
                - label: Background Logger
                  path: plugins/sanic-ext/logger.html
                - label: Configuration
                  path: plugins/sanic-ext/configuration.html
                - label: Custom Extensions
                  path: plugins/sanic-ext/custom.html
          - label: Sanic Testing
            items:
                - label: Getting Started
                  path: plugins/sanic-testing/getting-started.html
                - label: Test Clients
                  path: plugins/sanic-testing/clients.html
    - label: Release Notes
      items:
          - label: "2025"
            items:
                - label: Sanic 25.12
                  path: release-notes/2025/v25.12.html
                - label: Sanic 25.3
                  path: release-notes/2025/v25.3.html
          - label: "2024"
            items:
                - label: Sanic 24.12
                  path: release-notes/2024/v24.12.html
                - label: Sanic 24.6
                  path: release-notes/2024/v24.6.html
          - label: "2023"
            items:
                - label: Sanic 23.12
                  path: release-notes/2023/v23.12.html
                - label: Sanic 23.9
                  path: release-notes/2023/v23.9.html
                - label: Sanic 23.6
                  path: release-notes/2023/v23.6.html
                - label: Sanic 23.3
                  path: release-notes/2023/v23.3.html
          - label: "2022"
            items:
                - label: Sanic 22.12
                  path: release-notes/2022/v22.12.html
                - label: Sanic 22.9
                  path: release-notes/2022/v22.9.html
                - label: Sanic 22.6
                  path: release-notes/2022/v22.6.html
                - label: Sanic 22.3
                  path: release-notes/2022/v22.3.html
          - label: "2021"
            items:
                - label: Sanic 21.12
                  path: release-notes/2021/v21.12.html
                - label: Sanic 21.9
                  path: release-notes/2021/v21.9.html
                - label: Sanic 21.6
                  path: release-notes/2021/v21.6.html
                - label: Sanic 21.3
                  path: release-notes/2021/v21.3.html
          - label: Changelog
            path: release-notes/changelog.html
    - label: Organization
      items:
          - label: Contributing
            path: organization/contributing.html
          - label: Code of Conduct
            path: organization/code-of-conduct.html
          - label: S.C.O.P.E. (Governance)
            path: organization/scope.html
          - label: Policies
            path: organization/policies.html
    - label: API Reference
      items:
          - label: Application
            items:
                - label: sanic.app
                  path: /api/sanic.app.html
                - label: sanic.config
                  path: /api/sanic.config.html
                - label: sanic.application
                  path: /api/sanic.application.html
          - label: Blueprint
            items:
                - label: sanic.blueprints
                  path: /api/sanic.blueprints.html
                - label: sanic.blueprint_group
                  path: /api/sanic.blueprint_group.html
          - label: Constant
            items:
                - label: sanic.constants
                  path: /api/sanic.constants.html
          - label: Core
            items:
                - label: sanic.cookies
                  path: /api/sanic.cookies.html
                - label: sanic.handlers
                  path: /api/sanic.handlers.html
                - label: sanic.headers
                  path: /api/sanic.headers.html
                - label: sanic.middleware
                  path: /api/sanic.middleware.html
                - label: sanic.mixins
                  path: /api/sanic.mixins.html
                - label: sanic.request
                  path: /api/sanic.request.html
                - label: sanic.response
                  path: /api/sanic.response.html
                - label: sanic.views
                  path: /api/sanic.views.html
          - label: Display
            items:
                - label: sanic.pages
                  path: /api/sanic.pages.html
          - label: Exception
            items:
                - label: sanic.errorpages
                  path: /api/sanic.errorpages.html
                - label: sanic.exceptions
                  path: /api/sanic.exceptions.html
          - label: Model
            items:
                - label: sanic.models
                  path: /api/sanic.models.html
          - label: Routing
            items:
                - label: sanic.router
                  path: /api/sanic.router.html
                - label: sanic.signals
                  path: /api/sanic.signals.html
          - label: Server
            items:
                - label: sanic.http
                  path: /api/sanic.http.html
                - label: sanic.server
                  path: /api/sanic.server.html
                - label: sanic.worker
                  path: /api/sanic.worker.html
          - label: Utility
            items:
                - label: sanic.compat
                  path: /api/sanic.compat.html
                - label: sanic.helpers
                  path: /api/sanic.helpers.html
                - label: sanic.logging
                  path: /api/sanic.logging.html
                - label: sanic.utils
                  path: /api/sanic.utils.html

---

### Guide Content En Built With Sanic (`guide/content/en/built-with-sanic.md`)

---
title: Full Speed Ahead - How We Built This Site with Sanic
layout: main
---

.. attrs::
    :class: title

    Full Speed Ahead:

.. attrs::
    :class: subtitle

    How We Built This Site with Sanic

Welcome to our little corner of the Internet where we proudly say, "Yes, we built this with Sanic!" This isn't just a website; it's our playground, our test lab, our battlefield, and, well, our home.



### The Story: "We Drink Our Own Champagne"

We believe in Sanic so much that we decided to put it to the ultimate test—running our own website. It's like a chef eating at their own restaurant, only with less risk of food poisoning.

Why? Because building a website or web application is hard. There are countless moving parts, a plethora of challenges, and the ever-present need for speed and reliability. We want to show you just one of the many ways you *could* do it.

In this high-stakes digital kitchen, Sanic is our secret ingredient. By deploying our own website on Sanic, we're not just showcasing its capabilities; we're stress-testing them in the real world. This is our chance to walk the walk, proving that Sanic isn't just good on paper—it's a robust, high-performance framework that can handle everything from the smallest blog to the busiest e-commerce site. 

So, here we are, sipping our own champagne, confident in the knowledge that if Sanic can run our site, it can power yours too. Cheers to coding at the speed of thought! 🥂

### The Setup: Digital Ocean, Ahoy!

We launched our site on Digital Ocean's App Platform because we love high-performance cloud sailing. Think of it as having a Ferrari in the cloud—fast, sleek, but way easier to handle.

Why go for simplicity? With a lean team and no DevOps gurus, we needed a no-fuss, straightforward solution. Digital Ocean gives us that smooth sailing platform-as-a-service (PaaS) experience. It’s perfect for our needs: easy setup, automatic deployments, and the kind of reliability that lets you sleep soundly.

Our choice reflects our ethos: focus on your strengths and let the platform do the heavy lifting. For us, it means creating amazing web experiences with Sanic, supported by a deployment solution that's simple yet powerful. ⛵

### The Code: GitHub's Where It's At

All our code is out in the open, basking in the glory of public scrutiny on GitHub. Why hide the magic? It's right there, in full view, at [our GitHub repository](https://github.com/sanic-org/sanic/tree/main/guide). Go ahead, take a peek, fork it, play with it, break it (and then kindly fix it).

Open-source isn't just a buzzword for us; it's our ethos. It's about building something bigger than ourselves, together. Our code is a testament to collaborative innovation, a playground for development, and a real-life example of Sanic in action.

Every line of code, every commit, reflects our journey with Sanic, showcasing how we leverage its speed and scalability. Your contributions, whether fixing a bug, suggesting a feature, or enhancing documentation, are what propel this project forward.

So, dive in, contribute your genius, and let's keep shaping the future of web development with Sanic. Together, we're not just coding – we're creating a community-driven powerhouse. 🚀

### The Invitation: Write, Code, Break, Fix!

- **Documentarians**: Love making complex stuff sound easy? Our docs are your canvas. Paint away in words! 🎨

- **Code Ninjas**: Find bugs? Squash 'em. Got ideas? Code 'em. Make pull requests rain! 🥷

- **Bug Hunters**: If you find bugs, don't just stare. Let us know. We love a good bug hunt. 🐛
 
### The Bottom Line

We built this site with Sanic to show off what it can do. It's fast, it's fun, and it's what we use. So, if things load swiftly, pat us on the back. If they don't, well, uh... we blame cosmic rays?

Join us in making Sanic not just good, but "I-can't-believe-it's-not-butter" good!

Cheers,
The Sanic Team (who occasionally wear capes)

---

### Guide Content En Help (`guide/content/en/help.md`)

---
title: Need some help?
layout: main
---

# Need some help?

As an active community of developers, we try to support each other. If you need some help, try one of the following:

.. column::

    ### Discord 💬

    Best place to turn for quick answers and live chat

    `#sanic-support` channel on the [Discord server](https://discord.gg/FARQzAEMAA)

.. column::

    ### Community Forums 👥

    Good for sharing snippets of code and longer support queries

    `Questions and Help` category on the [Forums](https://community.sanicframework.org/c/questions-and-help/6)

---

We also actively monitor the `[sanic]` tag on [Stack Overflow](https://stackoverflow.com/questions/tagged/sanic).

---

### Guide Public Web Robots (`guide/public/web/robots.txt`)

User-agent: *
Allow: /
Sitemap: https://sanic.dev/sitemap.xml
Host: https://sanic.dev

---

### Sanic Releases 21 21.12 (`docs/sanic/releases/21/21.12.md`)

## Version 21.12.1 🔷

_Current LTS version_

- [#2349](https://github.com/sanic-org/sanic/pull/2349) Only display MOTD on startup
- [#2354](https://github.com/sanic-org/sanic/pull/2354) Ignore name argument in Python 3.7
- [#2355](https://github.com/sanic-org/sanic/pull/2355) Add config.update support for all config values

## Version 21.12.0 🔹

### Features
- [#2260](https://github.com/sanic-org/sanic/pull/2260) Allow early Blueprint registrations to still apply later added objects
- [#2262](https://github.com/sanic-org/sanic/pull/2262) Noisy exceptions - force logging of all exceptions
- [#2264](https://github.com/sanic-org/sanic/pull/2264) Optional `uvloop` by configuration
- [#2270](https://github.com/sanic-org/sanic/pull/2270) Vhost support using multiple TLS certificates
- [#2277](https://github.com/sanic-org/sanic/pull/2277) Change signal routing for increased consistency
    - *BREAKING CHANGE*: If you were manually routing signals there is a breaking change. The signal router's `get` is no longer 100% determinative. There is now an additional step to loop thru the returned signals for proper matching on the requirements. If signals are being dispatched using `app.dispatch` or `bp.dispatch`, there is no change.
- [#2290](https://github.com/sanic-org/sanic/pull/2290) Add contextual exceptions
- [#2291](https://github.com/sanic-org/sanic/pull/2291) Increase join concat performance 
- [#2295](https://github.com/sanic-org/sanic/pull/2295), [#2316](https://github.com/sanic-org/sanic/pull/2316), [#2331](https://github.com/sanic-org/sanic/pull/2331) Restructure of CLI and application state with new displays and more command parity with `app.run`
- [#2302](https://github.com/sanic-org/sanic/pull/2302) Add route context at definition time
- [#2304](https://github.com/sanic-org/sanic/pull/2304) Named tasks and new API for managing background tasks
- [#2307](https://github.com/sanic-org/sanic/pull/2307) On app auto-reload, provide insight of changed files
- [#2308](https://github.com/sanic-org/sanic/pull/2308) Auto extend application with [Sanic Extensions](https://sanicframework.org/en/plugins/sanic-ext/getting-started.html) if it is installed, and provide first class support for accessing the extensions
- [#2309](https://github.com/sanic-org/sanic/pull/2309) Builtin signals changed to `Enum`
- [#2313](https://github.com/sanic-org/sanic/pull/2313) Support additional config implementation use case
- [#2321](https://github.com/sanic-org/sanic/pull/2321) Refactor environment variable hydration logic
- [#2327](https://github.com/sanic-org/sanic/pull/2327) Prevent sending multiple or mixed responses on a single request
- [#2330](https://github.com/sanic-org/sanic/pull/2330) Custom type casting on environment variables
- [#2332](https://github.com/sanic-org/sanic/pull/2332) Make all deprecation notices consistent
- [#2335](https://github.com/sanic-org/sanic/pull/2335) Allow underscore to start instance names

### Bugfixes
- [#2273](https://github.com/sanic-org/sanic/pull/2273) Replace assignation by typing for `websocket_handshake`
- [#2285](https://github.com/sanic-org/sanic/pull/2285) Fix IPv6 display in startup logs
- [#2299](https://github.com/sanic-org/sanic/pull/2299) Dispatch `http.lifecyle.response` from exception handler

### Deprecations and Removals
- [#2306](https://github.com/sanic-org/sanic/pull/2306) Removal of deprecated items
    - `Sanic` and `Blueprint` may no longer have arbitrary properties attached to them
    - `Sanic` and `Blueprint` forced to have compliant names
        - alphanumeric + `_` + `-`
        - must start with letter or `_`
    - `load_env` keyword argument of `Sanic`
    - `sanic.exceptions.abort`
    - `sanic.views.CompositionView`
    - `sanic.response.StreamingHTTPResponse`
        - *NOTE:* the `stream()` response method (where you pass a callable streaming function) has been deprecated and will be removed in v22.6. You should upgrade all streaming responses to the new style: https://sanicframework.org/en/guide/advanced/streaming.html#response-streaming
- [#2320](https://github.com/sanic-org/sanic/pull/2320) Remove app instance from Config for error handler setting

### Developer infrastructure
- [#2251](https://github.com/sanic-org/sanic/pull/2251) Change dev install command
- [#2286](https://github.com/sanic-org/sanic/pull/2286) Change codeclimate complexity threshold from 5 to 10
- [#2287](https://github.com/sanic-org/sanic/pull/2287) Update host test function names so they are not overwritten
- [#2292](https://github.com/sanic-org/sanic/pull/2292) Fail CI on error
- [#2311](https://github.com/sanic-org/sanic/pull/2311), [#2324](https://github.com/sanic-org/sanic/pull/2324) Do not run tests for draft PRs
- [#2336](https://github.com/sanic-org/sanic/pull/2336) Remove paths from coverage checks
- [#2338](https://github.com/sanic-org/sanic/pull/2338) Cleanup ports on tests

### Improved Documentation
- [#2269](https://github.com/sanic-org/sanic/pull/2269), [#2329](https://github.com/sanic-org/sanic/pull/2329), [#2333](https://github.com/sanic-org/sanic/pull/2333) Cleanup typos and fix language

### Miscellaneous
- [#2257](https://github.com/sanic-org/sanic/pull/2257), [#2294](https://github.com/sanic-org/sanic/pull/2294), [#2341](https://github.com/sanic-org/sanic/pull/2341) Add Python 3.10 support
- [#2279](https://github.com/sanic-org/sanic/pull/2279), [#2317](https://github.com/sanic-org/sanic/pull/2317), [#2322](https://github.com/sanic-org/sanic/pull/2322) Add/correct missing type annotations
- [#2305](https://github.com/sanic-org/sanic/pull/2305) Fix examples to use modern implementations

---

### Sanic Releases 21 21.9 (`docs/sanic/releases/21/21.9.md`)

## Version 21.9.3
*Rerelease of v21.9.2 with some cleanup*

## Version 21.9.2
- [#2268](https://github.com/sanic-org/sanic/pull/2268) Make HTTP connections start in IDLE stage, avoiding delays and error messages
- [#2310](https://github.com/sanic-org/sanic/pull/2310) More consistent config setting with post-FALLBACK_ERROR_FORMAT apply

## Version 21.9.1
- [#2259](https://github.com/sanic-org/sanic/pull/2259) Allow non-conforming ErrorHandlers

## Version 21.9.0

### Features
- [#2158](https://github.com/sanic-org/sanic/pull/2158), [#2248](https://github.com/sanic-org/sanic/pull/2248) Complete overhaul of I/O to websockets
- [#2160](https://github.com/sanic-org/sanic/pull/2160) Add new 17 signals into server and request lifecycles
- [#2162](https://github.com/sanic-org/sanic/pull/2162) Smarter `auto` fallback formatting upon exception
- [#2184](https://github.com/sanic-org/sanic/pull/2184) Introduce implementation for copying a Blueprint
- [#2200](https://github.com/sanic-org/sanic/pull/2200) Accept header parsing
- [#2207](https://github.com/sanic-org/sanic/pull/2207) Log remote address if available
- [#2209](https://github.com/sanic-org/sanic/pull/2209) Add convenience methods to BP groups
- [#2216](https://github.com/sanic-org/sanic/pull/2216) Add default messages to SanicExceptions
- [#2225](https://github.com/sanic-org/sanic/pull/2225) Type annotation convenience for annotated handlers with path parameters
- [#2236](https://github.com/sanic-org/sanic/pull/2236) Allow Falsey (but not-None) responses from route handlers
- [#2238](https://github.com/sanic-org/sanic/pull/2238) Add `exception` decorator to Blueprint Groups
- [#2244](https://github.com/sanic-org/sanic/pull/2244) Explicit static directive for serving file or dir (ex: `static(..., resource_type="file")`)
- [#2245](https://github.com/sanic-org/sanic/pull/2245) Close HTTP loop when connection task cancelled

### Bugfixes
- [#2188](https://github.com/sanic-org/sanic/pull/2188) Fix the handling of the end of a chunked request
- [#2195](https://github.com/sanic-org/sanic/pull/2195) Resolve unexpected error handling on static requests
- [#2208](https://github.com/sanic-org/sanic/pull/2208) Make blueprint-based exceptions attach and trigger in a more intuitive manner
- [#2211](https://github.com/sanic-org/sanic/pull/2211) Fixed for handling exceptions of asgi app call
- [#2213](https://github.com/sanic-org/sanic/pull/2213) Fix bug where ws exceptions not being logged
- [#2231](https://github.com/sanic-org/sanic/pull/2231) Cleaner closing of tasks by using `abort()` in strategic places to avoid dangling sockets
- [#2247](https://github.com/sanic-org/sanic/pull/2247) Fix logging of auto-reload status in debug mode
- [#2246](https://github.com/sanic-org/sanic/pull/2246) Account for BP with exception handler but no routes

### Developer infrastructure  
- [#2194](https://github.com/sanic-org/sanic/pull/2194) HTTP unit tests with raw client
- [#2199](https://github.com/sanic-org/sanic/pull/2199) Switch to codeclimate
- [#2214](https://github.com/sanic-org/sanic/pull/2214) Try Reopening Windows Tests
- [#2229](https://github.com/sanic-org/sanic/pull/2229) Refactor `HttpProtocol` into a base class
- [#2230](https://github.com/sanic-org/sanic/pull/2230) Refactor `server.py` into multi-file module

### Miscellaneous
- [#2173](https://github.com/sanic-org/sanic/pull/2173) Remove Duplicated Dependencies and PEP 517 Support 
- [#2193](https://github.com/sanic-org/sanic/pull/2193), [#2196](https://github.com/sanic-org/sanic/pull/2196), [#2217](https://github.com/sanic-org/sanic/pull/2217) Type annotation changes

---

### Sanic Releases 22 22.12 (`docs/sanic/releases/22/22.12.md`)

## Version 22.12.0 🔷

_Current version_

### Features

- [#2569](https://github.com/sanic-org/sanic/pull/2569) Add `JSONResponse` class with some convenient methods when updating a response object
- [#2598](https://github.com/sanic-org/sanic/pull/2598) Change `uvloop` requirement to `>=0.15.0`
- [#2609](https://github.com/sanic-org/sanic/pull/2609) Add compatibility with `websockets` v11.0
- [#2610](https://github.com/sanic-org/sanic/pull/2610) Kill server early on worker error
    - Raise deadlock timeout to 30s
- [#2617](https://github.com/sanic-org/sanic/pull/2617) Scale number of running server workers
- [#2621](https://github.com/sanic-org/sanic/pull/2621) [#2634](https://github.com/sanic-org/sanic/pull/2634) Send `SIGKILL` on subsequent `ctrl+c` to force worker exit
- [#2622](https://github.com/sanic-org/sanic/pull/2622) Add API to restart all workers from the multiplexer
- [#2624](https://github.com/sanic-org/sanic/pull/2624) Default to `spawn` for all subprocesses unless specifically set:
    ```python
    from sanic import Sanic
    
    Sanic.start_method = "fork"
    ```
- [#2625](https://github.com/sanic-org/sanic/pull/2625) Filename normalisation of form-data/multipart file uploads
- [#2626](https://github.com/sanic-org/sanic/pull/2626) Move to HTTP Inspector:
    - Remote access to inspect running Sanic instances
    - TLS support for encrypted calls to Inspector
    - Authentication to Inspector with API key
    - Ability to extend Inspector with custom commands
- [#2632](https://github.com/sanic-org/sanic/pull/2632) Control order of restart operations
- [#2633](https://github.com/sanic-org/sanic/pull/2633) Move reload interval to class variable
- [#2636](https://github.com/sanic-org/sanic/pull/2636) Add `priority` to `register_middleware` method
- [#2639](https://github.com/sanic-org/sanic/pull/2639) Add `unquote` to `add_route` method
- [#2640](https://github.com/sanic-org/sanic/pull/2640) ASGI websockets to receive `text` or `bytes`


### Bugfixes

- [#2607](https://github.com/sanic-org/sanic/pull/2607) Force socket shutdown before close to allow rebinding
- [#2590](https://github.com/sanic-org/sanic/pull/2590) Use actual `StrEnum` in Python 3.11+
- [#2615](https://github.com/sanic-org/sanic/pull/2615) Ensure middleware executes only once per request timeout
- [#2627](https://github.com/sanic-org/sanic/pull/2627) Crash ASGI application on lifespan failure
- [#2635](https://github.com/sanic-org/sanic/pull/2635) Resolve error with low-level server creation on Windows


### Deprecations and Removals

- [#2608](https://github.com/sanic-org/sanic/pull/2608) [#2630](https://github.com/sanic-org/sanic/pull/2630) Signal conditions and triggers saved on `signal.extra` 
- [#2626](https://github.com/sanic-org/sanic/pull/2626) Move to HTTP Inspector
    - 🚨 *BREAKING CHANGE*: Moves the Inspector to a Sanic app from a simple TCP socket with a custom protocol
    - *DEPRECATE*: The `--inspect*` commands have been deprecated in favor of `inspect ...` commands
- [#2628](https://github.com/sanic-org/sanic/pull/2628) Replace deprecated `distutils.strtobool`


### Developer infrastructure

- [#2612](https://github.com/sanic-org/sanic/pull/2612) Add CI testing for Python 3.11

---

### Sanic Releases 22 22.3 (`docs/sanic/releases/22/22.3.md`)

## Version 22.3.0

### Features
- [#2347](https://github.com/sanic-org/sanic/pull/2347) API for multi-application server
    - 🚨 *BREAKING CHANGE*: The old `sanic.worker.GunicornWorker` has been **removed**. To run Sanic with `gunicorn`, you should use it thru `uvicorn` [as described in their docs](https://www.uvicorn.org/#running-with-gunicorn).
    - 🧁 *SIDE EFFECT*: Named background tasks are now supported, even in Python 3.7
- [#2357](https://github.com/sanic-org/sanic/pull/2357) Parse `Authorization` header as `Request.credentials`
- [#2361](https://github.com/sanic-org/sanic/pull/2361) Add config option to skip `Touchup` step in application startup
- [#2372](https://github.com/sanic-org/sanic/pull/2372) Updates to CLI help messaging
- [#2382](https://github.com/sanic-org/sanic/pull/2382) Downgrade warnings to backwater debug messages 
- [#2396](https://github.com/sanic-org/sanic/pull/2396) Allow for `multidict` v0.6
- [#2401](https://github.com/sanic-org/sanic/pull/2401) Upgrade CLI catching for alternative application run types
- [#2402](https://github.com/sanic-org/sanic/pull/2402) Conditionally inject CLI arguments into factory
- [#2413](https://github.com/sanic-org/sanic/pull/2413) Add new start and stop event listeners to reloader process
- [#2414](https://github.com/sanic-org/sanic/pull/2414) Remove loop as required listener arg
- [#2415](https://github.com/sanic-org/sanic/pull/2415) Better exception for bad URL parsing
- [sanic-routing#47](https://github.com/sanic-org/sanic-routing/pull/47) Add a new extention parameter type: `<file:ext>`, `<file:ext=jpg>`, `<file:ext=jpg|png|gif|svg>`, `<file=int:ext>`, `<file=int:ext=jpg|png|gif|svg>`, `<file=float:ext=tar.gz>`
    - 👶 *BETA FEATURE*: This feature will not work with `path` type matching, and is being released as a beta feature only.
- [sanic-routing#57](https://github.com/sanic-org/sanic-routing/pull/57) Change `register_pattern` to accept a `str` or `Pattern`
- [sanic-routing#58](https://github.com/sanic-org/sanic-routing/pull/58) Default matching on non-empty strings only, and new `strorempty` pattern type
    - 🚨 *BREAKING CHANGE*: Previously a route with a dynamic string parameter (`/<foo>` or `/<foo:str>`) would match on any string, including empty strings. It will now **only** match a non-empty string. To retain the old behavior, you should use the new parameter type: `/<foo:strorempty>`.

### Bugfixes
- [#2373](https://github.com/sanic-org/sanic/pull/2373) Remove `error_logger` on websockets
- [#2381](https://github.com/sanic-org/sanic/pull/2381) Fix newly assigned `None` in task registry
- [sanic-routing#52](https://github.com/sanic-org/sanic-routing/pull/52) Add type casting to regex route matching
- [sanic-routing#60](https://github.com/sanic-org/sanic-routing/pull/60) Add requirements check on regex routes (this resolves, for example, multiple static directories with differing `host` values)

### Deprecations and Removals
- [#2362](https://github.com/sanic-org/sanic/pull/2362) 22.3 Deprecations and changes
    1. `debug=True` and `--debug` do _NOT_ automatically run `auto_reload`
    2. Default error render is with plain text (browsers still get HTML by default because `auto` looks at headers)
    3. `config` is required for `ErrorHandler.finalize`
    4. `ErrorHandler.lookup` requires two positional args
    5. Unused websocket protocol args removed
- [#2344](https://github.com/sanic-org/sanic/pull/2344) Deprecate loading of lowercase environment variables

### Developer infrastructure
- [#2363](https://github.com/sanic-org/sanic/pull/2363) Revert code coverage back to Codecov
- [#2405](https://github.com/sanic-org/sanic/pull/2405) Upgrade tests for `sanic-routing` changes
- [sanic-testing#35](https://github.com/sanic-org/sanic-testing/pull/35) Allow for httpx v0.22

### Improved Documentation
- [#2350](https://github.com/sanic-org/sanic/pull/2350) Fix link in README for ASGI
- [#2398](https://github.com/sanic-org/sanic/pull/2398) Document middleware on_request and on_response
- [#2409](https://github.com/sanic-org/sanic/pull/2409) Add missing documentation for `Request.respond`

### Miscellaneous
- [#2376](https://github.com/sanic-org/sanic/pull/2376) Fix typing for `ListenerMixin.listener`
- [#2383](https://github.com/sanic-org/sanic/pull/2383) Clear deprecation warning in `asyncio.wait`
- [#2387](https://github.com/sanic-org/sanic/pull/2387) Cleanup `__slots__` implementations
- [#2390](https://github.com/sanic-org/sanic/pull/2390) Clear deprecation warning in `asyncio.get_event_loop`

---

### Sanic Releases 22 22.6 (`docs/sanic/releases/22/22.6.md`)

## Version 22.6.2

### Bugfixes

- [#2522](https://github.com/sanic-org/sanic/pull/2522) Always show server location in ASGI

## Version 22.6.1

### Bugfixes

- [#2477](https://github.com/sanic-org/sanic/pull/2477) Sanic static directory fails when folder name ends with ".."


## Version 22.6.0

### Features
- [#2378](https://github.com/sanic-org/sanic/pull/2378) Introduce HTTP/3 and autogeneration of TLS certificates in `DEBUG` mode
    - 👶 *EARLY RELEASE FEATURE*: Serving Sanic over HTTP/3 is an early release feature. It does not yet fully cover the HTTP/3 spec, but instead aims for feature parity with Sanic's existing HTTP/1.1 server. Websockets, WebTransport, push responses are examples of some features not yet implemented.
    - 📦 *EXTRA REQUIREMENT*: Not all HTTP clients are capable of interfacing with HTTP/3 servers. You may need to install a [HTTP/3 capable client](https://curl.se/docs/http3.html).
    - 📦 *EXTRA REQUIREMENT*: In order to use TLS autogeneration, you must install either [mkcert](https://github.com/FiloSottile/mkcert) or [trustme](https://github.com/python-trio/trustme).
- [#2416](https://github.com/sanic-org/sanic/pull/2416) Add message to `task.cancel`
- [#2420](https://github.com/sanic-org/sanic/pull/2420) Add exception aliases for more consistent naming with standard HTTP response types (`BadRequest`, `MethodNotAllowed`, `RangeNotSatisfiable`)
- [#2432](https://github.com/sanic-org/sanic/pull/2432) Expose ASGI `scope` as a property on the `Request` object
- [#2438](https://github.com/sanic-org/sanic/pull/2438) Easier access to websocket class for annotation: `from sanic import Websocket`
- [#2439](https://github.com/sanic-org/sanic/pull/2439) New API for reading form values with options: `Request.get_form` 
- [#2445](https://github.com/sanic-org/sanic/pull/2445) Add custom `loads` function
- [#2447](https://github.com/sanic-org/sanic/pull/2447), [#2486](https://github.com/sanic-org/sanic/pull/2486) Improved API to support setting cache control headers
- [#2453](https://github.com/sanic-org/sanic/pull/2453) Move verbosity filtering to logger
- [#2475](https://github.com/sanic-org/sanic/pull/2475) Expose getter for current request using `Request.get_current()`

### Bugfixes
- [#2448](https://github.com/sanic-org/sanic/pull/2448) Fix to allow running with `pythonw.exe` or places where there is no `sys.stdout`
- [#2451](https://github.com/sanic-org/sanic/pull/2451) Trigger `http.lifecycle.request` signal in ASGI mode
- [#2455](https://github.com/sanic-org/sanic/pull/2455) Resolve typing of stacked route definitions
- [#2463](https://github.com/sanic-org/sanic/pull/2463) Properly catch websocket CancelledError in websocket handler in Python 3.7

### Deprecations and Removals
- [#2487](https://github.com/sanic-org/sanic/pull/2487) v22.6 deprecations and changes
    1. Optional application registry
    1. Execution of custom handlers after some part of response was sent
    1. Configuring fallback handlers on the `ErrorHandler`
    1. Custom `LOGO` setting
    1. `sanic.response.stream`
    1. `AsyncioServer.init`

### Developer infrastructure
- [#2449](https://github.com/sanic-org/sanic/pull/2449) Clean up `black` and `isort` config
- [#2479](https://github.com/sanic-org/sanic/pull/2479) Fix some flappy tests

### Improved Documentation
- [#2461](https://github.com/sanic-org/sanic/pull/2461) Update example to match current application naming standards
- [#2466](https://github.com/sanic-org/sanic/pull/2466) Better type annotation for `Extend`
- [#2485](https://github.com/sanic-org/sanic/pull/2485) Improved help messages in CLI

---

### Sanic Releases 22 22.9 (`docs/sanic/releases/22/22.9.md`)

## Version 22.9.1

### Features

- [#2585](https://github.com/sanic-org/sanic/pull/2585) Improved error message when no applications have been registered


### Bugfixes

- [#2578](https://github.com/sanic-org/sanic/pull/2578) Add certificate loader for in process certificate creation
- [#2591](https://github.com/sanic-org/sanic/pull/2591) Do not use sentinel identity for `spawn` compatibility
- [#2592](https://github.com/sanic-org/sanic/pull/2592) Fix properties in nested blueprint groups
- [#2595](https://github.com/sanic-org/sanic/pull/2595) Introduce sleep interval on new worker reloader


### Deprecations and Removals


### Developer infrastructure

- [#2588](https://github.com/sanic-org/sanic/pull/2588) Markdown templates on issue forms


### Improved Documentation

- [#2556](https://github.com/sanic-org/sanic/pull/2556) v22.9 documentation
- [#2582](https://github.com/sanic-org/sanic/pull/2582) Cleanup documentation on Windows support


## Version 22.9.0

### Features

- [#2445](https://github.com/sanic-org/sanic/pull/2445) Add custom loads function 
- [#2490](https://github.com/sanic-org/sanic/pull/2490) Make `WebsocketImplProtocol` async iterable
- [#2499](https://github.com/sanic-org/sanic/pull/2499) Sanic Server WorkerManager refactor
- [#2506](https://github.com/sanic-org/sanic/pull/2506) Use `pathlib` for path resolution (for static file serving)
- [#2508](https://github.com/sanic-org/sanic/pull/2508) Use `path.parts` instead of `match` (for static file serving)
- [#2513](https://github.com/sanic-org/sanic/pull/2513) Better request cancel handling
- [#2516](https://github.com/sanic-org/sanic/pull/2516) Add request properties for HTTP method info:
    - `request.is_safe`
    - `request.is_idempotent`
    - `request.is_cacheable`
    - *See* [MDN docs](https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods) *for more information about when these apply*
- [#2522](https://github.com/sanic-org/sanic/pull/2522) Always show server location in ASGI
- [#2526](https://github.com/sanic-org/sanic/pull/2526) Cache control support for static files for returning 304 when appropriate
- [#2533](https://github.com/sanic-org/sanic/pull/2533) Refactor `_static_request_handler`
- [#2540](https://github.com/sanic-org/sanic/pull/2540) Add signals before and after handler execution
    - `http.handler.before`
    - `http.handler.after`
- [#2542](https://github.com/sanic-org/sanic/pull/2542) Add *[redacted]* to CLI :)
- [#2546](https://github.com/sanic-org/sanic/pull/2546) Add deprecation warning filter
- [#2550](https://github.com/sanic-org/sanic/pull/2550) Middleware priority and performance enhancements

### Bugfixes

- [#2495](https://github.com/sanic-org/sanic/pull/2495) Prevent directory traversion with static files
- [#2515](https://github.com/sanic-org/sanic/pull/2515) Do not apply double slash to paths in certain static dirs in Blueprints

### Deprecations and Removals

- [#2525](https://github.com/sanic-org/sanic/pull/2525) Warn on duplicate route names, will be prevented outright in v23.3
- [#2537](https://github.com/sanic-org/sanic/pull/2537) Raise warning and deprecation notice on duplicate exceptions, will be prevented outright in v23.3

### Developer infrastructure

- [#2504](https://github.com/sanic-org/sanic/pull/2504) Cleanup test suite
- [#2505](https://github.com/sanic-org/sanic/pull/2505) Replace Unsupported Python Version Number from the Contributing Doc
- [#2530](https://github.com/sanic-org/sanic/pull/2530) Do not include tests folder in installed package resolver

### Improved Documentation

- [#2502](https://github.com/sanic-org/sanic/pull/2502) Fix a few typos
- [#2517](https://github.com/sanic-org/sanic/pull/2517) [#2536](https://github.com/sanic-org/sanic/pull/2536) Add some type hints

---

### Sanic Releases 23 23.3 (`docs/sanic/releases/23/23.3.md`)

## Version 23.3.0

### Features
- [#2545](https://github.com/sanic-org/sanic/pull/2545) Standardize init of exceptions for more consistent control of HTTP responses using exceptions
- [#2606](https://github.com/sanic-org/sanic/pull/2606) Decode headers as UTF-8 also in ASGI
- [#2646](https://github.com/sanic-org/sanic/pull/2646) Separate ASGI request and lifespan callables
- [#2659](https://github.com/sanic-org/sanic/pull/2659) Use ``FALLBACK_ERROR_FORMAT`` for handlers that return ``empty()``
- [#2662](https://github.com/sanic-org/sanic/pull/2662) Add basic file browser (HTML page) and auto-index serving
- [#2667](https://github.com/sanic-org/sanic/pull/2667) Nicer traceback formatting (HTML page)
- [#2668](https://github.com/sanic-org/sanic/pull/2668) Smarter error page rendering format selection; more reliant upon header and "common sense" defaults
- [#2680](https://github.com/sanic-org/sanic/pull/2680) Check the status of socket before shutting down with ``SHUT_RDWR``
- [#2687](https://github.com/sanic-org/sanic/pull/2687) Refresh ``Request.accept`` functionality to be more performant and spec-compliant
- [#2696](https://github.com/sanic-org/sanic/pull/2696) Add header accessors as properties
    ```
    Example-Field: Foo, Bar
    Example-Field: Baz
    ```
    ```python
    request.headers.example_field == "Foo, Bar,Baz"
    ```
- [#2700](https://github.com/sanic-org/sanic/pull/2700) Simpler CLI targets

    ```sh
    $ sanic path.to.module:app          # global app instance
    $ sanic path.to.module:create_app   # factory pattern
    $ sanic ./path/to/directory/        # simple serve
    ```
- [#2701](https://github.com/sanic-org/sanic/pull/2701) API to define a number of workers in managed processes
- [#2704](https://github.com/sanic-org/sanic/pull/2704) Add convenience for dynamic changes to routing
- [#2706](https://github.com/sanic-org/sanic/pull/2706) Add convenience methods for cookie creation and deletion
    
    ```python
    response = text("...")
    response.add_cookie("test", "It worked!", domain=".yummy-yummy-cookie.com")
    ```
- [#2707](https://github.com/sanic-org/sanic/pull/2707) Simplified ``parse_content_header`` escaping to be RFC-compliant and remove outdated FF hack
- [#2710](https://github.com/sanic-org/sanic/pull/2710) Stricter charset handling and escaping of request URLs
- [#2711](https://github.com/sanic-org/sanic/pull/2711) Consume body on ``DELETE`` by default
- [#2719](https://github.com/sanic-org/sanic/pull/2719) Allow ``password`` to be passed to TLS context
- [#2720](https://github.com/sanic-org/sanic/pull/2720) Skip middleware on ``RequestCancelled``
- [#2721](https://github.com/sanic-org/sanic/pull/2721) Change access logging format to ``%s``
- [#2722](https://github.com/sanic-org/sanic/pull/2722) Add ``CertLoader`` as application option for directly controlling ``SSLContext`` objects
- [#2725](https://github.com/sanic-org/sanic/pull/2725) Worker sync state tolerance on race condition

### Bugfixes
- [#2651](https://github.com/sanic-org/sanic/pull/2651) ASGI websocket to pass thru bytes as is
- [#2697](https://github.com/sanic-org/sanic/pull/2697) Fix comparison between datetime aware and naive in ``file`` when using ``If-Modified-Since``

### Deprecations and Removals
- [#2666](https://github.com/sanic-org/sanic/pull/2666) Remove deprecated ``__blueprintname__`` property

### Improved Documentation
- [#2712](https://github.com/sanic-org/sanic/pull/2712) Improved example using ``'https'`` to create the redirect

---

### Sanic Releases 23 23.6 (`docs/sanic/releases/23/23.6.md`)

## Version 23.6.0  🔶

### Features
- [#2670](https://github.com/sanic-org/sanic/pull/2670) Increase `KEEP_ALIVE_TIMEOUT` default to 120 seconds
- [#2716](https://github.com/sanic-org/sanic/pull/2716) Adding allow route overwrite option in blueprint
- [#2724](https://github.com/sanic-org/sanic/pull/2724) and [#2792](https://github.com/sanic-org/sanic/pull/2792) Add a new exception signal for ALL exceptions raised anywhere in application
- [#2727](https://github.com/sanic-org/sanic/pull/2727) Add name prefixing to BP groups
- [#2754](https://github.com/sanic-org/sanic/pull/2754) Update request type on middleware types
- [#2770](https://github.com/sanic-org/sanic/pull/2770) Better exception message on startup time application induced import error
- [#2776](https://github.com/sanic-org/sanic/pull/2776) Set multiprocessing start method early
- [#2785](https://github.com/sanic-org/sanic/pull/2785) Add custom typing to config and ctx objects
- [#2790](https://github.com/sanic-org/sanic/pull/2790) Add `request.client_ip`

### Bugfixes
- [#2728](https://github.com/sanic-org/sanic/pull/2728) Fix traversals for intended results
- [#2729](https://github.com/sanic-org/sanic/pull/2729) Handle case when headers argument of ResponseStream constructor is None
- [#2737](https://github.com/sanic-org/sanic/pull/2737) Fix type annotation for `JSONREsponse` default content type
- [#2740](https://github.com/sanic-org/sanic/pull/2740) Use Sanic's serializer for JSON responses in the Inspector
- [#2760](https://github.com/sanic-org/sanic/pull/2760) Support for `Request.get_current` in ASGI mode
- [#2773](https://github.com/sanic-org/sanic/pull/2773) Alow Blueprint routes to explicitly define error_format
- [#2774](https://github.com/sanic-org/sanic/pull/2774) Resolve headers on different renderers
- [#2782](https://github.com/sanic-org/sanic/pull/2782) Resolve pypy compatibility issues

### Deprecations and Removals
- [#2777](https://github.com/sanic-org/sanic/pull/2777) Remove Python 3.7 support

### Developer infrastructure
- [#2766](https://github.com/sanic-org/sanic/pull/2766) Unpin setuptools version
- [#2779](https://github.com/sanic-org/sanic/pull/2779) Run keep alive tests in loop to get available port

### Improved Documentation
- [#2741](https://github.com/sanic-org/sanic/pull/2741) Better documentation examples about running Sanic
From that list, the items to highlight in the release notes:

---

### Guide Content En Guide Introduction (`guide/content/en/guide/introduction.md`)

# Introduction

Sanic is a Python 3.10+ web server and web framework that's written to go fast. It allows the usage of the async/await syntax added in Python 3.5, which makes your code non-blocking and speedy.

.. attrs::
    :class: introduction-table

    |  |  |
    |--|--|
    | Build    | [](https://github.com/sanic-org/sanic/actions/workflows/tests.yml) |
    | Docs     | [](https://sanicframework.org/) [](http://sanic.readthedocs.io/en/latest/?badge=latest) |
    | Package  | [](https://pypi.python.org/pypi/sanic/) [](https://pypi.python.org/pypi/sanic/) [](https://pypi.python.org/pypi/sanic) [](https://pypi.python.org/pypi/sanic) [](https://github.com/ambv/black) |
    | Support  | [](https://community.sanicframework.org/) [](https://discord.gg/FARQzAEMAA) [](https://github.com/mekicha/awesome-sanic) |
    | Stats    | [](https://pepy.tech/project/sanic) [](https://pepy.tech/project/sanic) [](https://anaconda.org/conda-forge/sanic) |



## What is it?

First things first, before you jump in the water, you should know that Sanic is different than other frameworks.

Right there in that first sentence there is a huge mistake because Sanic is _both_ a **framework** and a **web server**. In the deployment section we will talk a little bit more about this. 

But, remember, out of the box Sanic comes with everything you need to write, deploy, and scale a production grade web application. 🚀

## Goal

> To provide a simple way to get up and running a highly performant HTTP server that is easy to build, to expand, and ultimately to scale.
## Features

.. column::

    ### Core

    - Built in, **_fast_** web server
    - Production ready
    - Highly scalable
    - ASGI compliant
    - Simple and intuitive API design
    - By the community, for the community

.. column::

    ### Sanic Extensions [[learn more](../plugins/sanic-ext/getting-started.md)]

    - CORS protection
    - Template rendering with Jinja
    - Dependency injection into route handlers
    - OpenAPI documentation with Redoc and/or Swagger
    - Predefined, endpoint-specific response serializers
    - Request query arguments and body input validation
    - Auto create `HEAD`, `OPTIONS`, and `TRACE` endpoints

## Sponsor

Check out [open collective](https://opencollective.com/sanic-org) to learn more about helping to fund Sanic.


## Join the Community

The main channel for discussion is at the [community forums](https://community.sanicframework.org/). There also is a [Discord Server](https://discord.gg/FARQzAEMAA) for live discussion and chat.

The Stackoverflow `[sanic]` tag is [actively monitored](https://stackoverflow.com/questions/tagged/sanic) by project maintainers.

## Contribution

We are always happy to have new contributions. We have [marked issues good for anyone looking to get started](https://github.com/sanic-org/sanic/issues?q=is%3Aopen+is%3Aissue+label%3Abeginner), and welcome [questions/answers/discussion on the forums](https://community.sanicframework.org/). Please take a look at our [Contribution guidelines](https://github.com/sanic-org/sanic/blob/master/CONTRIBUTING.rst).

---

### Guide Content En Organization Code Of Conduct (`guide/content/en/organization/code-of-conduct.md`)

# Contributor Covenant Code of Conduct

## Our Pledge

In the interest of fostering an open and welcoming environment, we as
contributors and maintainers pledge to making participation in our project and
our community a harassment-free experience for everyone, regardless of age, body
size, disability, ethnicity, gender identity and expression, level of experience,
nationality, personal appearance, race, religion, or sexual identity and
orientation.

## Our Standards

Examples of behavior that contributes to creating a positive environment
include:

* Using welcoming and inclusive language
* Being respectful of differing viewpoints and experiences
* Gracefully accepting constructive criticism
* Focusing on what is best for the community
* Showing empathy towards other community members

Examples of unacceptable behavior by participants include:

* The use of sexualized language or imagery and unwelcome sexual attention or
advances
* Trolling, insulting/derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or electronic
  address, without explicit permission
* Other conduct which could reasonably be considered inappropriate in a
  professional setting

## Our Responsibilities

Project maintainers are responsible for clarifying the standards of acceptable
behavior and are expected to take appropriate and fair corrective action in
response to any instances of unacceptable behavior.

Project maintainers have the right and responsibility to remove, edit, or
reject comments, commits, code, wiki edits, issues, and other contributions
that are not aligned to this Code of Conduct, or to ban temporarily or
permanently any contributor for other behaviors that they deem inappropriate,
threatening, offensive, or harmful.

## Scope

This Code of Conduct applies both within project spaces and in public spaces
when an individual is representing the project or its community. Examples of
representing a project or community include using an official project e-mail
address, posting via an official social media account, or acting as an appointed
representative at an online or offline event. Representation of a project may be
further defined and clarified by project maintainers.

## Enforcement

Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported by contacting the project team at adam@sanicframework.org. All
complaints will be reviewed and investigated and will result in a response that
is deemed necessary and appropriate to the circumstances. The project team is
obligated to maintain confidentiality with regard to the reporter of an incident.
Further details of specific enforcement policies may be posted separately.

Project maintainers who do not follow or enforce the Code of Conduct in good
faith may face temporary or permanent repercussions as determined by other
members of the project's leadership.

## Attribution

This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
available at [http://contributor-covenant.org/version/1/4][version]

[homepage]: http://contributor-covenant.org
[version]: http://contributor-covenant.org/version/1/4/

---

### Guide Content En Organization Contributing (`guide/content/en/organization/contributing.md`)

# Contributing

Thank you for your interest! Sanic is always looking for contributors. If you don't feel comfortable contributing code, adding docstrings to the source files, or helping with the [Sanic User Guide](https://github.com/sanic-org/sanic-guide) by providing documentation or implementation examples would be appreciated!

We are committed to providing a friendly, safe and welcoming environment for all, regardless of gender, sexual orientation, disability, ethnicity, religion, or similar personal characteristic. Our [code of conduct](https://github.com/sanic-org/sanic/blob/master/CONDUCT.md) sets the standards for behavior.

## Installation

To develop on Sanic (and mainly to just run the tests) it is highly recommend to install from sources.

So assume you have already cloned the repo and are in the working directory with a virtual environment already set up, then run:

```sh
pip install -e ".[dev]"
```

## Dependency Changes

`Sanic` doesn't use `requirements*.txt` files to manage any kind of dependencies related to it in order to simplify the effort required in managing the dependencies. Please make sure you have read and understood the following section of the document that explains the way `sanic` manages dependencies inside the `setup.py` file.

| Dependency Type                 | Usage                                             | Installation                 |
| ------------------------------- | ------------------------------------------------- | ---------------------------- |
| requirements                    | Bare minimum dependencies required for sanic to function | `pip3 install -e .`         |
| tests_require / extras_require['test'] | Dependencies required to run the Unit Tests for `sanic` | `pip3 install -e '.[test]'` |
| extras_require['dev']           | Additional Development requirements to add contributing | `pip3 install -e '.[dev]'`  |
| extras_require['docs']          | Dependencies required to enable building and enhancing sanic documentation | `pip3 install -e '.[docs]'` |

## Running all tests

To run the tests for Sanic it is recommended to use tox like so:

```sh
tox
```

See it's that simple!

`tox.ini` contains different environments. Running `tox` without any arguments will
run all unittests, perform lint and other checks.

## Run unittests

`tox` environment -> `[testenv]`

To execute only unittests, run `tox` with environment like so:

```sh

tox -e py37 -v -- tests/test_config.py
# or
tox -e py310 -v -- tests/test_config.py
```

## Run lint checks

`tox` environment -> `[testenv:lint]`

Permform `flake8`\ , `black` and `isort` checks.


```sh
tox -e lint
```

## Run type annotation checks

`tox` environment -> `[testenv:type-checking]`

Permform `mypy` checks.

```sh
tox -e type-checking
```

## Run other checks

`tox` environment -> `[testenv:check]`

Perform other checks.

```sh
tox -e check
```

## Run Static Analysis

`tox` environment -> `[testenv:security]`

Perform static analysis security scan

```sh
tox -e security
```

## Run Documentation sanity check

`tox` environment -> `[testenv:docs]`

Perform sanity check on documentation

```sh
tox -e docs
```
## Code Style

To maintain the code consistency, Sanic uses the following tools:

1. [isort](https://github.com/timothycrosley/isort)
2. [black](https://github.com/python/black)
3. [flake8](https://github.com/PyCQA/flake8)
4. [slotscheck](https://github.com/ariebovenberg/slotscheck)

### isort

`isort` sorts Python imports. It divides imports into three categories sorted each in alphabetical order:

1. built-in
2. third-party
3. project-specific

### black

`black` is a Python code formatter.

### flake8

`flake8` is a Python style guide that wraps the following tools into one:

1. PyFlakes
2. pycodestyle
3. Ned Batchelder's McCabe script

### slotscheck

`slotscheck` ensures that there are no problems with `__slots__` (e.g., overlaps, or missing slots in base classes).

`isort`, `black`, `flake8`, and `slotscheck` checks are performed during `tox` lint checks.

The **easiest** way to make your code conform is to run the following before committing:

```bash
make pretty
```

Refer to [tox documentation](https://tox.readthedocs.io/en/latest/index.html) for more details.

## Pull requests

So the pull request approval rules are pretty simple:

1. All pull requests must pass unit tests.
2. All pull requests must be reviewed and approved by at least one current member of the Core Developer team.
3. All pull requests must pass flake8 checks.
4. All pull requests must match `isort` and `black` requirements.
5. All pull requests must be **PROPERLY** type annotated, unless exemption is given.
6. All pull requests must be consistent with the existing code.
7. If you decide to remove/change anything from any common interface a deprecation message should accompany it in accordance with our [deprecation policy](https://sanicframework.org/en/guide/project/policies.html#deprecation).
8. If you implement a new feature you should have at least one unit test to accompany it.
9. An example must be one of the following:
    * Example of how to use Sanic
    * Example of how to use Sanic extensions
    * Example of how to use Sanic and asynchronous library

## Documentation

_Check back. We are reworking our documentation so this will change._

---

### Guide Content En Organization Policies (`guide/content/en/organization/policies.md`)

# Policies

## Versioning

Sanic uses [calendar versioning](https://calver.org/), aka "calver". To be more specific, the pattern follows:

```
YY.MM.MICRO
```

Generally, versions are referred to in their ``YY.MM`` form. The `MICRO` number indicates an incremental patch version, starting at `0`.

## Reporting a Vulnerability

If you discover a security vulnerability, we ask that you **do not** create an issue on GitHub. Instead, please [send a message to the core-devs](https://community.sanicframework.org/g/core-devs) on the community forums. Once logged in, you can send a message to the core-devs by clicking the message button.

Alternatively, you can send a private message to Adam Hopkins on Discord. Find him on the [Sanic discord server](https://discord.gg/FARQzAEMAA).

This will help to not publicize the issue until the team can address it and resolve it.

## Release Schedule

There are four (4) scheduled releases per year: March, June, September, and December. Therefore, there are four (4) released versions per year: `YY.3`, `YY.6`, `YY.9`, and `YY.12`. 

This release schedule provides:

- a predictable release cadence,
- relatively short development windows allowing features to be regularly released,
- controlled [deprecations](#deprecation), and
- consistent stability with a yearly LTS.

We also use the yearly release cycle in conjunction with our governance model, covered by the [S.C.O.P.E.](./scope.md)

### Long term support v Interim releases

Sanic releases a long term support release (aka "LTS") once a year in December. The LTS releases receive bug fixes and security updates for **24 months**. Interim releases throughout the year occur every three months, and are supported until the subsequent release.

| Version | Release    | LTS           | Supported       |
|---------|------------|---------------|-----------------|
| 24.12   | 2024-12-31 | until 2026-12 | ✅              |
| 24.6    | 2024-06-30 |               | ⚪              |
| 23.12   | 2023-12-31 | until 2025-12 | ☑️              |
| 23.6    | 2023-07-25 |               | ⚪              |
| 23.3    | 2023-03-26 |               | ⚪              |
| 22.12   | 2022-12-27 |               | ☑️              |
| 22.9    | 2022-09-29 |               | ⚪              |
| 22.6    | 2022-06-30 |               | ⚪              |
| 22.3    | 2022-03-31 |               | ⚪              |
| 21.12   | 2021-12-26 |               | ⚪              |
| 21.9    | 2021-09-30 |               | ⚪              |
| 21.6    | 2021-06-27 |               | ⚪              |
| 21.3    | 2021-03-21 |               | ⚪              |
| 20.12   | 2020-12-29 |               | ⚪              |
| 20.9    | 2020-09-30 |               | ⚪              |
| 20.6    | 2020-06-28 |               | ⚪              |
| 20.3    | 2020-05-14 |               | ⚪              |
| 19.12   | 2019-12-27 |               | ⚪              |
| 19.9    | 2019-10-12 |               | ⚪              |
| 19.6    | 2019-06-21 |               | ⚪              |
| 19.3    | 2019-03-23 |               | ⚪              |
| 18.12   | 2018-12-27 |               | ⚪              |
| 0.8.3   | 2018-09-13 |               | ⚪              |
| 0.7.0   | 2017-12-06 |               | ⚪              |
| 0.6.0   | 2017-08-03 |               | ⚪              |
| 0.5.4   | 2017-05-09 |               | ⚪              |
| 0.4.1   | 2017-02-28 |               | ⚪              |
| 0.3.1   | 2017-02-09 |               | ⚪              |
| 0.2.0   | 2017-01-14 |               | ⚪              |
| 0.1.9   | 2016-12-25 |               | ⚪              |
| 0.1.0   | 2016-10-16 |               | ⚪              |

☑️ = security fixes  
✅ = full support  
⚪ = no support

## Deprecation

Before a feature is deprecated, or breaking changes are introduced into the API, it shall be publicized and shall appear with deprecation warnings through two release cycles. No deprecations shall be made in an LTS release.

Breaking changes or feature removal may happen outside of these guidelines when absolutely warranted. These circumstances should be rare. For example, it might happen when no alternative is available to curtail a major security issue.

---

### Guide Content En Organization Scope (`guide/content/en/organization/scope.md`)

# Sanic Community Organization Policy E-manual (SCOPE)

.. attrs::
    :class: is-size-7

    _December 2019, version 1_

## Goals

To create a sustainable, community-driven organization around the Sanic projects that promote: (1) stability and predictability, (2) quick iteration and enhancement cycles, (3) engagement from outside contributors, (4) overall reliable software, and (5) a safe, rewarding environment for the community members.

## Overview

This Policy is the governance model for the Sanic Community Organization (“SCO”). The SCO is a meritocratic, consensus-based community organization responsible for all projects adopted by it. Anyone with an interest in one of the projects can join the community, contribute to the community or projects, and participate in the decision making process. This document describes how that participation takes place and how to set about earning merit within the project community.

## Structure

The SCO has multiple **projects**. Each project is represented by a single GitHub repository under the Sanic community umbrella. These projects are used by **users**, developed by **contributors**, governed by **core developers**, released by **release managers**, and ultimately overseen by a **steering council**. If this sounds similar to the Python project and PEP 8016 that is because it is intentionally designed that way.

## Roles and responsibilities

### Users

Users are community members who have a need for the projects. They are the developers and personnel that download and install the packages. Users are the **most important** members of the community and without them the projects would have no purpose. Anyone can be a user and the licenses adopted by the projects shall be appropriate open source licenses.

_The SCO asks its users to participate in the project and community as much as possible._

User contributions enable the project team to ensure that they are satisfying the needs of those users. Common user contributions include (but are not limited to):

*   evangelizing about the project (e.g. a link on a website and word-of-mouth awareness raising)
*   informing developers of strengths and weaknesses from a new user perspective
*   providing moral support (a ‘thank you’ goes a long way)
*   providing financial support (the software is open source, but its developers need to eat)

Users who continue to engage with the SCO, its projects, and its community will often become more and more involved. Such users may find themselves becoming contributors, as described in the next section.

### Contributors

Contributors are community members who contribute in concrete ways to one or more of the projects. Anyone can become a contributor and contributions can take many forms. Contributions and requirements are governed by each project separately by a contribution policy.

There is **no expectation** of commitment to the project, **no specific skill requirements** and **no selection process**.

In addition to their actions as users, contributors may also find themselves doing one or more of the following:

*   supporting new users (existing users are often the best people to support new users)
*   reporting bugs
*   identifying requirements
*   providing graphics and web design
*   Programming
*   example use cases
*   assisting with project infrastructure
*   writing documentation
*   fixing bugs
*   adding features
*   providing constructive opinions and engaging in community discourse

Contributors engage with the projects through GitHub and the Community Forums. They submit changes to the projects itself via pull requests, which will be considered for inclusion in the project by the community at large. The Community Forums are the most appropriate place to ask for help when making that first contribution.

Indeed one of the most important roles of a contributor may be to **simply engage in the community conversation**. Most decisions about the direction of a project are made by consensus. This is discussed in more detail below. In general, however, it is helpful for the health and direction of the projects for the contributors to **speak freely** (within the confines of the code of conduct) and **express their opinions and experiences** to help drive the consensus building.

As contributors gain experience and familiarity with a project, their profile within, and commitment to, the community will increase. At some stage, they may find themselves being nominated for a core developer team.

### Core Developer

Each project under the SCO umbrella has its own team of core developers. They are the people in charge of that project.

_What is a core developer?_

Core developers are community members who have shown that they are committed to the continued development of the project through ongoing engagement with the community. Being a core developer allows contributors to more easily carry on with their project related activities by giving them direct access to the project’s resources. They can make changes directly to the project repository without having to submit changes via pull requests from a fork.

This does not mean that a core developer is free to do what they want. In fact, core developers have no more direct authority over the final release of a package than do contributors. While this honor does indicate a valued member of the community who has demonstrated a healthy respect for the project’s aims and objectives, their work continues to be reviewed by the community before acceptance in an official release.

_What can a core developer do on a project?_

Each project might define this role slightly differently. However, the general usage of this designation is that an individual has risen to a level of trust within the community such that they now are given some control. This comes in the form of push rights to non-protected branches, and the ability to have a voice in the approval of pull requests.

The projects employ various communication mechanisms to ensure that all contributions are reviewed by the community as a whole. This includes tools provided by GitHub, as well as the Community Forums. By the time a contributor is invited to become a core developer, they should be familiar with the various tools and workflows as a user and then as a contributor.

_How to become a core developer?_

Anyone can become a core developer; there are no special requirements, other than to have shown a willingness and ability to positively participate in the project as a team player.

Typically, a potential core developer will need to show that they have an understanding of the project, its objectives and its strategy. They will also have provided valuable contributions to the project over a period of time. However, there is **no technical or other skill** requirement for eligibility.

New core developers can be **nominated by any existing core developer** at any time. At least twice a year (April and October) there will be a ballot process run by the Steering Council. Voting should be done by secret ballot. Each existing core developer for that project receives a number of votes equivalent to the number of nominees on the ballot. For example, if there are four nominees, then each existing core developer has four votes. The core developer may cast those votes however they choose, but may not vote for a single nominee more than once. A nominee must receive two-thirds approval from the number of cast ballots (not the number of eligible ballots). Once accepted by the core developers, it is the responsibility of the Steering Council to approve and finalize the nomination. The Steering Council does not have the right to determine whether a nominee is meritorious enough to receive the core developer title. However, they do retain the right to override a vote in cases where the health of the community would so require.

Once the vote has been held, the aggregated voting results are published on the Community Forums. The nominee is entitled to request an explanation of any override against them. A nominee that fails to be admitted as a core developer may be nominated again in the future.

It is important to recognize that being a core developer is a privilege, not a right. That privilege must be earned and once earned it can be removed by the Steering Council (see next section) in extreme circumstances. However, under normal circumstances the core developer title exists for as long as the individual wishes to continue engaging with the project and community.

A committer who shows an above-average level of contribution to the project, particularly with respect to its strategic direction and long-term health, may be nominated to become a member of the Steering Council, or a Release Manager. This role is described below.

_What are the rights and responsibilities of core developers?_

As discussed, the majority of decisions to be made are by consensus building. In certain circumstances where an issue has become more contentious, or a major decision needs to be made, the Release Manager or Steering Council may decide (or be required) to implement the RFC process, which is outlined in more detail below.

It is also incumbent upon core developers to have a voice in the governance of the community. All core developers for all of the projects have the ability to be nominated to be on the Steering Council and vote in their elections.

This Policy (the “SCOPE”) may only be changed under the authority of two-thirds of active core developers, except that in the first six (6) months after adoption, the core developers reserve the right to make changes under the authority of a simple majority of active core developers.

_What if a core developer becomes inactive?_

It is hoped that all core developers participate and remain active on a regular basis in their projects. However, it is also understood that such commitments may not be realistic or possible from time to time.

Therefore, the Steering Council has the duty to encourage participation and the responsibility to place core developers into an inactive status if they are no longer willing or capable to participate. The main purpose of this is **not to punish** a person for behavior, but to help the development process to continue for those that do remain active.

To this end, a core developer that becomes “inactive” shall not have commit rights to a repository, and shall not participate in any votes. To be eligible to vote in an election, a core developer **must have been active** at the time of the previous scheduled project release.

Inactive members may ask the Steering Council to reinstate their status at any time, and upon such request the Steering Council shall make the core developer active again.

Individuals that know they will be unable to maintain their active status for a period are asked to be in communication with the Steering Council and declare themselves inactive if necessary.

An “active” core developer is an individual that has participated in a meaningful way during the previous six months. Any further definition is within the discretion of the Steering Council.

### Release Manager

Core developers shall have access only to make commits and merges on non-protected branches. The “master” branch and other protected branches are controlled by the release management team for that project. Release managers shall be elected from the core development team by the core development team, and shall serve for a full release cycle.

Each core developer team may decide how many release managers to have for each release cycle. It is highly encouraged that there be at least two release managers for a release cycle to help divide the responsibilities and not force too much effort upon a single person. However, there also should not be so many managers that their efforts are impeded.

The main responsibilities of the release management team include:

*   push the development cycle forward by monitoring and facilitating technical discussions
*   establish a release calendar and perform actions required to release packages
*   approve pull requests to the master branch and other protected branches
*   merge pull requests to the master branch and other protected branches

The release managers **do not have the authority to veto or withhold a merge** of a pull request that otherwise meets contribution criteria and has been accepted by the community. It is not their responsibility to decide what should be developed, but rather that the decisions of the community are carried out and that the project is being moved forward.

From time to time, a decision may need to be made that cannot be achieved through consensus. In that case, the release managers have the authority to call upon the removal of the decision to the RFC process. This should not occur regularly (unless required as discussed below), and its use should be discouraged in favor of the more communal consensus building strategy.

Since not all projects have the same requirements, the specifics governing release managers on a project shall be set forth in an Appendix to this Policy, or in the project’s contribution guidelines.

If necessary, the Steering Council has the right to remove a release manager that is derelict in their duties, or for other good cause.

### Steering Council

The Steering Council is the governing body consisting of those individuals identified as the “project owner” and having control of the resources and assets of the SCO. Their ultimate goal is to ensure the smooth operation of the projects by removing impediments, and assisting the members as needed. It is expected that they will be regular voices in the community.

_What can the Steering Council do?_

The members of the Steering Council **do not individually have any more authority than any other core developer**, and shall not have any additional rights to make decisions, commits, merges, or the like on a project.

However, as a body, the Steering Council has the following capacity:

*   accept, remand, and reject all RFCs
*   enforce the community code of conduct
*   administer community assets such as repositories, servers, forums, integration services, and the like (or, to delegate such authority to someone else)
*   place core developers into inactive status where appropriate take any other enforcement measures afforded to it in this Policy, including, in extreme cases, removing core developers
*   adopt or remove projects from the community umbrella

It is highly encouraged that the Steering Council delegate its authority as much as possible, and where appropriate, to other willing community members.

The Steering Council **does not have the authority** to change this Policy.

_How many members are on the Steering Council?_

Four.

While it seems like a committee with four votes may potentially end in a deadlock with no way to break a majority vote, the Steering Council is discouraged from voting as much as possible. Instead, it should try to work by consensus, and requires three consenting votes when it is necessary to vote on a matter.

_How long do members serve on the Steering Council?_

A single term shall be for two calendar years starting in January. Terms shall be staggered so that each year there are two members continuing from the previous year’s council.

Therefore, the inaugural vote shall have two positions available for a two year term, and two positions available for a one year term.

There are no limits to the number of terms that can be served, and it is possible for an individual to serve consecutive terms.

_Who runs the Steering Council?_

After the Steering Council is elected, the group shall collectively decide upon one person to act as the Chair. The Chair does not have any additional rights or authority over any other member of the Steering Council.

The role of the Chair is merely as a coordinator and facilitator. The Chair is expected to ensure that all governance processes are adhered to. The position is more administrative and clerical, and is expected that the Chair sets agendas and coordinates discussion of the group.

_How are council members elected?_

Once a year, **all eligible core developers** for each of the projects shall have the right to elect members to the Steering Council.

Nominations shall be open from September 1 and shall close on September 30. After that, voting shall begin on October 1 and shall close on October 31. Every core developer active on the date of the June release of the Sanic Framework for that year shall be eligible to receive one vote per vacant seat on the Steering Council. For the sake of clarity, to be eligible to vote, a core developer **does not** need to be a core developer on Sanic Framework, but rather just have been active within their respective project on that date.

The top recipients of votes shall be declared the winners. If there is any tie, it is highly encouraged that the tied nominees themselves resolve the dispute before a decision is made at random.

In regards to the inaugural vote of the Steering Council, the top two vote-recipients shall serve for two years, and the next two vote-recipients shall assume the one-year seats.

To be an eligible candidate for the Steering Council, the individual must have been a core developer in active status on at least one project for the previous twelve months.

_What if there is a vacancy?_

If a vacancy on the Steering Council exists during a term, then the next highest vote-recipient in the previous election shall be offered to complete the remainder of the term. If one cannot be found this way, the Steering Council may decide the most appropriate course of action to fill the seat (whether by appointment, vote, or other means).

If a member of the Steering Council becomes inactive, then that individual shall be removed from the Steering Council immediately and the seat shall become vacant.

In extreme cases, the body of all core developers has the right to bring a vote to remove a member of the Steering Council for cause by a two-thirds majority of all eligible voting core developers.

_How shall the Steering Council conduct its business?_

As much as possible, the Steering Council shall conduct its business and discussions in the open. Any member of the community should be allowed to enter the conversation with them. However, at times it may be necessary or appropriate for discussions to be held privately. Selecting the proper venue for conversations is part of the administrative duties of the Chair.

While the specifics of how to operate are beyond the scope of the Policy, it is encouraged that the Steering Council attempt to meet at least one time per quarter in a “real-time” discussion. This could be achieved via video conferencing, live chatting, or other appropriate means.

Support
-------

All participants in the community are encouraged to provide support for users within the project management infrastructure. This support is provided as a way of growing the community. Those seeking support should recognize that all support activity within the project is voluntary and is therefore provided as and when time allows. A user requiring guaranteed response times or results should therefore seek to purchase a support contract from a community member. However, for those willing to engage with the project on its own terms, and willing to help support other users, the community support channels are ideal.

Decision making process
-----------------------

Decisions about the future of the projects are made through discussion with all members of the community, from the newest user to the most experienced member. Everyone has a voice.

All non-sensitive project management discussion takes place on the community forums, or other designated channels. Occasionally, sensitive discussions may occur in private.

In order to ensure that the project is not bogged down by endless discussion and continual voting, the project operates a policy of **lazy consensus**. This allows the majority of decisions to be made without resorting to a formal vote. For any **major decision** (as defined below), there is a separate Request for Comment (RFC) process.

### Technical decisions

Pull requests and technical decisions should generally fall into the following categories.

*   **Routine**: Documentation fixes, code changes that are for cleanup or additional testing. No functionality changes.
*   **Minor**: Changes to the code base that either fix a bug, or introduce a trivial feature. No breaking changes.
*   **Major**: Any change to the code base that breaks or deprecates existing API, alters operation in a non-trivial manner, or adds a significant feature.

It is generally the responsibility of the release managers to make sure that changes to the repositories receive the proper authorization before merge.

The release managers retain the authority to individually review and accept routine decisions that meet standards for code quality without additional input.

### Lazy consensus

Decision making (whether by the community or Steering Council) typically involves the following steps:

*   proposal
*   discussion
*   vote (if consensus is not reached through discussion)
*   decision

Any community member can make a proposal for consideration by the community. In order to initiate a discussion about a new idea, they should post a message on the appropriate channel on the Community forums, or submit a pull request implementing the idea on GitHub. This will prompt a review and, if necessary, a discussion of the idea.

The goal of this review and discussion is to gain approval for the contribution. Since most people in the project community have a shared vision, there is often little need for discussion in order to reach consensus.

In general, as long as nobody explicitly opposes a proposal or patch, it is recognized as having the support of the community. This is called lazy consensus; that is, those who have not stated their opinion explicitly have implicitly agreed to the implementation of the proposal.

Lazy consensus is a very important concept within the SCO. It is this process that allows a large group of people to efficiently reach consensus, as someone with no objections to a proposal need not spend time stating their position, and others need not spend time reading such messages.

For lazy consensus to be effective, it is necessary to allow an appropriate amount of time before assuming that there are no objections to the proposal. This is somewhat dependent upon the circumstances, but it is generally assumed that 72 hours is reasonable. This requirement ensures that everyone is given enough time to read, digest and respond to the proposal. This time period is chosen so as to be as inclusive as possible of all participants, regardless of their location and time commitments. The facilitators of discussion (whether it be the Chair or the Release Managers, where applicable) shall be charged with determining the proper length of time for such consensus to be reached.

As discussed above regarding so-called routine decisions, the release managers have the right to make decisions within a shorter period of time. In such cases, lazy consensus shall be implied.

### Request for Comment (RFC)

The Steering Council shall be in charge of overseeing the RFC process. It shall be a process that remains open to debate to all members of the community, and shall allow for ample time to consider a proposal and for members to respond and engage in meaningful discussion.

The final decision is vested with the Steering Council. However, it is strongly discouraged that the Steering Council adopt a decision that is contrary to any consensus that may exist in the community. From time to time this may happen if there is a conflict between consensus and the overall project and community goals.

An RFC shall be initiated by submission to the Steering Council in the public manner as set forth by the Steering Council. Debate shall continue and be facilitated by the Steering Council in general, and the Chair specifically.

In circumstances that the Steering Council feels it is appropriate, the RFC process may be waived in favor of lazy consensus.

---

### Guide Content En Release Notes Changelog (`guide/content/en/release-notes/changelog.md`)

---
content_class: changelog
---

# Changelog

🔶 Current release  
🔷 In support LTS release

## Version 25.12.0 🔶

_Current LTS version_

### Features
- [#3071](https://github.com/sanic-org/sanic/pull/3071) Add automatic `charset=UTF-8` to text content types
- [#3079](https://github.com/sanic-org/sanic/pull/3079) Add `DetailedConverter` for advanced environment variable conversion
- [#3080](https://github.com/sanic-org/sanic/pull/3080) Update `str_to_bool` function to include `nope` as a valid false value
- [#3102](https://github.com/sanic-org/sanic/pull/3102) Better server error messaging
- [#3110](https://github.com/sanic-org/sanic/pull/3110) Add daemon mode to Sanic CLI
- [#3114](https://github.com/sanic-org/sanic/pull/3114) Return task when creating a task
- [#3117](https://github.com/sanic-org/sanic/pull/3117) Explicit symlink params for static files/dirs

### Bugfixes
- [#3064](https://github.com/sanic-org/sanic/pull/3064) Change the log type to debug
- [#3068](https://github.com/sanic-org/sanic/pull/3068) Silent on `RuntimeError` when `write_eof`
- [#3077](https://github.com/sanic-org/sanic/pull/3077) Fix `WorkerManager.kill` on Windows
- [#3085](https://github.com/sanic-org/sanic/pull/3085) Fix `AttributeError` in `close_if_idle()` when `_http` is not initialized
- [#3086](https://github.com/sanic-org/sanic/pull/3086) Fix race condition in worker restart causing spawn failure
- [#3088](https://github.com/sanic-org/sanic/pull/3088) Fixing bad term cleanup at exit
- [#3119](https://github.com/sanic-org/sanic/pull/3119) Fix static file serving for directories with CJK characters
- [#3120](https://github.com/sanic-org/sanic/pull/3120) Respect `LOG_EXTRA` in all cases
- [#3121](https://github.com/sanic-org/sanic/pull/3121) Respect `KEEP_ALIVE` config
- [#3122](https://github.com/sanic-org/sanic/pull/3122) Check state in shutdown for handling uvloop double kill

### Deprecations and Removals
- [#3115](https://github.com/sanic-org/sanic/pull/3115) Remove Python 3.9 support and add Python 3.14

### Developer infrastructure
- [#3083](https://github.com/sanic-org/sanic/pull/3083) Add typing for parameters of constructor of `WorkerManager`
- [#3084](https://github.com/sanic-org/sanic/pull/3084) Create baseline for bandit to remove false positives
- [#3091](https://github.com/sanic-org/sanic/pull/3091) Use secrets for generating unique ping payloads
- [#3094](https://github.com/sanic-org/sanic/pull/3094) Add some typing and fix some tests
- [#3095](https://github.com/sanic-org/sanic/pull/3095) Update required Python to >=3.10
- [#3101](https://github.com/sanic-org/sanic/pull/3101) Upgrade tracerite to latest
- [#3107](https://github.com/sanic-org/sanic/pull/3107) Testing improvements
- [#3108](https://github.com/sanic-org/sanic/pull/3108) Move to 2-stage coverage check
- [#3109](https://github.com/sanic-org/sanic/pull/3109) Bump `dawidd6/action-download-artifact` from 3 to 6

### Improved Documentation
- [#3035](https://github.com/sanic-org/sanic/pull/3035) Fixes `sanic_ext` openapi component documentation
- [#3054](https://github.com/sanic-org/sanic/pull/3054) Fix 'how we built sanic' sidebar link
- [#3056](https://github.com/sanic-org/sanic/pull/3056) Fix broken link in website
- [#3057](https://github.com/sanic-org/sanic/pull/3057) Add correct path for Contribution guidelines
- [#3065](https://github.com/sanic-org/sanic/pull/3065) Fixed incorrect links throughout the documentation
- [#3066](https://github.com/sanic-org/sanic/pull/3066) Single letter typo fix for request.md documentation


## Version 25.3.0

### Features
- [#3030](https://github.com/sanic-org/sanic/pull/3030) Improve `websockets` import ordering
- [#3042](https://github.com/sanic-org/sanic/pull/3042) Add REPL context
- [#3046](https://github.com/sanic-org/sanic/pull/3046) Support latest v14 `websockets`
- [#3049](https://github.com/sanic-org/sanic/pull/3049) Subclassing `HTTPMethodView` to allow generics

### Bugfixes
- [#3047](https://github.com/sanic-org/sanic/pull/3047) Add default to `response.cookies`
- [#3048](https://github.com/sanic-org/sanic/pull/3048) Add exception logging on connection auto close


### Developer infrastructure
- [#3023](https://github.com/sanic-org/sanic/pull/3023) Cleanup from Python 3.8 removal
- [#3024](https://github.com/sanic-org/sanic/pull/3024) Improve type hinting
- [#3028](https://github.com/sanic-org/sanic/pull/3028) Add missing tests
- [#3041](https://github.com/sanic-org/sanic/pull/3041) Improve GitHub Actions checks


## Version 24.12.0 🔷

### Features
- [#3019](https://github.com/sanic-org/sanic/pull/3019) Add custom commands to `sanic` CLI

### Bugfixes
- [#2992](https://github.com/sanic-org/sanic/pull/2992) Fix `mixins.startup.serve` UnboundLocalError
- [#3000](https://github.com/sanic-org/sanic/pull/3000) Fix type annocation for `JSONResponse` method for return type `bytes` allowed for `dumps` callable
- [#3009](https://github.com/sanic-org/sanic/pull/3009) Fix `SanicException.quiet` attribute handling when set to `False`
- [#3014](https://github.com/sanic-org/sanic/pull/3014) Cleanup some typing
- [#3015](https://github.com/sanic-org/sanic/pull/3015) Kill the entire process group if applicable
- [#3016](https://github.com/sanic-org/sanic/pull/3016) Fix incompatible type annotation of get method in the HTTPMethodView class

### Deprecations and Removals
- [#3020](https://github.com/sanic-org/sanic/pull/3020) Remove Python 3.8 support

### Developer infrastructure
- [#3017](https://github.com/sanic-org/sanic/pull/3017) Cleanup setup.cfg

### Improved Documentation
- [#3007](https://github.com/sanic-org/sanic/pull/3007) Fix typo in documentation for `sanic-ext`

## Version 24.6.0

### Features
- [#2838](https://github.com/sanic-org/sanic/pull/2838) Simplify request cookies `getlist`
- [#2850](https://github.com/sanic-org/sanic/pull/2850) Unix sockets can now use `pathlib.Path`
- [#2931](https://github.com/sanic-org/sanic/pull/2931) [#2958](https://github.com/sanic-org/sanic/pull/2958) Logging improvements
- [#2947](https://github.com/sanic-org/sanic/pull/2947) Make the .message field on exceptions non-empty
- [#2961](https://github.com/sanic-org/sanic/pull/2961) [#2964](https://github.com/sanic-org/sanic/pull/2964) Allow for custom name generation

### Bugfixes
- [#2919](https://github.com/sanic-org/sanic/pull/2919) Remove deprecation notice in websockets
- [#2937](https://github.com/sanic-org/sanic/pull/2937) Resolve response streaming error when in ASGI mode
- [#2959](https://github.com/sanic-org/sanic/pull/2959) Resolve Python 3.12 deprecation notic
- [#2960](https://github.com/sanic-org/sanic/pull/2960) Ensure proper intent for noisy exceptions
- [#2970](https://github.com/sanic-org/sanic/pull/2970) [#2978](https://github.com/sanic-org/sanic/pull/2978) Fix missing dependencies for 3.12
- [#2971](https://github.com/sanic-org/sanic/pull/2971) Fix middleware exceptions on Not Found routes with error in middleware
- [#2973](https://github.com/sanic-org/sanic/pull/2973) Resolve cheduling logic for `transport.close` and `transport.abort`
- [#2976](https://github.com/sanic-org/sanic/pull/2976) Fix deleting a cookie that was created with `secure=False`
- [#2979](https://github.com/sanic-org/sanic/pull/2979) Throw error on bad body length
- [#2980](https://github.com/sanic-org/sanic/pull/2980) Throw error on bad body encoding

### Deprecations and Removals
- [#2899](https://github.com/sanic-org/sanic/pull/2899) Remove erroneous line from REPL impacting environments without HTTPX
- [#2962](https://github.com/sanic-org/sanic/pull/2962) Merge entity header removal

### Developer infrastructure
- [#2882](https://github.com/sanic-org/sanic/pull/2882) [#2896](https://github.com/sanic-org/sanic/pull/2896) Apply dynamic port fixture for improving tests with port selection
- [#2887](https://github.com/sanic-org/sanic/pull/2887) Updates to docker image builds
- [#2932](https://github.com/sanic-org/sanic/pull/2932) Cleanup code base with Ruff

### Improved Documentation
- [#2924](https://github.com/sanic-org/sanic/pull/2924) Cleanup markdown on html5tagger page
- [#2930](https://github.com/sanic-org/sanic/pull/2930) Cleanup typo on Sanic Extensions README.md
- [#2934](https://github.com/sanic-org/sanic/pull/2934) Add more context to the health check documents
- [#2936](https://github.com/sanic-org/sanic/pull/2936) Improve worker manager documentation
- [#2955](https://github.com/sanic-org/sanic/pull/2955) Fixed wrong formatting in `request.md`

## Version 23.12.0 🔷

### Features
- [#2775](https://github.com/sanic-org/sanic/pull/2775) Start and restart arbitrary processes
- [#2811](https://github.com/sanic-org/sanic/pull/2811) Cleaner process management in shutdown
- [#2812](https://github.com/sanic-org/sanic/pull/2812) Suppress task cancel traceback on open websocket
- [#2822](https://github.com/sanic-org/sanic/pull/2822) Listener and signal prioritization
- [#2831](https://github.com/sanic-org/sanic/pull/2831) Reduce memory consumption
- [#2837](https://github.com/sanic-org/sanic/pull/2837) Accept bare cookies
- [#2841](https://github.com/sanic-org/sanic/pull/2841) Add `websocket.handler.<before/after/exception>` signals
- [#2805](https://github.com/sanic-org/sanic/pull/2805) Add changed files to reload trigger listeners
- [#2813](https://github.com/sanic-org/sanic/pull/2813) Allow for simple signals
- [#2827](https://github.com/sanic-org/sanic/pull/2827) Improve functionality and consistency of `Sanic.event()`
- [#2851](https://github.com/sanic-org/sanic/pull/2851) Allow range requests for a single byte
- [#2854](https://github.com/sanic-org/sanic/pull/2854) Better `Request.scheme` for websocket requests
- [#2858](https://github.com/sanic-org/sanic/pull/2858) Convert Sanic `Request` to a Websockets `Request` for handshake
- [#2859](https://github.com/sanic-org/sanic/pull/2859) Add a REPL to the `sanic` CLI
- [#2870](https://github.com/sanic-org/sanic/pull/2870) Add Python 3.12 support
- [#2875](https://github.com/sanic-org/sanic/pull/2875) Better exception on multiprocessing context conflicts

### Bugfixes
- [#2803](https://github.com/sanic-org/sanic/pull/2803) Fix MOTD display for extra data

### Developer infrastructure
- [#2796](https://github.com/sanic-org/sanic/pull/2796) Refactor unit test cases
- [#2801](https://github.com/sanic-org/sanic/pull/2801) Fix `test_fast` when there is only one CPU
- [#2807](https://github.com/sanic-org/sanic/pull/2807) Add constraint for autodocsum (lint issue in old package version)
- [#2808](https://github.com/sanic-org/sanic/pull/2808) Refactor GitHub Actions
- [#2814](https://github.com/sanic-org/sanic/pull/2814) Run CI pipeline on git push
- [#2846](https://github.com/sanic-org/sanic/pull/2846) Drop old performance tests/benchmarks
- [#2848](https://github.com/sanic-org/sanic/pull/2848) Makefile cleanup
- [#2865](https://github.com/sanic-org/sanic/pull/2865)
  [#2869](https://github.com/sanic-org/sanic/pull/2869)
  [#2872](https://github.com/sanic-org/sanic/pull/2872)
  [#2879](https://github.com/sanic-org/sanic/pull/2879)
  Add ruff to toolchain
- [#2866](https://github.com/sanic-org/sanic/pull/2866) Fix the alt svc test to run locally with explicit buffer nbytes
- [#2877](https://github.com/sanic-org/sanic/pull/2877) Use Python's trusted publisher in deployments
- [#2882](https://github.com/sanic-org/sanic/pull/2882) Introduce dynamic port fixture in targeted locations in the test suite

### Improved Documentation
- [#2781](https://github.com/sanic-org/sanic/pull/2781)
  [#2821](https://github.com/sanic-org/sanic/pull/2821)
  [#2861](https://github.com/sanic-org/sanic/pull/2861)
  [#2863](https://github.com/sanic-org/sanic/pull/2863)
  Conversion of User Guide to the SHH (Sanic, html5tagger, HTMX) stack
- [#2810](https://github.com/sanic-org/sanic/pull/2810) Update README
- [#2855](https://github.com/sanic-org/sanic/pull/2855) Edit Discord badge
- [#2864](https://github.com/sanic-org/sanic/pull/2864) Adjust documentation for using state properties within http/https redirection document


## Version 23.9.0

_Due to circumstances at the time, v.23.9 was skipped._


## Version 23.6.0

### Features
- [#2670](https://github.com/sanic-org/sanic/pull/2670) Increase `KEEP_ALIVE_TIMEOUT` default to 120 seconds
- [#2716](https://github.com/sanic-org/sanic/pull/2716) Adding allow route overwrite option in blueprint
- [#2724](https://github.com/sanic-org/sanic/pull/2724) and [#2792](https://github.com/sanic-org/sanic/pull/2792) Add a new exception signal for ALL exceptions raised anywhere in application
- [#2727](https://github.com/sanic-org/sanic/pull/2727) Add name prefixing to BP groups
- [#2754](https://github.com/sanic-org/sanic/pull/2754) Update request type on middleware types
- [#2770](https://github.com/sanic-org/sanic/pull/2770) Better exception message on startup time application induced import error
- [#2776](https://github.com/sanic-org/sanic/pull/2776) Set multiprocessing start method early
- [#2785](https://github.com/sanic-org/sanic/pull/2785) Add custom typing to config and ctx objects
- [#2790](https://github.com/sanic-org/sanic/pull/2790) Add `request.client_ip`

### Bugfixes
- [#2728](https://github.com/sanic-org/sanic/pull/2728) Fix traversals for intended results
- [#2729](https://github.com/sanic-org/sanic/pull/2729) Handle case when headers argument of ResponseStream constructor is None
- [#2737](https://github.com/sanic-org/sanic/pull/2737) Fix type annotation for `JSONREsponse` default content type
- [#2740](https://github.com/sanic-org/sanic/pull/2740) Use Sanic's serializer for JSON responses in the Inspector
- [#2760](https://github.com/sanic-org/sanic/pull/2760) Support for `Request.get_current` in ASGI mode
- [#2773](https://github.com/sanic-org/sanic/pull/2773) Alow Blueprint routes to explicitly define error_format
- [#2774](https://github.com/sanic-org/sanic/pull/2774) Resolve headers on different renderers
- [#2782](https://github.com/sanic-org/sanic/pull/2782) Resolve pypy compatibility issues

### Deprecations and Removals
- [#2777](https://github.com/sanic-org/sanic/pull/2777) Remove Python 3.7 support

### Developer infrastructure
- [#2766](https://github.com/sanic-org/sanic/pull/2766) Unpin setuptools version
- [#2779](https://github.com/sanic-org/sanic/pull/2779) Run keep alive tests in loop to get available port

### Improved Documentation
- [#2741](https://github.com/sanic-org/sanic/pull/2741) Better documentation examples about running Sanic
From that list, the items to highlight in the release notes:


## Version 23.3.0

### Features
- [#2545](https://github.com/sanic-org/sanic/pull/2545) Standardize init of exceptions for more consistent control of HTTP responses using exceptions
- [#2606](https://github.com/sanic-org/sanic/pull/2606) Decode headers as UTF-8 also in ASGI
- [#2646](https://github.com/sanic-org/sanic/pull/2646) Separate ASGI request and lifespan callables
- [#2659](https://github.com/sanic-org/sanic/pull/2659) Use ``FALLBACK_ERROR_FORMAT`` for handlers that return ``empty()``
- [#2662](https://github.com/sanic-org/sanic/pull/2662) Add basic file browser (HTML page) and auto-index serving
- [#2667](https://github.com/sanic-org/sanic/pull/2667) Nicer traceback formatting (HTML page)
- [#2668](https://github.com/sanic-org/sanic/pull/2668) Smarter error page rendering format selection; more reliant upon header and "common sense" defaults
- [#2680](https://github.com/sanic-org/sanic/pull/2680) Check the status of socket before shutting down with ``SHUT_RDWR``
- [#2687](https://github.com/sanic-org/sanic/pull/2687) Refresh ``Request.accept`` functionality to be more performant and spec-compliant
- [#2696](https://github.com/sanic-org/sanic/pull/2696) Add header accessors as properties
    ```
    Example-Field: Foo, Bar
    Example-Field: Baz
    ```
    ```python
    request.headers.example_field == "Foo, Bar,Baz"
    ```
- [#2700](https://github.com/sanic-org/sanic/pull/2700) Simpler CLI targets

    ```sh
    $ sanic path.to.module:app          # global app instance
    $ sanic path.to.module:create_app   # factory pattern
    $ sanic ./path/to/directory/        # simple serve
    ```
- [#2701](https://github.com/sanic-org/sanic/pull/2701) API to define a number of workers in managed processes
- [#2704](https://github.com/sanic-org/sanic/pull/2704) Add convenience for dynamic changes to routing
- [#2706](https://github.com/sanic-org/sanic/pull/2706) Add convenience methods for cookie creation and deletion
    
    ```python
    response = text("...")
    response.add_cookie("test", "It worked!", domain=".yummy-yummy-cookie.com")
    ```
- [#2707](https://github.com/sanic-org/sanic/pull/2707) Simplified ``parse_content_header`` escaping to be RFC-compliant and remove outdated FF hack
- [#2710](https://github.com/sanic-org/sanic/pull/2710) Stricter charset handling and escaping of request URLs
- [#2711](https://github.com/sanic-org/sanic/pull/2711) Consume body on ``DELETE`` by default
- [#2719](https://github.com/sanic-org/sanic/pull/2719) Allow ``password`` to be passed to TLS context
- [#2720](https://github.com/sanic-org/sanic/pull/2720) Skip middleware on ``RequestCancelled``
- [#2721](https://github.com/sanic-org/sanic/pull/2721) Change access logging format to ``%s``
- [#2722](https://github.com/sanic-org/sanic/pull/2722) Add ``CertLoader`` as application option for directly controlling ``SSLContext`` objects
- [#2725](https://github.com/sanic-org/sanic/pull/2725) Worker sync state tolerance on race condition

### Bugfixes
- [#2651](https://github.com/sanic-org/sanic/pull/2651) ASGI websocket to pass thru bytes as is
- [#2697](https://github.com/sanic-org/sanic/pull/2697) Fix comparison between datetime aware and naive in ``file`` when using ``If-Modified-Since``

### Deprecations and Removals
- [#2666](https://github.com/sanic-org/sanic/pull/2666) Remove deprecated ``__blueprintname__`` property

### Improved Documentation
- [#2712](https://github.com/sanic-org/sanic/pull/2712) Improved example using ``'https'`` to create the redirect


## Version 22.12.0

_Current LTS version_

### Features

- [#2569](https://github.com/sanic-org/sanic/pull/2569) Add `JSONResponse` class with some convenient methods when updating a response object
- [#2598](https://github.com/sanic-org/sanic/pull/2598) Change `uvloop` requirement to `>=0.15.0`
- [#2609](https://github.com/sanic-org/sanic/pull/2609) Add compatibility with `websockets` v11.0
- [#2610](https://github.com/sanic-org/sanic/pull/2610) Kill server early on worker error
    - Raise deadlock timeout to 30s
- [#2617](https://github.com/sanic-org/sanic/pull/2617) Scale number of running server workers
- [#2621](https://github.com/sanic-org/sanic/pull/2621) [#2634](https://github.com/sanic-org/sanic/pull/2634) Send `SIGKILL` on subsequent `ctrl+c` to force worker exit
- [#2622](https://github.com/sanic-org/sanic/pull/2622) Add API to restart all workers from the multiplexer
- [#2624](https://github.com/sanic-org/sanic/pull/2624) Default to `spawn` for all subprocesses unless specifically set:
    ```python
    from sanic import Sanic
    
    Sanic.start_method = "fork"
    ```
- [#2625](https://github.com/sanic-org/sanic/pull/2625) Filename normalisation of form-data/multipart file uploads
- [#2626](https://github.com/sanic-org/sanic/pull/2626) Move to HTTP Inspector:
    - Remote access to inspect running Sanic instances
    - TLS support for encrypted calls to Inspector
    - Authentication to Inspector with API key
    - Ability to extend Inspector with custom commands
- [#2632](https://github.com/sanic-org/sanic/pull/2632) Control order of restart operations
- [#2633](https://github.com/sanic-org/sanic/pull/2633) Move reload interval to class variable
- [#2636](https://github.com/sanic-org/sanic/pull/2636) Add `priority` to `register_middleware` method
- [#2639](https://github.com/sanic-org/sanic/pull/2639) Add `unquote` to `add_route` method
- [#2640](https://github.com/sanic-org/sanic/pull/2640) ASGI websockets to receive `text` or `bytes`


### Bugfixes

- [#2607](https://github.com/sanic-org/sanic/pull/2607) Force socket shutdown before close to allow rebinding
- [#2590](https://github.com/sanic-org/sanic/pull/2590) Use actual `StrEnum` in Python 3.11+
- [#2615](https://github.com/sanic-org/sanic/pull/2615) Ensure middleware executes only once per request timeout
- [#2627](https://github.com/sanic-org/sanic/pull/2627) Crash ASGI application on lifespan failure
- [#2635](https://github.com/sanic-org/sanic/pull/2635) Resolve error with low-level server creation on Windows


### Deprecations and Removals

- [#2608](https://github.com/sanic-org/sanic/pull/2608) [#2630](https://github.com/sanic-org/sanic/pull/2630) Signal conditions and triggers saved on `signal.extra` 
- [#2626](https://github.com/sanic-org/sanic/pull/2626) Move to HTTP Inspector
    - 🚨 *BREAKING CHANGE*: Moves the Inspector to a Sanic app from a simple TCP socket with a custom protocol
    - *DEPRECATE*: The `--inspect*` commands have been deprecated in favor of `inspect ...` commands
- [#2628](https://github.com/sanic-org/sanic/pull/2628) Replace deprecated `distutils.strtobool`


### Developer infrastructure

- [#2612](https://github.com/sanic-org/sanic/pull/2612) Add CI testing for Python 3.11


## Version 22.9.1

### Features

- [#2585](https://github.com/sanic-org/sanic/pull/2585) Improved error message when no applications have been registered


### Bugfixes

- [#2578](https://github.com/sanic-org/sanic/pull/2578) Add certificate loader for in process certificate creation
- [#2591](https://github.com/sanic-org/sanic/pull/2591) Do not use sentinel identity for `spawn` compatibility
- [#2592](https://github.com/sanic-org/sanic/pull/2592) Fix properties in nested blueprint groups
- [#2595](https://github.com/sanic-org/sanic/pull/2595) Introduce sleep interval on new worker reloader


### Deprecations and Removals


### Developer infrastructure

- [#2588](https://github.com/sanic-org/sanic/pull/2588) Markdown templates on issue forms


### Improved Documentation

- [#2556](https://github.com/sanic-org/sanic/pull/2556) v22.9 documentation
- [#2582](https://github.com/sanic-org/sanic/pull/2582) Cleanup documentation on Windows support


## Version 22.9.0

### Features

- [#2445](https://github.com/sanic-org/sanic/pull/2445) Add custom loads function 
- [#2490](https://github.com/sanic-org/sanic/pull/2490) Make `WebsocketImplProtocol` async iterable
- [#2499](https://github.com/sanic-org/sanic/pull/2499) Sanic Server WorkerManager refactor
- [#2506](https://github.com/sanic-org/sanic/pull/2506) Use `pathlib` for path resolution (for static file serving)
- [#2508](https://github.com/sanic-org/sanic/pull/2508) Use `path.parts` instead of `match` (for static file serving)
- [#2513](https://github.com/sanic-org/sanic/pull/2513) Better request cancel handling
- [#2516](https://github.com/sanic-org/sanic/pull/2516) Add request properties for HTTP method info:
    - `request.is_safe`
    - `request.is_idempotent`
    - `request.is_cacheable`
    - *See* [MDN docs](https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods) *for more information about when these apply*
- [#2522](https://github.com/sanic-org/sanic/pull/2522) Always show server location in ASGI
- [#2526](https://github.com/sanic-org/sanic/pull/2526) Cache control support for static files for returning 304 when appropriate
- [#2533](https://github.com/sanic-org/sanic/pull/2533) Refactor `_static_request_handler`
- [#2540](https://github.com/sanic-org/sanic/pull/2540) Add signals before and after handler execution
    - `http.handler.before`
    - `http.handler.after`
- [#2542](https://github.com/sanic-org/sanic/pull/2542) Add *[redacted]* to CLI :)
- [#2546](https://github.com/sanic-org/sanic/pull/2546) Add deprecation warning filter
- [#2550](https://github.com/sanic-org/sanic/pull/2550) Middleware priority and performance enhancements

### Bugfixes

- [#2495](https://github.com/sanic-org/sanic/pull/2495) Prevent directory traversion with static files
- [#2515](https://github.com/sanic-org/sanic/pull/2515) Do not apply double slash to paths in certain static dirs in Blueprints

### Deprecations and Removals

- [#2525](https://github.com/sanic-org/sanic/pull/2525) Warn on duplicate route names, will be prevented outright in v23.3
- [#2537](https://github.com/sanic-org/sanic/pull/2537) Raise warning and deprecation notice on duplicate exceptions, will be prevented outright in v23.3

### Developer infrastructure

- [#2504](https://github.com/sanic-org/sanic/pull/2504) Cleanup test suite
- [#2505](https://github.com/sanic-org/sanic/pull/2505) Replace Unsupported Python Version Number from the Contributing Doc
- [#2530](https://github.com/sanic-org/sanic/pull/2530) Do not include tests folder in installed package resolver

### Improved Documentation

- [#2502](https://github.com/sanic-org/sanic/pull/2502) Fix a few typos
- [#2517](https://github.com/sanic-org/sanic/pull/2517) [#2536](https://github.com/sanic-org/sanic/pull/2536) Add some type hints


## Version 22.6.2

### Bugfixes

- [#2522](https://github.com/sanic-org/sanic/pull/2522) Always show server location in ASGI

## Version 22.6.1

### Bugfixes

- [#2477](https://github.com/sanic-org/sanic/pull/2477) Sanic static directory fails when folder name ends with ".."


## Version 22.6.0

### Features
- [#2378](https://github.com/sanic-org/sanic/pull/2378) Introduce HTTP/3 and autogeneration of TLS certificates in `DEBUG` mode
    - 👶 *EARLY RELEASE FEATURE*: Serving Sanic over HTTP/3 is an early release feature. It does not yet fully cover the HTTP/3 spec, but instead aims for feature parity with Sanic's existing HTTP/1.1 server. Websockets, WebTransport, push responses are examples of some features not yet implemented.
    - 📦 *EXTRA REQUIREMENT*: Not all HTTP clients are capable of interfacing with HTTP/3 servers. You may need to install a [HTTP/3 capable client](https://curl.se/docs/http3.html).
    - 📦 *EXTRA REQUIREMENT*: In order to use TLS autogeneration, you must install either [mkcert](https://github.com/FiloSottile/mkcert) or [trustme](https://github.com/python-trio/trustme).
- [#2416](https://github.com/sanic-org/sanic/pull/2416) Add message to `task.cancel`
- [#2420](https://github.com/sanic-org/sanic/pull/2420) Add exception aliases for more consistent naming with standard HTTP response types (`BadRequest`, `MethodNotAllowed`, `RangeNotSatisfiable`)
- [#2432](https://github.com/sanic-org/sanic/pull/2432) Expose ASGI `scope` as a property on the `Request` object
- [#2438](https://github.com/sanic-org/sanic/pull/2438) Easier access to websocket class for annotation: `from sanic import Websocket`
- [#2439](https://github.com/sanic-org/sanic/pull/2439) New API for reading form values with options: `Request.get_form` 
- [#2445](https://github.com/sanic-org/sanic/pull/2445) Add custom `loads` function
- [#2447](https://github.com/sanic-org/sanic/pull/2447), [#2486](https://github.com/sanic-org/sanic/pull/2486) Improved API to support setting cache control headers
- [#2453](https://github.com/sanic-org/sanic/pull/2453) Move verbosity filtering to logger
- [#2475](https://github.com/sanic-org/sanic/pull/2475) Expose getter for current request using `Request.get_current()`

### Bugfixes
- [#2448](https://github.com/sanic-org/sanic/pull/2448) Fix to allow running with `pythonw.exe` or places where there is no `sys.stdout`
- [#2451](https://github.com/sanic-org/sanic/pull/2451) Trigger `http.lifecycle.request` signal in ASGI mode
- [#2455](https://github.com/sanic-org/sanic/pull/2455) Resolve typing of stacked route definitions
- [#2463](https://github.com/sanic-org/sanic/pull/2463) Properly catch websocket CancelledError in websocket handler in Python 3.7

### Deprecations and Removals
- [#2487](https://github.com/sanic-org/sanic/pull/2487) v22.6 deprecations and changes
    1. Optional application registry
    1. Execution of custom handlers after some part of response was sent
    1. Configuring fallback handlers on the `ErrorHandler`
    1. Custom `LOGO` setting
    1. `sanic.response.stream`
    1. `AsyncioServer.init`

### Developer infrastructure
- [#2449](https://github.com/sanic-org/sanic/pull/2449) Clean up `black` and `isort` config
- [#2479](https://github.com/sanic-org/sanic/pull/2479) Fix some flappy tests

### Improved Documentation
- [#2461](https://github.com/sanic-org/sanic/pull/2461) Update example to match current application naming standards
- [#2466](https://github.com/sanic-org/sanic/pull/2466) Better type annotation for `Extend`
- [#2485](https://github.com/sanic-org/sanic/pull/2485) Improved help messages in CLI


## Version 22.3.0

### Features
- [#2347](https://github.com/sanic-org/sanic/pull/2347) API for multi-application server
    - 🚨 *BREAKING CHANGE*: The old `sanic.worker.GunicornWorker` has been **removed**. To run Sanic with `gunicorn`, you should use it thru `uvicorn` [as described in their docs](https://www.uvicorn.org/#running-with-gunicorn).
    - 🧁 *SIDE EFFECT*: Named background tasks are now supported, even in Python 3.7
- [#2357](https://github.com/sanic-org/sanic/pull/2357) Parse `Authorization` header as `Request.credentials`
- [#2361](https://github.com/sanic-org/sanic/pull/2361) Add config option to skip `Touchup` step in application startup
- [#2372](https://github.com/sanic-org/sanic/pull/2372) Updates to CLI help messaging
- [#2382](https://github.com/sanic-org/sanic/pull/2382) Downgrade warnings to backwater debug messages 
- [#2396](https://github.com/sanic-org/sanic/pull/2396) Allow for `multidict` v0.6
- [#2401](https://github.com/sanic-org/sanic/pull/2401) Upgrade CLI catching for alternative application run types
- [#2402](https://github.com/sanic-org/sanic/pull/2402) Conditionally inject CLI arguments into factory
- [#2413](https://github.com/sanic-org/sanic/pull/2413) Add new start and stop event listeners to reloader process
- [#2414](https://github.com/sanic-org/sanic/pull/2414) Remove loop as required listener arg
- [#2415](https://github.com/sanic-org/sanic/pull/2415) Better exception for bad URL parsing
- [sanic-routing#47](https://github.com/sanic-org/sanic-routing/pull/47) Add a new extention parameter type: `<file:ext>`, `<file:ext=jpg>`, `<file:ext=jpg|png|gif|svg>`, `<file=int:ext>`, `<file=int:ext=jpg|png|gif|svg>`, `<file=float:ext=tar.gz>`
    - 👶 *BETA FEATURE*: This feature will not work with `path` type matching, and is being released as a beta feature only.
- [sanic-routing#57](https://github.com/sanic-org/sanic-routing/pull/57) Change `register_pattern` to accept a `str` or `Pattern`
- [sanic-routing#58](https://github.com/sanic-org/sanic-routing/pull/58) Default matching on non-empty strings only, and new `strorempty` pattern type
    - 🚨 *BREAKING CHANGE*: Previously a route with a dynamic string parameter (`/<foo>` or `/<foo:str>`) would match on any string, including empty strings. It will now **only** match a non-empty string. To retain the old behavior, you should use the new parameter type: `/<foo:strorempty>`.

### Bugfixes
- [#2373](https://github.com/sanic-org/sanic/pull/2373) Remove `error_logger` on websockets
- [#2381](https://github.com/sanic-org/sanic/pull/2381) Fix newly assigned `None` in task registry
- [sanic-routing#52](https://github.com/sanic-org/sanic-routing/pull/52) Add type casting to regex route matching
- [sanic-routing#60](https://github.com/sanic-org/sanic-routing/pull/60) Add requirements check on regex routes (this resolves, for example, multiple static directories with differing `host` values)

### Deprecations and Removals
- [#2362](https://github.com/sanic-org/sanic/pull/2362) 22.3 Deprecations and changes
    1. `debug=True` and `--debug` do _NOT_ automatically run `auto_reload`
    2. Default error render is with plain text (browsers still get HTML by default because `auto` looks at headers)
    3. `config` is required for `ErrorHandler.finalize`
    4. `ErrorHandler.lookup` requires two positional args
    5. Unused websocket protocol args removed
- [#2344](https://github.com/sanic-org/sanic/pull/2344) Deprecate loading of lowercase environment variables

### Developer infrastructure
- [#2363](https://github.com/sanic-org/sanic/pull/2363) Revert code coverage back to Codecov
- [#2405](https://github.com/sanic-org/sanic/pull/2405) Upgrade tests for `sanic-routing` changes
- [sanic-testing#35](https://github.com/sanic-org/sanic-testing/pull/35) Allow for httpx v0.22

### Improved Documentation
- [#2350](https://github.com/sanic-org/sanic/pull/2350) Fix link in README for ASGI
- [#2398](https://github.com/sanic-org/sanic/pull/2398) Document middleware on_request and on_response
- [#2409](https://github.com/sanic-org/sanic/pull/2409) Add missing documentation for `Request.respond`

### Miscellaneous
- [#2376](https://github.com/sanic-org/sanic/pull/2376) Fix typing for `ListenerMixin.listener`
- [#2383](https://github.com/sanic-org/sanic/pull/2383) Clear deprecation warning in `asyncio.wait`
- [#2387](https://github.com/sanic-org/sanic/pull/2387) Cleanup `__slots__` implementations
- [#2390](https://github.com/sanic-org/sanic/pull/2390) Clear deprecation warning in `asyncio.get_event_loop`


## Version 21.12.1

- [#2349](https://github.com/sanic-org/sanic/pull/2349) Only display MOTD on startup
- [#2354](https://github.com/sanic-org/sanic/pull/2354) Ignore name argument in Python 3.7
- [#2355](https://github.com/sanic-org/sanic/pull/2355) Add config.update support for all config values

## Version 21.12.0

### Features
- [#2260](https://github.com/sanic-org/sanic/pull/2260) Allow early Blueprint registrations to still apply later added objects
- [#2262](https://github.com/sanic-org/sanic/pull/2262) Noisy exceptions - force logging of all exceptions
- [#2264](https://github.com/sanic-org/sanic/pull/2264) Optional `uvloop` by configuration
- [#2270](https://github.com/sanic-org/sanic/pull/2270) Vhost support using multiple TLS certificates
- [#2277](https://github.com/sanic-org/sanic/pull/2277) Change signal routing for increased consistency
    - *BREAKING CHANGE*: If you were manually routing signals there is a breaking change. The signal router's `get` is no longer 100% determinative. There is now an additional step to loop thru the returned signals for proper matching on the requirements. If signals are being dispatched using `app.dispatch` or `bp.dispatch`, there is no change.
- [#2290](https://github.com/sanic-org/sanic/pull/2290) Add contextual exceptions
- [#2291](https://github.com/sanic-org/sanic/pull/2291) Increase join concat performance 
- [#2295](https://github.com/sanic-org/sanic/pull/2295), [#2316](https://github.com/sanic-org/sanic/pull/2316), [#2331](https://github.com/sanic-org/sanic/pull/2331) Restructure of CLI and application state with new displays and more command parity with `app.run`
- [#2302](https://github.com/sanic-org/sanic/pull/2302) Add route context at definition time
- [#2304](https://github.com/sanic-org/sanic/pull/2304) Named tasks and new API for managing background tasks
- [#2307](https://github.com/sanic-org/sanic/pull/2307) On app auto-reload, provide insight of changed files
- [#2308](https://github.com/sanic-org/sanic/pull/2308) Auto extend application with [Sanic Extensions](https://sanicframework.org/en/plugins/sanic-ext/getting-started.html) if it is installed, and provide first class support for accessing the extensions
- [#2309](https://github.com/sanic-org/sanic/pull/2309) Builtin signals changed to `Enum`
- [#2313](https://github.com/sanic-org/sanic/pull/2313) Support additional config implementation use case
- [#2321](https://github.com/sanic-org/sanic/pull/2321) Refactor environment variable hydration logic
- [#2327](https://github.com/sanic-org/sanic/pull/2327) Prevent sending multiple or mixed responses on a single request
- [#2330](https://github.com/sanic-org/sanic/pull/2330) Custom type casting on environment variables
- [#2332](https://github.com/sanic-org/sanic/pull/2332) Make all deprecation notices consistent
- [#2335](https://github.com/sanic-org/sanic/pull/2335) Allow underscore to start instance names

### Bugfixes
- [#2273](https://github.com/sanic-org/sanic/pull/2273) Replace assignation by typing for `websocket_handshake`
- [#2285](https://github.com/sanic-org/sanic/pull/2285) Fix IPv6 display in startup logs
- [#2299](https://github.com/sanic-org/sanic/pull/2299) Dispatch `http.lifecyle.response` from exception handler

### Deprecations and Removals
- [#2306](https://github.com/sanic-org/sanic/pull/2306) Removal of deprecated items
    - `Sanic` and `Blueprint` may no longer have arbitrary properties attached to them
    - `Sanic` and `Blueprint` forced to have compliant names
        - alphanumeric + `_` + `-`
        - must start with letter or `_`
    - `load_env` keyword argument of `Sanic`
    - `sanic.exceptions.abort`
    - `sanic.views.CompositionView`
    - `sanic.response.StreamingHTTPResponse`
        - *NOTE:* the `stream()` response method (where you pass a callable streaming function) has been deprecated and will be removed in v22.6. You should upgrade all streaming responses to the new style: https://sanicframework.org/en/guide/advanced/streaming.html#response-streaming
- [#2320](https://github.com/sanic-org/sanic/pull/2320) Remove app instance from Config for error handler setting

### Developer infrastructure
- [#2251](https://github.com/sanic-org/sanic/pull/2251) Change dev install command
- [#2286](https://github.com/sanic-org/sanic/pull/2286) Change codeclimate complexity threshold from 5 to 10
- [#2287](https://github.com/sanic-org/sanic/pull/2287) Update host test function names so they are not overwritten
- [#2292](https://github.com/sanic-org/sanic/pull/2292) Fail CI on error
- [#2311](https://github.com/sanic-org/sanic/pull/2311), [#2324](https://github.com/sanic-org/sanic/pull/2324) Do not run tests for draft PRs
- [#2336](https://github.com/sanic-org/sanic/pull/2336) Remove paths from coverage checks
- [#2338](https://github.com/sanic-org/sanic/pull/2338) Cleanup ports on tests

### Improved Documentation
- [#2269](https://github.com/sanic-org/sanic/pull/2269), [#2329](https://github.com/sanic-org/sanic/pull/2329), [#2333](https://github.com/sanic-org/sanic/pull/2333) Cleanup typos and fix language

### Miscellaneous
- [#2257](https://github.com/sanic-org/sanic/pull/2257), [#2294](https://github.com/sanic-org/sanic/pull/2294), [#2341](https://github.com/sanic-org/sanic/pull/2341) Add Python 3.10 support
- [#2279](https://github.com/sanic-org/sanic/pull/2279), [#2317](https://github.com/sanic-org/sanic/pull/2317), [#2322](https://github.com/sanic-org/sanic/pull/2322) Add/correct missing type annotations
- [#2305](https://github.com/sanic-org/sanic/pull/2305) Fix examples to use modern implementations


## Version 21.9.3
*Rerelease of v21.9.2 with some cleanup*

## Version 21.9.2
- [#2268](https://github.com/sanic-org/sanic/pull/2268) Make HTTP connections start in IDLE stage, avoiding delays and error messages
- [#2310](https://github.com/sanic-org/sanic/pull/2310) More consistent config setting with post-FALLBACK_ERROR_FORMAT apply

## Version 21.9.1
- [#2259](https://github.com/sanic-org/sanic/pull/2259) Allow non-conforming ErrorHandlers

## Version 21.9.0

### Features
- [#2158](https://github.com/sanic-org/sanic/pull/2158), [#2248](https://github.com/sanic-org/sanic/pull/2248) Complete overhaul of I/O to websockets
- [#2160](https://github.com/sanic-org/sanic/pull/2160) Add new 17 signals into server and request lifecycles
- [#2162](https://github.com/sanic-org/sanic/pull/2162) Smarter `auto` fallback formatting upon exception
- [#2184](https://github.com/sanic-org/sanic/pull/2184) Introduce implementation for copying a Blueprint
- [#2200](https://github.com/sanic-org/sanic/pull/2200) Accept header parsing
- [#2207](https://github.com/sanic-org/sanic/pull/2207) Log remote address if available
- [#2209](https://github.com/sanic-org/sanic/pull/2209) Add convenience methods to BP groups
- [#2216](https://github.com/sanic-org/sanic/pull/2216) Add default messages to SanicExceptions
- [#2225](https://github.com/sanic-org/sanic/pull/2225) Type annotation convenience for annotated handlers with path parameters
- [#2236](https://github.com/sanic-org/sanic/pull/2236) Allow Falsey (but not-None) responses from route handlers
- [#2238](https://github.com/sanic-org/sanic/pull/2238) Add `exception` decorator to Blueprint Groups
- [#2244](https://github.com/sanic-org/sanic/pull/2244) Explicit static directive for serving file or dir (ex: `static(..., resource_type="file")`)
- [#2245](https://github.com/sanic-org/sanic/pull/2245) Close HTTP loop when connection task cancelled

### Bugfixes
- [#2188](https://github.com/sanic-org/sanic/pull/2188) Fix the handling of the end of a chunked request
- [#2195](https://github.com/sanic-org/sanic/pull/2195) Resolve unexpected error handling on static requests
- [#2208](https://github.com/sanic-org/sanic/pull/2208) Make blueprint-based exceptions attach and trigger in a more intuitive manner
- [#2211](https://github.com/sanic-org/sanic/pull/2211) Fixed for handling exceptions of asgi app call
- [#2213](https://github.com/sanic-org/sanic/pull/2213) Fix bug where ws exceptions not being logged
- [#2231](https://github.com/sanic-org/sanic/pull/2231) Cleaner closing of tasks by using `abort()` in strategic places to avoid dangling sockets
- [#2247](https://github.com/sanic-org/sanic/pull/2247) Fix logging of auto-reload status in debug mode
- [#2246](https://github.com/sanic-org/sanic/pull/2246) Account for BP with exception handler but no routes

### Developer infrastructure  
- [#2194](https://github.com/sanic-org/sanic/pull/2194) HTTP unit tests with raw client
- [#2199](https://github.com/sanic-org/sanic/pull/2199) Switch to codeclimate
- [#2214](https://github.com/sanic-org/sanic/pull/2214) Try Reopening Windows Tests
- [#2229](https://github.com/sanic-org/sanic/pull/2229) Refactor `HttpProtocol` into a base class
- [#2230](https://github.com/sanic-org/sanic/pull/2230) Refactor `server.py` into multi-file module

### Miscellaneous
- [#2173](https://github.com/sanic-org/sanic/pull/2173) Remove Duplicated Dependencies and PEP 517 Support 
- [#2193](https://github.com/sanic-org/sanic/pull/2193), [#2196](https://github.com/sanic-org/sanic/pull/2196), [#2217](https://github.com/sanic-org/sanic/pull/2217) Type annotation changes


## Version 21.6.1

**Bugfixes**

-   [#2178](https://github.com/sanic-org/sanic/pull/2178) Update
    sanic-routing to allow for better splitting of complex URI
    templates
-   [#2183](https://github.com/sanic-org/sanic/pull/2183) Proper
    handling of chunked request bodies to resolve phantom 503 in logs
-   [#2181](https://github.com/sanic-org/sanic/pull/2181) Resolve
    regression in exception logging
-   [#2201](https://github.com/sanic-org/sanic/pull/2201) Cleanup
    request info in pipelined requests

## Version 21.6.0

**Features**

-   [#2094](https://github.com/sanic-org/sanic/pull/2094) Add
    `response.eof()` method for closing a stream in a handler

-   [#2097](https://github.com/sanic-org/sanic/pull/2097) Allow
    case-insensitive HTTP Upgrade header

-   [#2104](https://github.com/sanic-org/sanic/pull/2104) Explicit
    usage of CIMultiDict getters

-   [#2109](https://github.com/sanic-org/sanic/pull/2109) Consistent
    use of error loggers

-   [#2114](https://github.com/sanic-org/sanic/pull/2114) New
    `client_ip` access of connection info instance

-   [#2119](https://github.com/sanic-org/sanic/pull/2119) Alternatate
    classes on instantiation for `Config` and `Sanic.ctx`

-   [#2133](https://github.com/sanic-org/sanic/pull/2133) Implement
    new version of AST router

    -   Proper differentiation between `alpha` and `string` param
        types
    -   Adds a `slug` param type, example: `<foo:slug>`
    -   Deprecates `<foo:string>` in favor of `<foo:str>`
    -   Deprecates `<foo:number>` in favor of `<foo:float>`
    -   Adds a `route.uri` accessor

-   [#2136](https://github.com/sanic-org/sanic/pull/2136) CLI
    improvements with new optional params

-   [#2137](https://github.com/sanic-org/sanic/pull/2137) Add
    `version_prefix` to URL builders

-   [#2140](https://github.com/sanic-org/sanic/pull/2140) Event
    autoregistration with `EVENT_AUTOREGISTER`

-   [#2146](https://github.com/sanic-org/sanic/pull/2146),
    [#2147](https://github.com/sanic-org/sanic/pull/2147) Require
    stricter names on `Sanic()` and `Blueprint()`

-   [#2150](https://github.com/sanic-org/sanic/pull/2150) Infinitely
    reusable and nestable `Blueprint` and `BlueprintGroup`

-   [#2154](https://github.com/sanic-org/sanic/pull/2154) Upgrade
    `websockets` dependency to min version

-   [#2155](https://github.com/sanic-org/sanic/pull/2155) Allow for
    maximum header sizes to be increased: `REQUEST_MAX_HEADER_SIZE`

-   [#2157](https://github.com/sanic-org/sanic/pull/2157) Allow app
    factory pattern in CLI

-   [#2165](https://github.com/sanic-org/sanic/pull/2165) Change HTTP
    methods to enums

-   [#2167](https://github.com/sanic-org/sanic/pull/2167) Allow
    auto-reloading on additional directories

-   [#2168](https://github.com/sanic-org/sanic/pull/2168) Add simple
    HTTP server to CLI

-   [#2170](https://github.com/sanic-org/sanic/pull/2170) Additional
    methods for attaching `HTTPMethodView`

**Bugfixes**

-   [#2091](https://github.com/sanic-org/sanic/pull/2091) Fix
    `UserWarning` in ASGI mode for missing `__slots__`
-   [#2099](https://github.com/sanic-org/sanic/pull/2099) Fix static
    request handler logging exception on 404
-   [#2110](https://github.com/sanic-org/sanic/pull/2110) Fix
    request.args.pop removes parameters inconsistently
-   [#2107](https://github.com/sanic-org/sanic/pull/2107) Fix type
    hinting for load_env
-   [#2127](https://github.com/sanic-org/sanic/pull/2127) Make sure
    ASGI ws subprotocols is a list
-   [#2128](https://github.com/sanic-org/sanic/pull/2128) Fix issue
    where Blueprint exception handlers do not consistently route to
    proper handler

**Deprecations and Removals**

-   [#2156](https://github.com/sanic-org/sanic/pull/2156) Remove
    config value `REQUEST_BUFFER_QUEUE_SIZE`
-   [#2170](https://github.com/sanic-org/sanic/pull/2170)
    `CompositionView` deprecated and marked for removal in 21.12
-   [#2172](https://github.com/sanic-org/sanic/pull/2170) Deprecate
    StreamingHTTPResponse

**Developer infrastructure**

-   [#2149](https://github.com/sanic-org/sanic/pull/2149) Remove
    Travis CI in favor of GitHub Actions

**Improved Documentation**

-   [#2164](https://github.com/sanic-org/sanic/pull/2164) Fix typo in
    documentation
-   [#2100](https://github.com/sanic-org/sanic/pull/2100) Remove
    documentation for non-existent arguments

## Version 21.3.2

**Bugfixes**

-   [#2081](https://github.com/sanic-org/sanic/pull/2081) Disable
    response timeout on websocket connections
-   [#2085](https://github.com/sanic-org/sanic/pull/2085) Make sure
    that blueprints with no slash is maintained when applied

## Version 21.3.1

**Bugfixes**

-   [#2076](https://github.com/sanic-org/sanic/pull/2076) Static files
    inside subfolders are not accessible (404)

## Version 21.3.0

[Release
Notes](https://sanicframework.org/en/guide/release-notes/v21.3.html)

**Features**

-   [#1876](https://github.com/sanic-org/sanic/pull/1876) Unified
    streaming server
-   [#2005](https://github.com/sanic-org/sanic/pull/2005) New
    `Request.id` property
-   [#2008](https://github.com/sanic-org/sanic/pull/2008) Allow
    Pathlib Path objects to be passed to `app.static()` helper
-   [#2010](https://github.com/sanic-org/sanic/pull/2010),
    [#2031](https://github.com/sanic-org/sanic/pull/2031) New
    startup-optimized router
-   [#2018](https://github.com/sanic-org/sanic/pull/2018)
    [#2064](https://github.com/sanic-org/sanic/pull/2064) Listeners
    for main server process
-   [#2032](https://github.com/sanic-org/sanic/pull/2032) Add raw
    header info to request object
-   [#2042](https://github.com/sanic-org/sanic/pull/2042)
    [#2060](https://github.com/sanic-org/sanic/pull/2060)
    [#2061](https://github.com/sanic-org/sanic/pull/2061) Introduce
    Signals API
-   [#2043](https://github.com/sanic-org/sanic/pull/2043) Add
    `__str__` and `__repr__` to Sanic and Blueprint
-   [#2047](https://github.com/sanic-org/sanic/pull/2047) Enable
    versioning and strict slash on BlueprintGroup
-   [#2053](https://github.com/sanic-org/sanic/pull/2053) Make
    `get_app` name argument optional
-   [#2055](https://github.com/sanic-org/sanic/pull/2055) JSON encoder
    change via app
-   [#2063](https://github.com/sanic-org/sanic/pull/2063) App and
    connection level context objects

**Bugfixes**

-   Resolve [#1420](https://github.com/sanic-org/sanic/pull/1420)
    `url_for` where `strict_slashes` are on for a path ending in `/`
-   Resolve [#1525](https://github.com/sanic-org/sanic/pull/1525)
    Routing is incorrect with some special characters
-   Resolve [#1653](https://github.com/sanic-org/sanic/pull/1653) ASGI
    headers in body
-   Resolve [#1722](https://github.com/sanic-org/sanic/pull/1722)
    Using curl in chunk mode
-   Resolve [#1730](https://github.com/sanic-org/sanic/pull/1730)
    Extra content in ASGI streaming response
-   Resolve [#1749](https://github.com/sanic-org/sanic/pull/1749)
    Restore broken middleware edge cases
-   Resolve [#1785](https://github.com/sanic-org/sanic/pull/1785)
    [#1804](https://github.com/sanic-org/sanic/pull/1804) Synchronous
    error handlers
-   Resolve [#1790](https://github.com/sanic-org/sanic/pull/1790)
    Protocol errors did not support async error handlers #1790
-   Resolve [#1824](https://github.com/sanic-org/sanic/pull/1824)
    Timeout on specific methods
-   Resolve [#1875](https://github.com/sanic-org/sanic/pull/1875)
    Response timeout error from all routes after returning several
    timeouts from a specific route
-   Resolve [#1988](https://github.com/sanic-org/sanic/pull/1988)
    Handling of safe methods with body
-   [#2001](https://github.com/sanic-org/sanic/pull/2001) Raise
    ValueError when cookie max-age is not an integer

**Deprecations and Removals**

-   [#2007](https://github.com/sanic-org/sanic/pull/2007) \* Config
    using `from_envvar` \* Config using `from_pyfile` \* Config using
    `from_object`
-   [#2009](https://github.com/sanic-org/sanic/pull/2009) Remove Sanic
    test client to its own package
-   [#2036](https://github.com/sanic-org/sanic/pull/2036),
    [#2037](https://github.com/sanic-org/sanic/pull/2037) Drop Python
    3.6 support
-   `Request.endpoint` deprecated in favor of `Request.name`
-   handler type name prefixes removed (static, websocket, etc)

**Developer infrastructure**

-   [#1995](https://github.com/sanic-org/sanic/pull/1995) Create
    FUNDING.yml
-   [#2013](https://github.com/sanic-org/sanic/pull/2013) Add codeql
    to CI pipeline
-   [#2038](https://github.com/sanic-org/sanic/pull/2038) Codecov
    configuration updates
-   [#2049](https://github.com/sanic-org/sanic/pull/2049) Updated
    setup.py to use `find_packages`

**Improved Documentation**

-   [#1218](https://github.com/sanic-org/sanic/pull/1218)
    Documentation for sanic.log.\* is missing
-   [#1608](https://github.com/sanic-org/sanic/pull/1608) Add
    documentation on calver and LTS
-   [#1731](https://github.com/sanic-org/sanic/pull/1731) Support
    mounting application elsewhere than at root path
-   [#2006](https://github.com/sanic-org/sanic/pull/2006) Upgraded
    type annotations and improved docstrings and API documentation
-   [#2052](https://github.com/sanic-org/sanic/pull/2052) Fix some
    examples and docs

**Miscellaneous**

-   `Request.route` property
-   Better websocket subprotocols support
-   Resolve bug with middleware in Blueprint Group when passed
    callable
-   Moves common logic between Blueprint and Sanic into mixins
-   Route naming changed to be more consistent
    -   request endpoint is the route name
    -   route names are fully namespaced
-   Some new convenience decorators:
    -   `@app.main_process_start`
    -   `@app.main_process_stop`
    -   `@app.before_server_start`
    -   `@app.after_server_start`
    -   `@app.before_server_stop`
    -   `@app.after_server_stop`
    -   `@app.on_request`
    -   `@app.on_response`
-   Fixes `Allow` header that did not include `HEAD`
-   Using \"name\" keyword in `url_for` for a \"static\" route where
    name does not exist
-   Cannot have multiple `app.static()` without using the named param
-   Using \"filename\" keyword in `url_for` on a file route
-   `unquote` in route def (not automatic)
-   `routes_all` is tuples
-   Handler arguments are kwarg only
-   `request.match_info` is now a cached (and not computed) property
-   Unknown static file mimetype is sent as `application/octet-stream`
-   `_host` keyword in `url_for`
-   Add charset default to `utf-8` for text and js content types if
    not specified
-   Version for a route can be str, float, or int
-   Route has ctx property
-   App has `routes_static`, `routes_dynamic`, `routes_regex`
-   [#2044](https://github.com/sanic-org/sanic/pull/2044) Code cleanup
    and refactoring
-   [#2072](https://github.com/sanic-org/sanic/pull/2072) Remove
    `BaseSanic` metaclass
-   [#2074](https://github.com/sanic-org/sanic/pull/2074) Performance
    adjustments in `handle_request_`

## Version 20.12.3

**Bugfixes**

-   [#2021](https://github.com/sanic-org/sanic/pull/2021) Remove
    prefix from websocket handler name

## Version 20.12.2

**Dependencies**

-   [#2026](https://github.com/sanic-org/sanic/pull/2026) Fix uvloop
    to 0.14 because 0.15 drops Python 3.6 support
-   [#2029](https://github.com/sanic-org/sanic/pull/2029) Remove old
    chardet requirement, add in hard multidict requirement

## Version 19.12.5

**Dependencies**

-   [#2025](https://github.com/sanic-org/sanic/pull/2025) Fix uvloop
    to 0.14 because 0.15 drops Python 3.6 support
-   [#2027](https://github.com/sanic-org/sanic/pull/2027) Remove old
    chardet requirement, add in hard multidict requirement

## Version 20.12.0

**Features**

-   [#1993](https://github.com/sanic-org/sanic/pull/1993) Add disable
    app registry
-   [#1945](https://github.com/sanic-org/sanic/pull/1945) Static route
    more verbose if file not found
-   [#1954](https://github.com/sanic-org/sanic/pull/1954) Fix static
    routes registration on a blueprint
-   [#1961](https://github.com/sanic-org/sanic/pull/1961) Add Python
    3.9 support
-   [#1962](https://github.com/sanic-org/sanic/pull/1962) Sanic CLI
    upgrade
-   [#1967](https://github.com/sanic-org/sanic/pull/1967) Update
    aiofile version requirements
-   [#1969](https://github.com/sanic-org/sanic/pull/1969) Update
    multidict version requirements
-   [#1970](https://github.com/sanic-org/sanic/pull/1970) Add py.typed
    file
-   [#1972](https://github.com/sanic-org/sanic/pull/1972) Speed
    optimization in request handler
-   [#1979](https://github.com/sanic-org/sanic/pull/1979) Add app
    registry and Sanic class level app retrieval

**Bugfixes**

-   [#1965](https://github.com/sanic-org/sanic/pull/1965) Fix Chunked
    Transport-Encoding in ASGI streaming response

**Deprecations and Removals**

-   [#1981](https://github.com/sanic-org/sanic/pull/1981) Cleanup and
    remove deprecated code

**Developer infrastructure**

-   [#1956](https://github.com/sanic-org/sanic/pull/1956) Fix load
    module test
-   [#1973](https://github.com/sanic-org/sanic/pull/1973) Transition
    Travis from .org to .com
-   [#1986](https://github.com/sanic-org/sanic/pull/1986) Update tox
    requirements

**Improved Documentation**

-   [#1951](https://github.com/sanic-org/sanic/pull/1951)
    Documentation improvements
-   [#1983](https://github.com/sanic-org/sanic/pull/1983) Remove
    duplicate contents in testing.rst
-   [#1984](https://github.com/sanic-org/sanic/pull/1984) Fix typo in
    routing.rst

## Version 20.9.1

**Bugfixes**

-   [#1954](https://github.com/sanic-org/sanic/pull/1954) Fix static
    route registration on blueprints
-   [#1957](https://github.com/sanic-org/sanic/pull/1957) Removes
    duplicate headers in ASGI streaming body

## Version 19.12.3

**Bugfixes**

-   [#1959](https://github.com/sanic-org/sanic/pull/1959) Removes
    duplicate headers in ASGI streaming body

## Version 20.9.0

**Features**

-   [#1887](https://github.com/sanic-org/sanic/pull/1887) Pass
    subprotocols in websockets (both sanic server and ASGI)
-   [#1894](https://github.com/sanic-org/sanic/pull/1894)
    Automatically set `test_mode` flag on app instance
-   [#1903](https://github.com/sanic-org/sanic/pull/1903) Add new
    unified method for updating app values
-   [#1906](https://github.com/sanic-org/sanic/pull/1906),
    [#1909](https://github.com/sanic-org/sanic/pull/1909) Adds
    WEBSOCKET_PING_TIMEOUT and WEBSOCKET_PING_INTERVAL configuration
    values
-   [#1935](https://github.com/sanic-org/sanic/pull/1935) httpx
    version dependency updated, it is slated for removal as a
    dependency in v20.12
-   [#1937](https://github.com/sanic-org/sanic/pull/1937) Added auto,
    text, and json fallback error handlers (in v21.3, the default will
    change form html to auto)

**Bugfixes**

-   [#1897](https://github.com/sanic-org/sanic/pull/1897) Resolves
    exception from unread bytes in stream

**Deprecations and Removals**

-   [#1903](https://github.com/sanic-org/sanic/pull/1903)
    config.from_envar, config.from_pyfile, and config.from_object are
    deprecated and set to be removed in v21.3

**Developer infrastructure**

-   [#1890](https://github.com/sanic-org/sanic/pull/1890),
    [#1891](https://github.com/sanic-org/sanic/pull/1891) Update isort
    calls to be compatible with new API
-   [#1893](https://github.com/sanic-org/sanic/pull/1893) Remove
    version section from setup.cfg
-   [#1924](https://github.com/sanic-org/sanic/pull/1924) Adding
    \--strict-markers for pytest

**Improved Documentation**

-   [#1922](https://github.com/sanic-org/sanic/pull/1922) Add explicit
    ASGI compliance to the README

## Version 20.6.3

**Bugfixes**

-   [#1884](https://github.com/sanic-org/sanic/pull/1884) Revert
    change to multiprocessing mode

## Version 20.6.2

**Features**

-   [#1641](https://github.com/sanic-org/sanic/pull/1641) Socket
    binding implemented properly for IPv6 and UNIX sockets

## Version 20.6.1

**Features**

-   [#1760](https://github.com/sanic-org/sanic/pull/1760) Add version
    parameter to websocket routes
-   [#1866](https://github.com/sanic-org/sanic/pull/1866) Add `sanic`
    as an entry point command
-   [#1880](https://github.com/sanic-org/sanic/pull/1880) Add handler
    names for websockets for url_for usage

**Bugfixes**

-   [#1776](https://github.com/sanic-org/sanic/pull/1776) Bug fix for
    host parameter issue with lists
-   [#1842](https://github.com/sanic-org/sanic/pull/1842) Fix static
    \_handler pickling error
-   [#1827](https://github.com/sanic-org/sanic/pull/1827) Fix reloader
    on OSX py38 and Windows
-   [#1848](https://github.com/sanic-org/sanic/pull/1848) Reverse
    named_response_middlware execution order, to match normal response
    middleware execution order
-   [#1853](https://github.com/sanic-org/sanic/pull/1853) Fix pickle
    error when attempting to pickle an application which contains
    websocket routes

**Deprecations and Removals**

-   [#1739](https://github.com/sanic-org/sanic/pull/1739) Deprecate
    body_bytes to merge into body

**Developer infrastructure**

-   [#1852](https://github.com/sanic-org/sanic/pull/1852) Fix naming
    of CI test env on Python nightlies
-   [#1857](https://github.com/sanic-org/sanic/pull/1857) Adjust
    websockets version to setup.py
-   [#1869](https://github.com/sanic-org/sanic/pull/1869) Wrap
    run()\'s \"protocol\" type annotation in Optional\[\]

**Improved Documentation**

-   [#1846](https://github.com/sanic-org/sanic/pull/1846) Update docs
    to clarify response middleware execution order
-   [#1865](https://github.com/sanic-org/sanic/pull/1865) Fixing rst
    format issue that was hiding documentation

## Version 20.6.0

*Released, but unintentionally omitting PR #1880, so was replaced by
20.6.1*

## Version 20.3.0

**Features**

-   [#1762](https://github.com/sanic-org/sanic/pull/1762) Add
    `srv.start_serving()` and `srv.serve_forever()` to `AsyncioServer`
-   [#1767](https://github.com/sanic-org/sanic/pull/1767) Make Sanic
    usable on `hypercorn -k trio myweb.app`
-   [#1768](https://github.com/sanic-org/sanic/pull/1768) No
    tracebacks on normal errors and prettier error pages
-   [#1769](https://github.com/sanic-org/sanic/pull/1769) Code cleanup
    in file responses
-   [#1793](https://github.com/sanic-org/sanic/pull/1793) and
    [#1819](https://github.com/sanic-org/sanic/pull/1819) Upgrade
    `str.format()` to f-strings
-   [#1798](https://github.com/sanic-org/sanic/pull/1798) Allow
    multiple workers on MacOS with Python 3.8
-   [#1820](https://github.com/sanic-org/sanic/pull/1820) Do not set
    content-type and content-length headers in exceptions

**Bugfixes**

-   [#1748](https://github.com/sanic-org/sanic/pull/1748) Remove loop
    argument in `asyncio.Event` in Python 3.8
-   [#1764](https://github.com/sanic-org/sanic/pull/1764) Allow route
    decorators to stack up again
-   [#1789](https://github.com/sanic-org/sanic/pull/1789) Fix tests
    using hosts yielding incorrect `url_for`
-   [#1808](https://github.com/sanic-org/sanic/pull/1808) Fix Ctrl+C
    and tests on Windows

**Deprecations and Removals**

-   [#1800](https://github.com/sanic-org/sanic/pull/1800) Begin
    deprecation in way of first-class streaming, removal of
    `body_init`, `body_push`, and `body_finish`
-   [#1801](https://github.com/sanic-org/sanic/pull/1801) Complete
    deprecation from
    [#1666](https://github.com/sanic-org/sanic/pull/1666) of
    dictionary context on `request` objects.
-   [#1807](https://github.com/sanic-org/sanic/pull/1807) Remove
    server config args that can be read directly from app
-   [#1818](https://github.com/sanic-org/sanic/pull/1818) Complete
    deprecation of `app.remove_route` and `request.raw_args`

**Dependencies**

-   [#1794](https://github.com/sanic-org/sanic/pull/1794) Bump `httpx`
    to 0.11.1
-   [#1806](https://github.com/sanic-org/sanic/pull/1806) Import
    `ASGIDispatch` from top-level `httpx` (from third-party
    deprecation)

**Developer infrastructure**

-   [#1833](https://github.com/sanic-org/sanic/pull/1833) Resolve
    broken documentation builds

**Improved Documentation**

-   [#1755](https://github.com/sanic-org/sanic/pull/1755) Usage of
    `response.empty()`
-   [#1778](https://github.com/sanic-org/sanic/pull/1778) Update
    README
-   [#1783](https://github.com/sanic-org/sanic/pull/1783) Fix typo
-   [#1784](https://github.com/sanic-org/sanic/pull/1784) Corrected
    changelog for docs move of MD to RST
    ([#1691](https://github.com/sanic-org/sanic/pull/1691))
-   [#1803](https://github.com/sanic-org/sanic/pull/1803) Update
    config docs to match DEFAULT_CONFIG
-   [#1814](https://github.com/sanic-org/sanic/pull/1814) Update
    getting_started.rst
-   [#1821](https://github.com/sanic-org/sanic/pull/1821) Update to
    deployment
-   [#1822](https://github.com/sanic-org/sanic/pull/1822) Update docs
    with changes done in 20.3
-   [#1834](https://github.com/sanic-org/sanic/pull/1834) Order of
    listeners

## Version 19.12.0

**Bugfixes**

-   Fix blueprint middleware application

    Currently, any blueprint middleware registered, irrespective of
    which blueprint was used to do so, was being applied to all of the
    routes created by the `@app` and `@blueprint` alike.

    As part of this change, the blueprint based middleware application
    is enforced based on where they are registered.

    -   If you register a middleware via `@blueprint.middleware` then it
        will apply only to the routes defined by the blueprint.
    -   If you register a middleware via `@blueprint_group.middleware`
        then it will apply to all blueprint based routes that are part
        of the group.
    -   If you define a middleware via `@app.middleware` then it will be
        applied on all available routes
        ([#37](https://github.com/sanic-org/sanic/issues/37))

-   Fix [url_for]{.title-ref} behavior with missing SERVER_NAME

    If the [SERVER_NAME]{.title-ref} was missing in the
    [app.config]{.title-ref} entity, the [url_for]{.title-ref} on the
    [request]{.title-ref} and [app]{.title-ref} were failing due to an
    [AttributeError]{.title-ref}. This fix makes the availability of
    [SERVER_NAME]{.title-ref} on our [app.config]{.title-ref} an
    optional behavior.
    ([#1707](https://github.com/sanic-org/sanic/issues/1707))

**Improved Documentation**

-   Move docs from MD to RST

    Moved all docs from markdown to restructured text like the rest of
    the docs to unify the scheme and make it easier in the future to
    update documentation.
    ([#1691](https://github.com/sanic-org/sanic/issues/1691))

-   Fix documentation for [get]{.title-ref} and [getlist]{.title-ref} of
    the [request.args]{.title-ref}

    Add additional example for showing the usage of
    [getlist]{.title-ref} and fix the documentation string for
    [request.args]{.title-ref} behavior
    ([#1704](https://github.com/sanic-org/sanic/issues/1704))

## Version 19.6.3

**Features**

-   Enable Towncrier Support

    As part of this feature, [towncrier]{.title-ref} is being introduced
    as a mechanism to partially automate the process of generating and
    managing change logs as part of each of pull requests.
    ([#1631](https://github.com/sanic-org/sanic/issues/1631))

**Improved Documentation**

-   Documentation infrastructure changes
    -   Enable having a single common [CHANGELOG]{.title-ref} file for
        both GitHub page and documentation
    -   Fix Sphinix deprecation warnings
    -   Fix documentation warnings due to invalid [rst]{.title-ref}
        indentation
    -   Enable common contribution guidelines file across GitHub and
        documentation via [CONTRIBUTING.rst]{.title-ref}
        ([#1631](https://github.com/sanic-org/sanic/issues/1631))

## Version 19.6.2

**Features**

-   [#1562](https://github.com/sanic-org/sanic/pull/1562) Remove
    `aiohttp` dependency and create new `SanicTestClient` based upon
    [requests-async](https://github.com/encode/requests-async)
-   [#1475](https://github.com/sanic-org/sanic/pull/1475) Added ASGI
    support (Beta)
-   [#1436](https://github.com/sanic-org/sanic/pull/1436) Add
    Configure support from object string

**Bugfixes**

-   [#1587](https://github.com/sanic-org/sanic/pull/1587) Add missing
    handle for Expect header.
-   [#1560](https://github.com/sanic-org/sanic/pull/1560) Allow to
    disable Transfer-Encoding: chunked.
-   [#1558](https://github.com/sanic-org/sanic/pull/1558) Fix graceful
    shutdown.
-   [#1594](https://github.com/sanic-org/sanic/pull/1594) Strict
    Slashes behavior fix

**Deprecations and Removals**

-   [#1544](https://github.com/sanic-org/sanic/pull/1544) Drop
    dependency on distutil
-   [#1562](https://github.com/sanic-org/sanic/pull/1562) Drop support
    for Python 3.5
-   [#1568](https://github.com/sanic-org/sanic/pull/1568) Deprecate
    route removal.

.. warning:: Warning

    Sanic will not support Python 3.5 from version 19.6 and forward. 
    However, version 18.12LTS will have its support period extended thru
    December 2020, and therefore passing Python\'s official support version
    3.5, which is set to expire in September 2020.

## Version 19.3

**Features**

-   [#1497](https://github.com/sanic-org/sanic/pull/1497) Add support
    for zero-length and RFC 5987 encoded filename for
    multipart/form-data requests.

-   [#1484](https://github.com/sanic-org/sanic/pull/1484) The type of
    `expires` attribute of `sanic.cookies.Cookie` is now enforced to
    be of type `datetime`.

-   [#1482](https://github.com/sanic-org/sanic/pull/1482) Add support
    for the `stream` parameter of `sanic.Sanic.add_route()` available
    to `sanic.Blueprint.add_route()`.

-   [#1481](https://github.com/sanic-org/sanic/pull/1481) Accept
    negative values for route parameters with type `int` or `number`.

-   [#1476](https://github.com/sanic-org/sanic/pull/1476) Deprecated
    the use of `sanic.request.Request.raw_args` - it has a fundamental
    flaw in which is drops repeated query string parameters. Added
    `sanic.request.Request.query_args` as a replacement for the
    original use-case.

-   [#1472](https://github.com/sanic-org/sanic/pull/1472) Remove an
    unwanted `None` check in Request class `repr` implementation. This
    changes the default `repr` of a Request from `<Request>` to
    `<Request: None />`

-   [#1470](https://github.com/sanic-org/sanic/pull/1470) Added 2 new
    parameters to `sanic.app.Sanic.create_server`:

    -   `return_asyncio_server` - whether to return an
        asyncio.Server.
    -   `asyncio_server_kwargs` - kwargs to pass to
        `loop.create_server` for the event loop that sanic is using.
    >
    This is a breaking change.

-   [#1499](https://github.com/sanic-org/sanic/pull/1499) Added a set
    of test cases that test and benchmark route resolution.

-   [#1457](https://github.com/sanic-org/sanic/pull/1457) The type of
    the `"max-age"` value in a `sanic.cookies.Cookie` is now enforced
    to be an integer. Non-integer values are replaced with `0`.

-   [#1445](https://github.com/sanic-org/sanic/pull/1445) Added the
    `endpoint` attribute to an incoming `request`, containing the name
    of the handler function.

-   [#1423](https://github.com/sanic-org/sanic/pull/1423) Improved
    request streaming. `request.stream` is now a bounded-size buffer
    instead of an unbounded queue. Callers must now call
    `await request.stream.read()` instead of
    `await request.stream.get()` to read each portion of the body.

    This is a breaking change.

**Bugfixes**

-   [#1502](https://github.com/sanic-org/sanic/pull/1502) Sanic was
    prefetching `time.time()` and updating it once per second to avoid
    excessive `time.time()` calls. The implementation was observed to
    cause memory leaks in some cases. The benefit of the prefetch
    appeared to negligible, so this has been removed. Fixes
    [#1500](https://github.com/sanic-org/sanic/pull/1500)
-   [#1501](https://github.com/sanic-org/sanic/pull/1501) Fix a bug in
    the auto-reloader when the process was launched as a module i.e.
    `python -m init0.mod1` where the sanic server is started in
    `init0/mod1.py` with `debug` enabled and imports another module in
    `init0`.
-   [#1376](https://github.com/sanic-org/sanic/pull/1376) Allow sanic
    test client to bind to a random port by specifying `port=None`
    when constructing a `SanicTestClient`
-   [#1399](https://github.com/sanic-org/sanic/pull/1399) Added the
    ability to specify middleware on a blueprint group, so that all
    routes produced from the blueprints in the group have the
    middleware applied.
-   [#1442](https://github.com/sanic-org/sanic/pull/1442) Allow the
    the use the `SANIC_ACCESS_LOG` environment variable to
    enable/disable the access log when not explicitly passed to
    `app.run()`. This allows the access log to be disabled for example
    when running via gunicorn.

**Developer infrastructure**

-   [#1529](https://github.com/sanic-org/sanic/pull/1529) Update
    project PyPI credentials
-   [#1515](https://github.com/sanic-org/sanic/pull/1515) fix linter
    issue causing travis build failures (fix #1514)
-   [#1490](https://github.com/sanic-org/sanic/pull/1490) Fix python
    version in doc build
-   [#1478](https://github.com/sanic-org/sanic/pull/1478) Upgrade
    setuptools version and use native docutils in doc build
-   [#1464](https://github.com/sanic-org/sanic/pull/1464) Upgrade
    pytest, and fix caplog unit tests

**Improved Documentation**

-   [#1516](https://github.com/sanic-org/sanic/pull/1516) Fix typo at
    the exception documentation
-   [#1510](https://github.com/sanic-org/sanic/pull/1510) fix typo in
    Asyncio example
-   [#1486](https://github.com/sanic-org/sanic/pull/1486)
    Documentation typo
-   [#1477](https://github.com/sanic-org/sanic/pull/1477) Fix grammar
    in README.md
-   [#1489](https://github.com/sanic-org/sanic/pull/1489) Added
    \"databases\" to the extensions list
-   [#1483](https://github.com/sanic-org/sanic/pull/1483) Add
    sanic-zipkin to extensions list
-   [#1487](https://github.com/sanic-org/sanic/pull/1487) Removed link
    to deleted repo, Sanic-OAuth, from the extensions list
-   [#1460](https://github.com/sanic-org/sanic/pull/1460) 18.12
    changelog
-   [#1449](https://github.com/sanic-org/sanic/pull/1449) Add example
    of amending request object
-   [#1446](https://github.com/sanic-org/sanic/pull/1446) Update
    README
-   [#1444](https://github.com/sanic-org/sanic/pull/1444) Update
    README
-   [#1443](https://github.com/sanic-org/sanic/pull/1443) Update
    README, including new logo
-   [#1440](https://github.com/sanic-org/sanic/pull/1440) fix minor
    type and pip install instruction mismatch
-   [#1424](https://github.com/sanic-org/sanic/pull/1424)
    Documentation Enhancements

Note: 19.3.0 was skipped for packagement purposes and not released on
PyPI

## Version 18.12

### 18.12.0

-   Changes:

    -   Improved codebase test coverage from 81% to 91%.
    -   Added stream_large_files and host examples in static_file
        document
    -   Added methods to append and finish body content on Request
        (#1379)
    -   Integrated with .appveyor.yml for windows ci support
    -   Added documentation for AF_INET6 and AF_UNIX socket usage
    -   Adopt black/isort for codestyle
    -   Cancel task when connection_lost
    -   Simplify request ip and port retrieval logic
    -   Handle config error in load config file.
    -   Integrate with codecov for CI
    -   Add missed documentation for config section.
    -   Deprecate Handler.log
    -   Pinned httptools requirement to version 0.0.10+

-   Fixes:

    -   Fix `remove_entity_headers` helper function (#1415)
    -   Fix TypeError when use Blueprint.group() to group blueprint
        with default url_prefix, Use os.path.normpath to avoid invalid
        url_prefix like api//v1 f8a6af1 Rename the `http` module to
        `helpers` to prevent conflicts with the built-in Python http
        library (fixes #1323)
    -   Fix unittests on windows
    -   Fix Namespacing of sanic logger
    -   Fix missing quotes in decorator example
    -   Fix redirect with quoted param
    -   Fix doc for latest blueprint code
    -   Fix build of latex documentation relating to markdown lists
    -   Fix loop exception handling in app.py
    -   Fix content length mismatch in windows and other platform
    -   Fix Range header handling for static files (#1402)
    -   Fix the logger and make it work (#1397)
    -   Fix type pikcle-\>pickle in multiprocessing test
    -   Fix pickling blueprints Change the string passed in the
        \"name\" section of the namedtuples in Blueprint to match the
        name of the Blueprint module attribute name. This allows
        blueprints to be pickled and unpickled, without errors, which
        is a requirement of running Sanic in multiprocessing mode in
        Windows. Added a test for pickling and unpickling blueprints
        Added a test for pickling and unpickling sanic itself Added a
        test for enabling multiprocessing on an app with a blueprint
        (only useful to catch this bug if the tests are run on
        Windows).
    -   Fix document for logging

## Version 0.8

**0.8.3**

-   Changes:
    -   Ownership changed to org \'sanic-org\'

**0.8.0**

-   Changes:
    -   Add Server-Sent Events extension (Innokenty Lebedev)
    -   Graceful handling of request_handler_task cancellation (Ashley
        Sommer)
    -   Sanitize URL before redirection (aveao)
    -   Add url_bytes to request (johndoe46)
    -   py37 support for travisci (yunstanford)
    -   Auto reloader support for OSX (garyo)
    -   Add UUID route support (Volodymyr Maksymiv)
    -   Add pausable response streams (Ashley Sommer)
    -   Add weakref to request slots (vopankov)
    -   remove ubuntu 12.04 from test fixture due to deprecation
        (yunstanford)
    -   Allow streaming handlers in add_route (kinware)
    -   use travis_retry for tox (Raphael Deem)
    -   update aiohttp version for test client (yunstanford)
    -   add redirect import for clarity (yingshaoxo)
    -   Update HTTP Entity headers (Arnulfo Solís)
    -   Add register_listener method (Stephan Fitzpatrick)
    -   Remove uvloop/ujson dependencies for Windows (abuckenheimer)
    -   Content-length header on 204/304 responses (Arnulfo Solís)
    -   Extend WebSocketProtocol arguments and add docs (Bob Olde
        Hampsink, yunstanford)
    -   Update development status from pre-alpha to beta (Maksim
        Anisenkov)
    -   KeepAlive Timeout log level changed to debug (Arnulfo Solís)
    -   Pin pytest to 3.3.2 because of pytest-dev/pytest#3170 (Maksim
        Aniskenov)
    -   Install Python 3.5 and 3.6 on docker container for tests (Shahin
        Azad)
    -   Add support for blueprint groups and nesting (Elias Tarhini)
    -   Remove uvloop for windows setup (Aleksandr Kurlov)
    -   Auto Reload (Yaser Amari)
    -   Documentation updates/fixups (multiple contributors)
-   Fixes:
    -   Fix: auto_reload in Linux (Ashley Sommer)
    -   Fix: broken tests for aiohttp \>= 3.3.0 (Ashley Sommer)
    -   Fix: disable auto_reload by default on windows (abuckenheimer)
    -   Fix (1143): Turn off access log with gunicorn (hqy)
    -   Fix (1268): Support status code for file response (Cosmo Borsky)
    -   Fix (1266): Add content_type flag to Sanic.static (Cosmo Borsky)
    -   Fix: subprotocols parameter missing from add_websocket_route
        (ciscorn)
    -   Fix (1242): Responses for CI header (yunstanford)
    -   Fix (1237): add version constraint for websockets (yunstanford)
    -   Fix (1231): memory leak - always release resource (Phillip Xu)
    -   Fix (1221): make request truthy if transport exists (Raphael
        Deem)
    -   Fix failing tests for aiohttp\>=3.1.0 (Ashley Sommer)
    -   Fix try_everything examples (PyManiacGR, kot83)
    -   Fix (1158): default to auto_reload in debug mode (Raphael Deem)
    -   Fix (1136): ErrorHandler.response handler call too restrictive
        (Julien Castiaux)
    -   Fix: raw requires bytes-like object (cloudship)
    -   Fix (1120): passing a list in to a route decorator\'s host arg
        (Timothy Ebiuwhe)
    -   Fix: Bug in multipart/form-data parser (DirkGuijt)
    -   Fix: Exception for missing parameter when value is null
        (NyanKiyoshi)
    -   Fix: Parameter check (Howie Hu)
    -   Fix (1089): Routing issue with named parameters and different
        methods (yunstanford)
    -   Fix (1085): Signal handling in multi-worker mode (yunstanford)
    -   Fix: single quote in readme.rst (Cosven)
    -   Fix: method typos (Dmitry Dygalo)
    -   Fix: log_response correct output for ip and port (Wibowo
        Arindrarto)
    -   Fix (1042): Exception Handling (Raphael Deem)
    -   Fix: Chinese URIs (Howie Hu)
    -   Fix (1079): timeout bug when self.transport is None (Raphael
        Deem)
    -   Fix (1074): fix strict_slashes when route has slash (Raphael
        Deem)
    -   Fix (1050): add samesite cookie to cookie keys (Raphael Deem)
    -   Fix (1065): allow add_task after server starts (Raphael Deem)
    -   Fix (1061): double quotes in unauthorized exception (Raphael
        Deem)
    -   Fix (1062): inject the app in add_task method (Raphael Deem)
    -   Fix: update environment.yml for readthedocs (Eli Uriegas)
    -   Fix: Cancel request task when response timeout is triggered
        (Jeong YunWon)
    -   Fix (1052): Method not allowed response for RFC7231 compliance
        (Raphael Deem)
    -   Fix: IPv6 Address and Socket Data Format (Dan Palmer)

Note: Changelog was unmaintained between 0.1 and 0.7

## Version 0.1

**0.1.7**

-   Reversed static url and directory arguments to meet spec

**0.1.6**

-   Static files
-   Lazy Cookie Loading

**0.1.5**

-   Cookies
-   Blueprint listeners and ordering
-   Faster Router
-   Fix: Incomplete file reads on medium+ sized post requests
-   Breaking: after_start and before_stop now pass sanic as their
    first argument

**0.1.4**

-   Multiprocessing

**0.1.3**

-   Blueprint support
-   Faster Response processing

**0.1.1 - 0.1.2**

-   Struggling to update pypi via CI

**0.1.0**

-   Released to public

---

### Guide Content En Guide Advanced Class Based Views (`guide/content/en/guide/advanced/class-based-views.md`)

# Class Based Views

## Why use them?

.. column::

    ### The problem

    A common pattern when designing an API is to have multiple functionality on the same endpoint that depends upon the HTTP method.

    While both of these options work, they are not good design practices and may be hard to maintain over time as your project grows.

.. column::

    ```python
    @app.get("/foo")
    async def foo_get(request):
        ...

    @app.post("/foo")
    async def foo_post(request):
        ...

    @app.put("/foo")
    async def foo_put(request):
        ...

    @app.route("/bar", methods=["GET", "POST", "PATCH"])
    async def bar(request):
        if request.method == "GET":
            ...

        elif request.method == "POST":
            ...
            
        elif request.method == "PATCH":
            ...
    ```


.. column::

    ### The solution

    Class-based views are simply classes that implement response behavior to requests. They provide a way to compartmentalize handling of different HTTP request types at the same endpoint.

.. column::

    ```python
    from sanic.views import HTTPMethodView

    class FooBar(HTTPMethodView):
        async def get(self, request):
            ...
        
        async def post(self, request):
            ...
        
        async def put(self, request):
            ...

    app.add_route(FooBar.as_view(), "/foobar")
    ```

## Defining a view

A class-based view should subclass :class:`sanic.views.HTTPMethodView`. You can then implement class methods with the name of the corresponding HTTP method. If a request is received that has no defined method, a `405: Method not allowed` response will be generated.

.. column::

    To register a class-based view on an endpoint, the `app.add_route` method is used. The first argument should be the defined class with the method `as_view` invoked, and the second should be the URL endpoint.

    The available methods are:

    - get
    - post
    - put
    - patch
    - delete
    - head
    - options

.. column::

    ```python
    from sanic.views import HTTPMethodView
    from sanic.response import text

    class SimpleView(HTTPMethodView):

      def get(self, request):
          return text("I am get method")

      # You can also use async syntax
      async def post(self, request):
          return text("I am post method")

      def put(self, request):
          return text("I am put method")

      def patch(self, request):
          return text("I am patch method")

      def delete(self, request):
          return text("I am delete method")

    app.add_route(SimpleView.as_view(), "/")
    ```

## Path parameters


.. column::

    You can use path parameters exactly as discussed in [the routing section](../basics/routing.md).

.. column::

    ```python
    class NameView(HTTPMethodView):

      def get(self, request, name):
        return text("Hello {}".format(name))

    app.add_route(NameView.as_view(), "/<name>")
    ```

## Decorators

As discussed in [the decorators section](../best-practices/decorators.md), often you will need to add functionality to endpoints with the use of decorators. You have two options with CBV:

1. Apply to _all_ HTTP methods in the view
2. Apply individually to HTTP methods in the view

Let's see what the options look like:

.. column::

    ### Apply to all methods

    If you want to add any decorators to the class, you can set the `decorators` class variable. These will be applied to the class when `as_view` is called.

.. column::

    ```python
    class ViewWithDecorator(HTTPMethodView):
      decorators = [some_decorator_here]

      def get(self, request, name):
        return text("Hello I have a decorator")

      def post(self, request, name):
        return text("Hello I also have a decorator")

    app.add_route(ViewWithDecorator.as_view(), "/url")
    ```


.. column::

    ### Apply to individual methods

    But if you just want to decorate some methods and not all methods, you can as shown here.

.. column::

    ```python
    class ViewWithSomeDecorator(HTTPMethodView):

        @staticmethod
        @some_decorator_here
        def get(request, name):
            return text("Hello I have a decorator")

        def post(self, request, name):
            return text("Hello I do not have any decorators")

        @some_decorator_here
        def patch(self, request, name):
            return text("Hello I have a decorator")
    ```

## Generating a URL

.. column::

    This works just like [generating any other URL](../basics/routing.md#generating-a-url), except that the class name is a part of the endpoint.

.. column::

    ```python
    @app.route("/")
    def index(request):
        url = app.url_for("SpecialClassView")
        return redirect(url)

    class SpecialClassView(HTTPMethodView):
        def get(self, request):
            return text("Hello from the Special Class View!")

    app.add_route(SpecialClassView.as_view(), "/special_class_view")
    ```

---

### Guide Content En Guide Advanced Commands (`guide/content/en/guide/advanced/commands.md`)

# Custom CLI Commands

Sanic ships with a [CLI](../running/running.md#running-via-command) for running the Sanic server. Sometimes, you may have the need to enhance that CLI to run your own custom commands. Commands are invoked using the following basic pattern:

```sh
sanic path.to:app exec <command> [--arg=value]
```

.. column::

    To enable this, you can use your `Sanic` app instance to wrap functions that can be callable from the CLI using the `@app.command` decorator.

.. column::

    ```python
    @app.command
    async def hello(name="world"):
        print(f"Hello, {name}.")
    ```
    
.. column::

    Now, you can easily invoke this command using the `exec` action. 
    
.. column::

    ```sh
    sanic path.to:app exec hello --name=Adam
    ```
    
Command handlers can be either synchronous or asynchronous. The handler can accept any number of keyword arguments, which will be passed in from the CLI.

.. column::

    By default, the name of the function will be the command name. You can override this by passing the `name` argument to the decorator.
    
.. column::

    ```python
    @app.command(name="greet")
    async def hello(name="world"):
        print(f"Hello, {name}.")
    ```
    
    ```sh
    sanic path.to:app exec greet --name=Adam
    ```

.. warning::

    This feature is still in **BETA** and may change in future versions. There is no type coercion or validation on the arguments passed in from the CLI, and the CLI will ignore any return values from the command handler. Future enhancements and changes are likely.

*Added in v24.12*

---

### Guide Content En Guide Advanced Proxy Headers (`guide/content/en/guide/advanced/proxy-headers.md`)

# Proxy configuration

When you use a reverse proxy server (e.g. nginx), the value of `request.ip` will contain the IP of a proxy, typically `127.0.0.1`. Almost always, this is **not** what you will want.

Sanic may be configured to use proxy headers for determining the true client IP, available as `request.remote_addr`. The full external URL is also constructed from header fields _if available_.


.. tip:: Heads up

    Without proper precautions, a malicious client may use proxy headers to spoof its own IP. To avoid such issues, Sanic does not use any proxy headers unless explicitly enabled.



.. column::

    Services behind reverse proxies must configure one or more of the following [configuration values](../deployment/configuration.md):

    - `FORWARDED_SECRET`
    - `REAL_IP_HEADER`
    - `PROXIES_COUNT`

.. column::

    ```python
    app.config.FORWARDED_SECRET = "super-duper-secret"
    app.config.REAL_IP_HEADER = "CF-Connecting-IP"
    app.config.PROXIES_COUNT = 2
    ```

## Forwarded header

In order to use the `Forwarded` header, you should set `app.config.FORWARDED_SECRET` to a value known to the trusted proxy server. The secret is used to securely identify a specific proxy server.

Sanic ignores any elements without the secret key, and will not even parse the header if no secret is set.

All other proxy headers are ignored once a trusted forwarded element is found, as it already carries complete information about the client.

To learn more about the `Forwarded` header, read the related [MDN](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Forwarded) and [Nginx](https://www.nginx.com/resources/wiki/start/topics/examples/forwarded/) articles.

## Traditional proxy headers

### IP Headers

When your proxy forwards you the IP address in a known header, you can tell Sanic what that is with the `REAL_IP_HEADER` config value.

### X-Forwarded-For

This header typically contains a chain of IP addresses through each layer of a proxy. Setting `PROXIES_COUNT` tells Sanic how deep to look to get an actual IP address for the client. This value should equal the _expected_ number of IP addresses in the chain.

### Other X-headers

If a client IP is found by one of these methods, Sanic uses the following headers for URL parts:

- x-forwarded-proto
- x-forwarded-host
- x-forwarded-port
- x-forwarded-path
- x-scheme

## Examples

In the following examples, all requests will assume that the endpoint looks like this:
```python
@app.route("/fwd")
async def forwarded(request):
    return json(
        {
            "remote_addr": request.remote_addr,
            "scheme": request.scheme,
            "server_name": request.server_name,
            "server_port": request.server_port,
            "forwarded": request.forwarded,
        }
    )
```

---

##### Example 1

Without configured FORWARDED_SECRET, x-headers should be respected

```sh
curl localhost:8000/fwd \
	-H 'Forwarded: for=1.1.1.1, for=injected;host=", for="[::2]";proto=https;host=me.tld;path="/app/";secret=mySecret,for=broken;;secret=b0rked, for=127.0.0.3;scheme=http;port=1234' \
	-H "X-Real-IP: 127.0.0.2" \
	-H "X-Forwarded-For: 127.0.1.1" \
	-H "X-Scheme: ws" \
	-H "Host: local.site" | jq
```

.. column::

    ```python
    # Sanic application config
    app.config.PROXIES_COUNT = 1
    app.config.REAL_IP_HEADER = "x-real-ip"
    ```

.. column::

    ```bash
    # curl response
    {
      "remote_addr": "127.0.0.2",
      "scheme": "ws",
      "server_name": "local.site",
      "server_port": 80,
      "forwarded": {
        "for": "127.0.0.2",
        "proto": "ws"
      }
    }
    ```

---

##### Example 2

FORWARDED_SECRET now configured

```sh
curl localhost:8000/fwd \
	-H 'Forwarded: for=1.1.1.1, for=injected;host=", for="[::2]";proto=https;host=me.tld;path="/app/";secret=mySecret,for=broken;;secret=b0rked, for=127.0.0.3;scheme=http;port=1234' \
	-H "X-Real-IP: 127.0.0.2" \
	-H "X-Forwarded-For: 127.0.1.1" \
	-H "X-Scheme: ws" \
	-H "Host: local.site" | jq
```

.. column::

    ```python
    # Sanic application config
    app.config.PROXIES_COUNT = 1
    app.config.REAL_IP_HEADER = "x-real-ip"
    app.config.FORWARDED_SECRET = "mySecret"
    ```

.. column::

    ```bash
    # curl response
    {
      "remote_addr": "[::2]",
      "scheme": "https",
      "server_name": "me.tld",
      "server_port": 443,
      "forwarded": {
        "for": "[::2]",
        "proto": "https",
        "host": "me.tld",
        "path": "/app/",
        "secret": "mySecret"
      }
    }
    ```

---

##### Example 3

Empty Forwarded header -> use X-headers

```sh
curl localhost:8000/fwd \
	-H "X-Real-IP: 127.0.0.2" \
	-H "X-Forwarded-For: 127.0.1.1" \
	-H "X-Scheme: ws" \
	-H "Host: local.site" | jq
```

.. column::

    ```python
    # Sanic application config
    app.config.PROXIES_COUNT = 1
    app.config.REAL_IP_HEADER = "x-real-ip"
    app.config.FORWARDED_SECRET = "mySecret"
    ```

.. column::

    ```bash
    # curl response
    {
      "remote_addr": "127.0.0.2",
      "scheme": "ws",
      "server_name": "local.site",
      "server_port": 80,
      "forwarded": {
        "for": "127.0.0.2",
        "proto": "ws"
      }
    }
    ```

---

##### Example 4

Header present but not matching anything

```sh
curl localhost:8000/fwd \
	-H "Forwarded: nomatch" | jq
```

.. column::

    ```python
    # Sanic application config
    app.config.PROXIES_COUNT = 1
    app.config.REAL_IP_HEADER = "x-real-ip"
    app.config.FORWARDED_SECRET = "mySecret"
    ```

.. column::

    ```bash
    # curl response
    {
      "remote_addr": "",
      "scheme": "http",
      "server_name": "localhost",
      "server_port": 8000,
      "forwarded": {}
    }

    ```

---

##### Example 5

Forwarded header present but no matching secret -> use X-headers

```sh
curl localhost:8000/fwd \
	-H "Forwarded: for=1.1.1.1;secret=x, for=127.0.0.1" \
	-H "X-Real-IP: 127.0.0.2" | jq
```

.. column::

    ```python
    # Sanic application config
    app.config.PROXIES_COUNT = 1
    app.config.REAL_IP_HEADER = "x-real-ip"
    app.config.FORWARDED_SECRET = "mySecret"
    ```

.. column::

    ```bash
    # curl response
    {
      "remote_addr": "127.0.0.2",
      "scheme": "http",
      "server_name": "localhost",
      "server_port": 8000,
      "forwarded": {
        "for": "127.0.0.2"
      }
    }
    ```

---

##### Example 6

Different formatting and hitting both ends of the header

```sh
curl localhost:8000/fwd \
	-H 'Forwarded: Secret="mySecret";For=127.0.0.4;Port=1234' | jq
```

.. column::

    ```python
    # Sanic application config
    app.config.PROXIES_COUNT = 1
    app.config.REAL_IP_HEADER = "x-real-ip"
    app.config.FORWARDED_SECRET = "mySecret"
    ```

.. column::

    ```bash
    # curl response
    {
      "remote_addr": "127.0.0.4",
      "scheme": "http",
      "server_name": "localhost",
      "server_port": 1234,
      "forwarded": {
        "secret": "mySecret",
        "for": "127.0.0.4",
        "port": 1234
      }
    }
    ```

---

##### Example 7

Test escapes (modify this if you see anyone implementing quoted-pairs)

```sh
curl localhost:8000/fwd \
	-H 'Forwarded: for=test;quoted="\,x=x;y=\";secret=mySecret' | jq
```

.. column::

    ```python
    # Sanic application config
    app.config.PROXIES_COUNT = 1
    app.config.REAL_IP_HEADER = "x-real-ip"
    app.config.FORWARDED_SECRET = "mySecret"
    ```

.. column::

    ```bash
    # curl response
    {
      "remote_addr": "test",
      "scheme": "http",
      "server_name": "localhost",
      "server_port": 8000,
      "forwarded": {
        "for": "test",
        "quoted": "\\,x=x;y=\\",
        "secret": "mySecret"
      }
    }
    ```

---

##### Example 8

Secret insulated by malformed field #1

```sh
curl localhost:8000/fwd \
	-H 'Forwarded: for=test;secret=mySecret;b0rked;proto=wss;' | jq
```

.. column::

    ```python
    # Sanic application config
    app.config.PROXIES_COUNT = 1
    app.config.REAL_IP_HEADER = "x-real-ip"
    app.config.FORWARDED_SECRET = "mySecret"
    ```

.. column::

    ```bash
    # curl response
    {
      "remote_addr": "test",
      "scheme": "http",
      "server_name": "localhost",
      "server_port": 8000,
      "forwarded": {
        "for": "test",
        "secret": "mySecret"
      }
    }
    ```

---

##### Example 9

Secret insulated by malformed field #2

```sh
curl localhost:8000/fwd \
	-H 'Forwarded: for=test;b0rked;secret=mySecret;proto=wss' | jq
```

.. column::

    ```python
    # Sanic application config
    app.config.PROXIES_COUNT = 1
    app.config.REAL_IP_HEADER = "x-real-ip"
    app.config.FORWARDED_SECRET = "mySecret"
    ```

.. column::

    ```bash
    # curl response
    {
      "remote_addr": "",
      "scheme": "wss",
      "server_name": "localhost",
      "server_port": 8000,
      "forwarded": {
        "secret": "mySecret",
        "proto": "wss"
      }
    }
    ```

---

##### Example 10

Unexpected termination should not lose existing acceptable values

```sh
curl localhost:8000/fwd \
	-H 'Forwarded: b0rked;secret=mySecret;proto=wss' | jq
```

.. column::

    ```python
    # Sanic application config
    app.config.PROXIES_COUNT = 1
    app.config.REAL_IP_HEADER = "x-real-ip"
    app.config.FORWARDED_SECRET = "mySecret"
    ```

.. column::

    ```bash
    # curl response
    {
      "remote_addr": "",
      "scheme": "wss",
      "server_name": "localhost",
      "server_port": 8000,
      "forwarded": {
        "secret": "mySecret",
        "proto": "wss"
      }
    }
    ```

---

##### Example 11

Field normalization

```sh
curl localhost:8000/fwd \
	-H 'Forwarded: PROTO=WSS;BY="CAFE::8000";FOR=unknown;PORT=X;HOST="A:2";PATH="/With%20Spaces%22Quoted%22/sanicApp?key=val";SECRET=mySecret' | jq
```

.. column::

    ```python
    # Sanic application config
    app.config.PROXIES_COUNT = 1
    app.config.REAL_IP_HEADER = "x-real-ip"
    app.config.FORWARDED_SECRET = "mySecret"
    ```

.. column::

    ```bash
    # curl response
    {
      "remote_addr": "",
      "scheme": "wss",
      "server_name": "a",
      "server_port": 2,
      "forwarded": {
        "proto": "wss",
        "by": "[cafe::8000]",
        "host": "a:2",
        "path": "/With Spaces\"Quoted\"/sanicApp?key=val",
        "secret": "mySecret"
      }
    }
    ```

---

##### Example 12

Using "by" field as secret

```sh
curl localhost:8000/fwd \
	-H 'Forwarded: for=1.2.3.4; by=_proxySecret' | jq
```

.. column::

    ```python
    # Sanic application config
    app.config.PROXIES_COUNT = 1
    app.config.REAL_IP_HEADER = "x-real-ip"
    app.config.FORWARDED_SECRET = "_proxySecret"
    ```

.. column::

    ```bash
    # curl response
    {
      "remote_addr": "1.2.3.4",
      "scheme": "http",
      "server_name": "localhost",
      "server_port": 8000,
      "forwarded": {
        "for": "1.2.3.4",
        "by": "_proxySecret"
      }
    }

    ```

---

### Guide Content En Guide Advanced Signals (`guide/content/en/guide/advanced/signals.md`)

# Signals

Signals provide a way for one part of your application to tell another part that something happened.

```python
@app.signal("user.registration.created")
async def send_registration_email(**context):
    await send_email(context["email"], template="registration")

@app.post("/register")
async def handle_registration(request):
    await do_registration(request)
    await request.app.dispatch(
        "user.registration.created",
        context={"email": request.json.email}
    })
```

## Adding a signal

.. column::

    The API for adding a signal is very similar to adding a route.

.. column::

    ```python
    async def my_signal_handler():
        print("something happened")

    app.add_signal(my_signal_handler, "something.happened.ohmy")
    ```


.. column::

    But, perhaps a slightly more convenient method is to use the built-in decorators.

.. column::

    ```python
    @app.signal("something.happened.ohmy")
    async def my_signal_handler():
        print("something happened")
    ```


.. column::

    If the signal requires conditions, make sure to add them while adding the handler.

.. column::

    ```python
    async def my_signal_handler1():
        print("something happened")

    app.add_signal(
        my_signal_handler,
        "something.happened.ohmy1",
        conditions={"some_condition": "value"}
    )

    @app.signal("something.happened.ohmy2", conditions={"some_condition": "value"})
    async def my_signal_handler2():
        print("something happened")
    ```


.. column::

    Signals can also be declared on blueprints

.. column::

    ```python
    bp = Blueprint("foo")

    @bp.signal("something.happened.ohmy")
    async def my_signal_handler():
        print("something happened")
    ```

## Built-in signals

In addition to creating a new signal, there are a number of built-in signals that are dispatched from Sanic itself. These signals exist to provide developers with more opportunities to add functionality into the request and server lifecycles.

*Added in v21.9*

.. column::

    You can attach them just like any other signal to an application or blueprint instance.

.. column::

    ```python
    @app.signal("http.lifecycle.complete")
    async def my_signal_handler(conn_info):
        print("Connection has been closed")
    ```

These signals are the signals that are available, along with the arguments that the handlers take, and the conditions that attach (if any).

| Event name                 | Arguments                       | Conditions                                                |
| -------------------------- | ------------------------------- | --------------------------------------------------------- |
| `http.routing.before`      | request                         |                                                           |
| `http.routing.after`       | request, route, kwargs, handler |                                                           |
| `http.handler.before`      | request                         |                                                           |
| `http.handler.after`       | request                         |                                                           |
| `http.lifecycle.begin`     | conn_info                       |                                                           |
| `http.lifecycle.read_head` | head                            |                                                           |
| `http.lifecycle.request`   | request                         |                                                           |
| `http.lifecycle.handle`    | request                         |                                                           |
| `http.lifecycle.read_body` | body                            |                                                           |
| `http.lifecycle.exception` | request, exception              |                                                           |
| `http.lifecycle.response`  | request, response               |                                                           |
| `http.lifecycle.send`      | data                            |                                                           |
| `http.lifecycle.complete`  | conn_info                       |                                                           |
| `http.middleware.before`   | request, response               | `{"attach_to": "request"}` or `{"attach_to": "response"}` |
| `http.middleware.after`    | request, response               | `{"attach_to": "request"}` or `{"attach_to": "response"}` |
| `server.exception.report`  | app, exception                  |                                                           |
| `server.init.before`       | app, loop                       |                                                           |
| `server.init.after`        | app, loop                       |                                                           |
| `server.shutdown.before`   | app, loop                       |                                                           |
| `server.shutdown.after`    | app, loop                       |                                                           |

Version 22.9 added `http.handler.before` and `http.handler.after`.

Version 23.6 added `server.exception.report`.

.. column::

    To make using the built-in signals easier, there is an `Enum` object that contains all of the allowed built-ins. With a modern IDE this will help so that you do not need to remember the full list of event names as strings.

    *Added in v21.12*

.. column::

    ```python
    from sanic.signals import Event

    @app.signal(Event.HTTP_LIFECYCLE_COMPLETE)
    async def my_signal_handler(conn_info):
        print("Connection has been closed")
    ```

## Events

.. column::

    Signals are based off of an _event_. An event, is simply a string in the following pattern:

.. column::

    ```
    namespace.reference.action
    ```



.. tip:: Events must have three parts. If you do not know what to use, try these patterns:

    - `my_app.something.happened`
    - `sanic.notice.hello`


### Event parameters

.. column::

    An event can be "dynamic" and declared using the same syntax as [path parameters](../basics/routing.md#path-parameters). This allows matching based upon arbitrary values.

.. column::

    ```python
    @app.signal("foo.bar.<thing>")
    async def signal_handler(thing):
        print(f"[signal_handler] {thing=}")

    @app.get("/")
    async def trigger(request):
        await app.dispatch("foo.bar.baz")
        return response.text("Done.")
    ```

Checkout [path parameters](../basics/routing.md#path-parameters) for more information on allowed type definitions.


.. info:: Only the third part of an event (the action) may be dynamic:

    - `foo.bar.<thing>` 🆗
    - `foo.<bar>.baz` ❌


### Waiting

.. column::

    In addition to executing a signal handler, your application can wait for an event to be triggered.

.. column::

    ```python
    await app.event("foo.bar.baz")
    ```


.. column::

    **IMPORTANT**: waiting is a blocking function. Therefore, you likely will want this to run in a [background task](../basics/tasks.md).

.. column::

    ```python
    async def wait_for_event(app):
        while True:
            print("> waiting")
            await app.event("foo.bar.baz")
            print("> event found\n")

    @app.after_server_start
    async def after_server_start(app, loop):
        app.add_task(wait_for_event(app))
    ```


.. column::

    If your event was defined with a dynamic path, you can use `*` to catch any action.

.. column::

    ```python
    @app.signal("foo.bar.<thing>")

    ...

    await app.event("foo.bar.*")
    ```

## Dispatching

*In the future, Sanic will dispatch some events automatically to assist developers to hook into life cycle events.*

.. column::

    Dispatching an event will do two things:

    1. execute any signal handlers defined on the event, and
    2. resolve anything that is "waiting" for the event to complete.

.. column::

    ```python
    @app.signal("foo.bar.<thing>")
    async def foo_bar(thing):
        print(f"{thing=}")

    await app.dispatch("foo.bar.baz")
    ```
    ```
    thing=baz
    ```

### Context

.. column::

    Sometimes you may find the need to pass extra information into the signal handler. In our first example above, we wanted our email registration process to have the email address for the user.

.. column::

    ```python
    @app.signal("user.registration.created")
    async def send_registration_email(**context):
        print(context)

    await app.dispatch(
        "user.registration.created",
        context={"hello": "world"}
    )
    ```
    ```
    {'hello': 'world'}
    ```



.. tip:: FYI

    Signals are dispatched in a background task.


### Blueprints

Dispatching blueprint signals works similar in concept to [middleware](../basics/middleware.md). Anything that is done from the app level, will trickle down to the blueprints. However, dispatching on a blueprint, will only execute the signals that are defined on that blueprint.

.. column::

    Perhaps an example is easier to explain:

.. column::

    ```python
    bp = Blueprint("bp")

    app_counter = 0
    bp_counter = 0

    @app.signal("foo.bar.baz")
    def app_signal():
        nonlocal app_counter
        app_counter += 1

    @bp.signal("foo.bar.baz")
    def bp_signal():
        nonlocal bp_counter
        bp_counter += 1
    ```


.. column::

    Running `app.dispatch("foo.bar.baz")` will execute both signals.

.. column::

    ```python
    await app.dispatch("foo.bar.baz")
    assert app_counter == 1
    assert bp_counter == 1
    ```


.. column::

    Running `bp.dispatch("foo.bar.baz")` will execute only the blueprint signal.

.. column::

    ```python
    await bp.dispatch("foo.bar.baz")
    assert app_counter == 1
    assert bp_counter == 2
    ```

---

### Guide Content En Guide Advanced Streaming (`guide/content/en/guide/advanced/streaming.md`)

# Streaming

## Request streaming

Sanic allows you to stream data sent by the client to begin processing data as the bytes arrive.

.. column::

    When enabled on an endpoint, you can stream the request body using `await request.stream.read()`.

    That method will return `None` when the body is completed.

.. column::

    ```python
    from sanic.views import stream

    class SimpleView(HTTPMethodView):
        @stream
        async def post(self, request):
            result = ""
            while True:
                body = await request.stream.read()
                if body is None:
                    break
                result += body.decode("utf-8")
            return text(result)
    ```


.. column::

    It also can be enabled with a keyword argument in the decorator...

.. column::

    ```python
    @app.post("/stream", stream=True)
    async def handler(request):
            ...
            body = await request.stream.read()
            ...
    ```


.. column::

    ... or the `add_route()` method.

.. column::

    ```python
    bp.add_route(
        bp_handler,
        "/bp_stream",
        methods=["POST"],
        stream=True,
    )
    ```



.. tip:: FYI

    Only post, put and patch decorators have stream argument.


## Response streaming

.. column::

    Sanic allows you to stream content to the client.

.. column::

    ```python
    @app.route("/")
    async def test(request):
        response = await request.respond(content_type="text/csv")
        await response.send("foo,")
        await response.send("bar")

        # Optionally, you can explicitly end the stream by calling:
        await response.eof()
    ```

This is useful in situations where you want to stream content to the client that originates in an external service, like a database. For example, you can stream database records to the client with the asynchronous cursor that `asyncpg` provides.

```python
@app.route("/")
async def index(request):
    response = await request.respond()
    conn = await asyncpg.connect(database='test')
    async with conn.transaction():
        async for record in conn.cursor('SELECT generate_series(0, 10)'):
            await response.send(record[0])
```


You can explicitly end a stream by calling `await response.eof()`. It a convenience method to replace `await response.send("", True)`. It should be called **one time** *after* your handler has determined that it has nothing left to send back to the client. While it is *optional* to use with Sanic server, if you are running Sanic in ASGI mode, then you **must** explicitly terminate the stream.

*Calling `eof` became optional in v21.6*

## File streaming

.. column::

    Sanic provides `sanic.response.file_stream` function that is useful when you want to send a large file. It returns a `StreamingHTTPResponse` object and will use chunked transfer encoding by default; for this reason Sanic doesn’t add `Content-Length` HTTP header in the response.

    A typical use case might be streaming an video file.

.. column::

    ```python
    @app.route("/mp4")
    async def handler_file_stream(request):
        return await response.file_stream(
            "/path/to/sample.mp4",
            chunk_size=1024,
            mime_type="application/metalink4+xml",
            headers={
                "Content-Disposition": 'Attachment; filename="nicer_name.meta4"',
                "Content-Type": "application/metalink4+xml",
            },
        )
    ```


.. column::

    If you want to use the `Content-Length` header, you can disable chunked transfer encoding and add it manually simply by adding the `Content-Length` header.

.. column::

    ```python
    from aiofiles import os as async_os
    from sanic.response import file_stream

    @app.route("/")
    async def index(request):
        file_path = "/srv/www/whatever.png"

        file_stat = await async_os.stat(file_path)
        headers = {"Content-Length": str(file_stat.st_size)}

        return await file_stream(
            file_path,
            headers=headers,
        )
    ```

---

### Guide Content En Guide Advanced Versioning (`guide/content/en/guide/advanced/versioning.md`)

# Versioning

It is standard practice in API building to add versions to your endpoints. This allows you to easily differentiate incompatible endpoints when you try and change your API down the road in a breaking manner.

Adding a version will add a `/v{version}` url prefix to your endpoints.

The version can be a `int`, `float`, or `str`. Acceptable values:

- `1`, `2`, `3`
- `1.1`, `2.25`, `3.0`
- `"1"`, `"v1"`, `"v1.1"`

## Per route

.. column::

    You can pass a version number to the routes directly.

.. column::

    ```python
    # /v1/text
    @app.route("/text", version=1)
    def handle_request(request):
        return response.text("Hello world! Version 1")

    # /v2/text
    @app.route("/text", version=2)
    def handle_request(request):
        return response.text("Hello world! Version 2")
    ```

## Per Blueprint

.. column::

    You can also pass a version number to the blueprint, which will apply to all routes in that blueprint.

.. column::

    ```python
    bp = Blueprint("test", url_prefix="/foo", version=1)

    # /v1/foo/html
    @bp.route("/html")
    def handle_request(request):
        return response.html("<p>Hello world!</p>")
    ```

## Per Blueprint Group

.. column::

    In order to simplify the management of the versioned blueprints, you can provide a version number in the blueprint
    group. The same will be inherited to all the blueprint grouped under it if the blueprints don't already override the
    same information with a value specified while creating a blueprint instance.

    When using blueprint groups for managing the versions, the following order is followed to apply the Version prefix to
    the routes being registered.

    1. Route Level configuration
    2. Blueprint level configuration
    3. Blueprint Group level configuration

    If we find a more pointed versioning specification, we will pick that over the more generic versioning specification
    provided under the Blueprint or Blueprint Group

.. column::

    ```python
    from sanic.blueprints import Blueprint
    from sanic.response import json

    bp1 = Blueprint(
        name="blueprint-1",
        url_prefix="/bp1",
        version=1.25,
    )
    bp2 = Blueprint(
        name="blueprint-2",
        url_prefix="/bp2",
    )

    group = Blueprint.group(
        [bp1, bp2],
        url_prefix="/bp-group",
        version="v2",
    )

    # GET /v1.25/bp-group/bp1/endpoint-1
    @bp1.get("/endpoint-1")
    async def handle_endpoint_1_bp1(request):
        return json({"Source": "blueprint-1/endpoint-1"})

    # GET /v2/bp-group/bp2/endpoint-2
    @bp2.get("/endpoint-1")
    async def handle_endpoint_1_bp2(request):
        return json({"Source": "blueprint-2/endpoint-1"})

    # GET /v1/bp-group/bp2/endpoint-2
    @bp2.get("/endpoint-2", version=1)
    async def handle_endpoint_2_bp2(request):
        return json({"Source": "blueprint-2/endpoint-2"})
    ```

## Version prefix

As seen above, the `version` that is applied to a route is **always** the first segment in the generated URI path. Therefore, to make it possible to add path segments before the version, every place that a `version` argument is passed, you can also pass `version_prefix`. 

The `version_prefix` argument can be defined in:

- `app.route` and `bp.route` decorators (and all the convenience decorators also)
- `Blueprint` instantiation
- `Blueprint.group` constructor
- `BlueprintGroup` instantiation
- `app.blueprint` registration

If there are definitions in multiple places, a more specific definition overrides a more general. This list provides that hierarchy.

The default value of `version_prefix` is `/v`.

.. column::

    An often requested feature is to be able to mount versioned routes on `/api`. This can easily be accomplished with `version_prefix`.

.. column::

    ```python
    # /v1/my/path
    app.route("/my/path", version=1, version_prefix="/api/v")
    ```


.. column::

    Perhaps a more compelling usage is to load all `/api` routes into a single `BlueprintGroup`.

.. column::

    ```python
    # /v1/my/path
    app = Sanic(__name__)
    v2ip = Blueprint("v2ip", url_prefix="/ip", version=2)
    api = Blueprint.group(v2ip, version_prefix="/api/version")

    # /api/version2/ip
    @v2ip.get("/")
    async def handler(request):
        return text(request.ip)

    app.blueprint(api)
    ```

We can therefore learn that a route's URI is:

```
version_prefix + version + url_prefix + URI definition
```


.. tip:: 
    
    Just like with `url_prefix`, it is possible to define path parameters inside a `version_prefix`. It is perfectly legitimate to do this. Just remember that every route will have that parameter injected into the handler.

    ```python
    version_prefix="/<foo:str>/v"
    ```


*Added in v21.6*

---

### Guide Content En Guide Advanced Websockets (`guide/content/en/guide/advanced/websockets.md`)

# Websockets

Sanic provides an easy to use abstraction on top of [websockets](https://websockets.readthedocs.io/en/stable/).

## Routing

.. column::

    Websocket handlers can be hooked up to the router similar to regular handlers.

.. column::

    ```python
    from sanic import Request, Websocket

    async def feed(request: Request, ws: Websocket):
        pass

    app.add_websocket_route(feed, "/feed")
    ```
    ```python
    from sanic import Request, Websocket

    @app.websocket("/feed")
    async def feed(request: Request, ws: Websocket):
        pass
    ```

## Handler


.. column::

    Typically, a websocket handler will want to hold open a loop.

    It can then use the `send()` and `recv()` methods on the second object injected into the handler.

    This example is a simple endpoint that echos back to the client messages that it receives.

.. column::

    ```python
    from sanic import Request, Websocket

    @app.websocket("/feed")
    async def feed(request: Request, ws: Websocket):
        while True:
            data = "hello!"
            print("Sending: " + data)
            await ws.send(data)
            data = await ws.recv()
            print("Received: " + data)
    ```


.. column::

    You can simplify your loop by just iterating over the `Websocket` object in a for loop.

    *Added in v22.9*

.. column::

    ```python
    from sanic import Request, Websocket

    @app.websocket("/feed")
    async def feed(request: Request, ws: Websocket):
        async for msg in ws:
            await ws.send(msg)
    ```


## Configuration

See [configuration section](../running/configuration.md) for more details, however the defaults are shown below.

```python
app.config.WEBSOCKET_MAX_SIZE = 2 ** 20
app.config.WEBSOCKET_PING_INTERVAL = 20
app.config.WEBSOCKET_PING_TIMEOUT = 20
```

---

### Guide Content En Guide Basics App (`guide/content/en/guide/basics/app.md`)

---
title: Sanic Application
---

# Sanic Application

See API docs: [sanic.app](/api/sanic.app)

## Instance

.. column::

    The most basic building block is the :class:`sanic.app.Sanic` instance. It is not required, but the custom is to instantiate this in a file called `server.py`.

.. column::

    ```python
    # /path/to/server.py

    from sanic import Sanic

    app = Sanic("MyHelloWorldApp")
    ```

## Application context

Most applications will have the need to share/reuse data or objects across different parts of the code base. Sanic helps be providing the `ctx` object on application instances. It is a free space for the developer to attach any objects or data that should existe throughout the lifetime of the application.


.. column::

    The most common pattern is to attach a database instance to the application.

.. column::

    ```python
    app = Sanic("MyApp")
    app.ctx.db = Database()
    ```


.. column::

    While the previous example will work and is illustrative, it is typically considered best practice to attach objects in one of the two application startup [listeners](./listeners).

.. column::

    ```python
    app = Sanic("MyApp")

    @app.before_server_start
    async def attach_db(app, loop):
        app.ctx.db = Database()
    ```


## App Registry

.. column::

    When you instantiate a Sanic instance, that can be retrieved at a later time from the Sanic app registry. This can be useful, for example, if you need to access your Sanic instance from a location where it is not otherwise accessible.

.. column::

    ```python
    # ./path/to/server.py
    from sanic import Sanic

    app = Sanic("my_awesome_server")

    # ./path/to/somewhere_else.py
    from sanic import Sanic

    app = Sanic.get_app("my_awesome_server")
    ```


.. column::

    If you call `Sanic.get_app("non-existing")` on an app that does not exist, it will raise :class:`sanic.exceptions.SanicException` by default. You can, instead, force the method to return a new instance of Sanic with that name.

.. column::

    ```python
    app = Sanic.get_app(
        "non-existing",
        force_create=True,
    )
    ```


.. column::

    If there is **only one** Sanic instance registered, then calling `Sanic.get_app()` with no arguments will return that instance

.. column::

    ```python
    Sanic("My only app")

    app = Sanic.get_app()
    ```

## Configuration

.. column::

    Sanic holds the configuration in the `config` attribute of the `Sanic` instance. Configuration can be modified **either** using dot-notation **OR** like a dictionary.

.. column::

    ```python
    app = Sanic('myapp')

    app.config.DB_NAME = 'appdb'
    app.config['DB_USER'] = 'appuser'

    db_settings = {
        'DB_HOST': 'localhost',
        'DB_NAME': 'appdb',
        'DB_USER': 'appuser'
    }
    app.config.update(db_settings)
    ```



.. note:: Heads up

    Config keys _should_ be uppercase. But, this is mainly by convention, and lowercase will work most of the time.
    ```python
    app.config.GOOD = "yay!"
    app.config.bad = "boo"
    ```


There is much [more detail about configuration](../running/configuration.md) later on.

## Factory pattern

Many of the examples in these docs will show the instantiation of the :class:`sanic.app.Sanic` instance in a file called `server.py` in the "global scope" (i.e. not inside a function). This is a common pattern for very simple "hello world" style applications, but it is often beneficial to use a factory pattern instead.

A "factory" is just a function that returns an instance of the object you want to use. This allows you to abstract the instantiation of the object, but also may make it easier to isolate the application instance.

.. column::

    A super simple factory pattern could look like this:
    
.. column::

    ```python
    # ./path/to/server.py
    from sanic import Sanic
    from .path.to.config import MyConfig
    from .path.to.some.blueprint import bp
    
    
    def create_app(config=MyConfig) -> Sanic:
        app = Sanic("MyApp", config=config)
        app.blueprint(bp)
        return app
    ```

.. column::

    When we get to running Sanic later, you will learn that the Sanic CLI can detect this pattern and use it to run your application.
    
.. column::

    ```sh
    sanic path.to.server:create_app
    ```

## Customization

The Sanic application instance can be customized for your application needs in a variety of ways at instantiation.

For complete details, see the [API docs](/api/sanic.app).

### Custom configuration

.. column::

    This simplest form of custom configuration would be to pass your own object directly into that Sanic application instance

    If you create a custom configuration object, it is *highly* recommended that you subclass the :class:`sanic.config.Config` option to inherit its behavior. You could use this option for adding properties, or your own set of custom logic.

    *Added in v21.6*

.. column::

    ```python
    from sanic.config import Config

    class MyConfig(Config):
        FOO = "bar"

    app = Sanic(..., config=MyConfig())
    ```


.. column::

    A useful example of this feature would be if you wanted to use a config file in a form that differs from what is [supported](../running/configuration.md#using-sanicupdateconfig).

.. column::

    ```python
    from sanic import Sanic, text
    from sanic.config import Config

    class TomlConfig(Config):
        def __init__(self, *args, path: str, **kwargs):
            super().__init__(*args, **kwargs)

            with open(path, "r") as f:
                self.apply(toml.load(f))

        def apply(self, config):
            self.update(self._to_uppercase(config))

        def _to_uppercase(self, obj: Dict[str, Any]) -> Dict[str, Any]:
            retval: Dict[str, Any] = {}
            for key, value in obj.items():
                upper_key = key.upper()
                if isinstance(value, list):
                    retval[upper_key] = [
                        self._to_uppercase(item) for item in value
                    ]
                elif isinstance(value, dict):
                    retval[upper_key] = self._to_uppercase(value)
                else:
                    retval[upper_key] = value
            return retval

    toml_config = TomlConfig(path="/path/to/config.toml")
    app = Sanic(toml_config.APP_NAME, config=toml_config)
    ```

### Custom context

.. column::

    By default, the application context is a [`SimpleNamespace()`](https://docs.python.org/3/library/types.html#types.SimpleNamespace) that allows you to set any properties you want on it. However, you also have the option of passing any object whatsoever instead.

    *Added in v21.6*

.. column::

    ```python
    app = Sanic(..., ctx=1)
    ```

    ```python
    app = Sanic(..., ctx={})
    ```

    ```python
    class MyContext:
        ...

    app = Sanic(..., ctx=MyContext())
    ```

### Custom requests

.. column::

    It is sometimes helpful to have your own `Request` class, and tell Sanic to use that instead of the default. One example is if you wanted to modify the default `request.id` generator.

    

    .. note:: Important

        It is important to remember that you are passing the *class* not an instance of the class.


.. column::

    ```python
    import time

    from sanic import Request, Sanic, text

    class NanoSecondRequest(Request):
        @classmethod
        def generate_id(*_):
            return time.time_ns()

    app = Sanic(..., request_class=NanoSecondRequest)

    @app.get("/")
    async def handler(request):
        return text(str(request.id))
    ```

### Custom error handler

.. column::

    See [exception handling](../best-practices/exceptions.md#custom-error-handling) for more

.. column::

    ```python
    from sanic.handlers import ErrorHandler

    class CustomErrorHandler(ErrorHandler):
        def default(self, request, exception):
            ''' handles errors that have no error handlers assigned '''
            # You custom error handling logic...
            return super().default(request, exception)

    app = Sanic(..., error_handler=CustomErrorHandler())
    ```

### Custom dumps function

.. column::

    It may sometimes be necessary or desirable to provide a custom function that serializes an object to JSON data.

.. column::

    ```python
    import ujson

    dumps = partial(ujson.dumps, escape_forward_slashes=False)
    app = Sanic(__name__, dumps=dumps)
    ```


.. column::

    Or, perhaps use another library or create your own.

.. column::

    ```python
    from orjson import dumps

    app = Sanic("MyApp", dumps=dumps)
    ```

### Custom loads function

.. column::

    Similar to `dumps`, you can also provide a custom function for deserializing data.

    *Added in v22.9*

.. column::

    ```python
    from orjson import loads

    app = Sanic("MyApp", loads=loads)
    ```



### Custom typed application

Beginning in v23.6, the correct type annotation of a default Sanic application instance is:

```python
sanic.app.Sanic[sanic.config.Config, types.SimpleNamespace]
```

It refers to two generic types:

1. The first is the type of the configuration object. It defaults to :class:`sanic.config.Config`, but can be any subclass of that.
2. The second is the type of the application context. It defaults to [`SimpleNamespace()`](https://docs.python.org/3/library/types.html#types.SimpleNamespace), but can be **any object** as show above.

Let's look at some examples of how the type will change.

.. column::

    Consider this example where we pass a custom subclass of :class:`sanic.config.Config` and a custom context object.

.. column::

    ```python
    from sanic import Sanic
    from sanic.config import Config

    class CustomConfig(Config):
        pass

    app = Sanic("test", config=CustomConfig())
    reveal_type(app) # N: Revealed type is "sanic.app.Sanic[main.CustomConfig, types.SimpleNamespace]"
    ```
    ```
    sanic.app.Sanic[main.CustomConfig, types.SimpleNamespace]
    ```


.. column::

    Similarly, when passing a custom context object, the type will change to reflect that.

.. column::

    ```python
    from sanic import Sanic

    class Foo:
        pass

    app = Sanic("test", ctx=Foo())
    reveal_type(app)  # N: Revealed type is "sanic.app.Sanic[sanic.config.Config, main.Foo]"
    ```
    ```
    sanic.app.Sanic[sanic.config.Config, main.Foo]
    ```


.. column::

    Of course, you can set both the config and context to custom types.

.. column::

    ```python
    from sanic import Sanic
    from sanic.config import Config

    class CustomConfig(Config):
        pass

    class Foo:
        pass

    app = Sanic("test", config=CustomConfig(), ctx=Foo())
    reveal_type(app)  # N: Revealed type is "sanic.app.Sanic[main.CustomConfig, main.Foo]"
    ```
    ```
    sanic.app.Sanic[main.CustomConfig, main.Foo]
    ```

This pattern is particularly useful if you create a custom type alias for your application instance so that you can use it to annotate listeners and handlers.

```python
# ./path/to/types.py
from sanic.app import Sanic
from sanic.config import Config
from myapp.context import MyContext
from typing import TypeAlias

MyApp = TypeAlias("MyApp", Sanic[Config, MyContext])
```

```python
# ./path/to/listeners.py
from myapp.types import MyApp

def add_listeners(app: MyApp):
    @app.before_server_start
    async def before_server_start(app: MyApp):
        # do something with your fully typed app instance
        await app.ctx.db.connect()
```

```python
# ./path/to/server.py
from myapp.types import MyApp
from myapp.context import MyContext
from myapp.config import MyConfig
from myapp.listeners import add_listeners

app = Sanic("myapp", config=MyConfig(), ctx=MyContext())
add_listeners(app)
```

*Added in v23.6*

### Custom typed request

Sanic also allows you to customize the type of the request object. This is useful if you want to add custom properties to the request object, or be able to access your custom properties of a typed application instance.

The correct, default type of a Sanic request instance is:

```python
sanic.request.Request[
    sanic.app.Sanic[sanic.config.Config, types.SimpleNamespace],
    types.SimpleNamespace
]
```

It refers to two generic types:

1. The first is the type of the application instance. It defaults to `sanic.app.Sanic[sanic.config.Config, types.SimpleNamespace]`, but can be any subclass of that.
2. The second is the type of the request context. It defaults to `types.SimpleNamespace`, but can be **any object** as show above in [custom requests](#custom-requests).

Let's look at some examples of how the type will change.

.. column::

    Expanding upon the full example above where there is a type alias for a customized application instance, we can also create a custom request type so that we can access those same type annotations.

    Of course, you do not need type aliases for this to work. We are only showing them here to cut down on the amount of code shown.

.. column::

    ```python
    from sanic import Request
    from myapp.types import MyApp
    from types import SimpleNamespace

    def add_routes(app: MyApp):
        @app.get("/")
        async def handler(request: Request[MyApp, SimpleNamespace]):
            # do something with your fully typed app instance
            results = await request.app.ctx.db.query("SELECT * FROM foo")
    ```


.. column::

    Perhaps you have a custom request object that generates a custom context object. You can type annotate it to properly access those properties with your IDE as shown here.

.. column::

    ```python
    from sanic import Request, Sanic
    from sanic.config import Config

    class CustomConfig(Config):
        pass

    class Foo:
        pass

    class RequestContext:
        foo: Foo

    class CustomRequest(Request[Sanic[CustomConfig, Foo], RequestContext]):
        @staticmethod
        def make_context() -> RequestContext:
            ctx = RequestContext()
            ctx.foo = Foo()
            return ctx

    app = Sanic(
        "test", config=CustomConfig(), ctx=Foo(), request_class=CustomRequest
    )

    @app.get("/")
    async def handler(request: CustomRequest):
        # Full access to typed:
        # - custom application configuration object
        # - custom application context object
        # - custom request context object
        pass
    ```

See more information in the [custom request context](./request.md#custom-request-context) section.

*Added in v23.6*

---

### Guide Content En Guide Basics Cookies (`guide/content/en/guide/basics/cookies.md`)

# Cookies

## Reading

.. column::

    Cookies can be accessed via the `Request` object’s `cookies` dictionary.

.. column::

    ```python
    @app.route("/cookie")
    async def test(request):
        test_cookie = request.cookies.get("test")
        return text(f"Test cookie: {test_cookie}")
    ```



.. tip:: FYI

    💡 The `request.cookies` object is one of a few types that is a dictionary with each value being a `list`. This is because HTTP allows a single key to be reused to send multiple values.

    Most of the time you will want to use the `.get()` method to access the first element and not a `list`. If you do want a `list` of all items, you can use `.getlist()`.

    *Added in v23.3*



## Writing

.. column::

    When returning a response, cookies can be set on the `Response` object: `response.cookies`. This object is an instance of `CookieJar` which is a special sort of dictionary that automatically will write the response headers for you.

.. column::

    ```python
    @app.route("/cookie")
    async def test(request):
        response = text("There's a cookie up in this response")
        response.add_cookie(
            "test",
            "It worked!",
            domain=".yummy-yummy-cookie.com",
            httponly=True
        )
        return response
    ```

Response cookies can be set like dictionary values and have the following parameters available:

- `path: str` - The subset of URLs to which this cookie applies. Defaults to `/`.
- `domain: str` - Specifies the domain for which the cookie is valid. An explicitly specified domain must always start with a dot.
- `max_age: int` - Number of seconds the cookie should live for.
- `expires: datetime` - The time for the cookie to expire on the client’s browser. Usually it is better to use max-age instead.
- `secure: bool` - Specifies whether the cookie will only be sent via HTTPS. Defaults to `True`.
- `httponly: bool` - Specifies whether the cookie cannot be read by JavaScript.
- `samesite: str` - Available values: Lax, Strict, and None. Defaults to `Lax`.
- `comment: str` - A comment (metadata).
- `host_prefix: bool` - Whether to add the `__Host-` prefix to the cookie.
- `secure_prefix: bool` - Whether to add the `__Secure-` prefix to the cookie.
- `partitioned: bool` - Whether to mark the cookie as partitioned.

To better understand the implications and usage of these values, it might be helpful to read the [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/HTTP/Cookies) on [setting cookies](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie).


.. tip:: FYI

    By default, Sanic will set the `secure` flag to `True` to ensure that cookies are only sent over HTTPS as a sensible default. This should not be impactful for local development since secure cookies over HTTP should still be sent to `localhost`. For more information, you should read the [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/HTTP/Cookies#restrict_access_to_cookies) on [secure cookies](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie#Secure).


## Deleting

.. column::

    Cookies can be removed semantically or explicitly.

.. column::

    ```python
    @app.route("/cookie")
    async def test(request):
        response = text("Time to eat some cookies muahaha")

        # This cookie will be set to expire in 0 seconds
        response.delete_cookie("eat_me")

        # This cookie will self destruct in 5 seconds
        response.add_cookie("fast_bake", "Be quick!", max_age=5)

        return response
    ```

    *Don't forget to add `path` or `domain` if needed!*

## Eating

.. column::

    Sanic likes cookies
    
.. column::

    .. attrs::
        :class: is-size-1 has-text-centered
        
        🍪

---

### Guide Content En Guide Basics Handlers (`guide/content/en/guide/basics/handlers.md`)

# Handlers

The next important building block are your _handlers_. These are also sometimes called "views".

In Sanic, a handler is any callable that takes at least a :class:`sanic.request.Request` instance as an argument, and returns either an :class:`sanic.response.HTTPResponse` instance, or a coroutine that does the same.

.. column::

    Huh? 😕

    It is a **function**; either synchronous or asynchronous.

    The job of the handler is to respond to an endpoint and do something. This is where the majority of your business logic will go.

.. column::

    ```python
    def i_am_a_handler(request):
        return HTTPResponse()

    async def i_am_ALSO_a_handler(request):
        return HTTPResponse()
    ```

Two more important items to note:

1. You almost *never* will want to use :class:`sanic.response.HTTPresponse` directly. It is much simpler to use one of the [convenience methods](./response.md#methods).

    - `from sanic import json`
    - `from sanic import html`
    - `from sanic import redirect`
    - *etc*
    
1. As we will see in [the streaming section](../advanced/streaming.md#response-streaming), you do not always need to return an object. If you use this lower-level API, you can control the flow of the response from within the handler, and a return object is not used.

.. tip:: Heads up

    If you want to learn more about encapsulating your logic, checkout [class based views](../advanced/class-based-views.md). For now, we will continue forward with just function-based views.


### A simple function-based handler

The most common way to create a route handler is to decorate the function. It creates a visually simple identification of a route definition. We'll learn more about [routing soon](./routing.md).

.. column::

    Let's look at a practical example.

    - We use a convenience decorator on our app instance: `@app.get()`
    - And a handy convenience method for generating out response object: `text()`

    Mission accomplished 💪

.. column::

    ```python
    from sanic import text

    @app.get("/foo")
    async def foo_handler(request):
        return text("I said foo!")
    ```

---

## A word about _async_...

.. column::

    It is entirely possible to write handlers that are synchronous.

    In this example, we are using the _blocking_ `time.sleep()` to simulate 100ms of processing time. Perhaps this represents fetching data from a DB, or a 3rd-party website.

    Using four (4) worker processes and a common benchmarking tool:

    - **956** requests in 30.10s
    - Or, about **31.76** requests/second

.. column::

    ```python
    @app.get("/sync")
    def sync_handler(request):
        time.sleep(0.1)
        return text("Done.")
    ```


.. column::

    Just by changing to the asynchronous alternative `asyncio.sleep()`, we see an incredible change in performance. 🚀

    Using the same four (4) worker processes:

    - **115,590** requests in 30.08s
    - Or, about **3,843.17** requests/second

    .. attrs::
        :class: is-size-2
    
        🤯

.. column::

    ```python
    @app.get("/async")
    async def async_handler(request):
        await asyncio.sleep(0.1)
        return text("Done.")
    ```


Okay... this is a ridiculously overdramatic result. And any benchmark you see is inherently very biased. This example is meant to over-the-top show the benefit of `async/await` in the web world. Results will certainly vary. Tools like Sanic and other async Python libraries are not magic bullets that make things faster. They make them _more efficient_.

In our example, the asynchronous version is so much better because while one request is sleeping, it is able to start another one, and another one, and another one, and another one...

But, this is the point! Sanic is fast because it takes the available resources and squeezes performance out of them. It can handle many requests concurrently, which means more requests per second.


.. tip:: A common mistake!

    Don't do this! You need to ping a website. What do you use? `pip install your-fav-request-library` 🙈

    Instead, try using a client that is `async/await` capable. Your server will thank you. Avoid using blocking tools, and favor those that play well in the asynchronous ecosystem. If you need recommendations, check out [Awesome Sanic](https://github.com/mekicha/awesome-sanic).

    Sanic uses [httpx](https://www.python-httpx.org/) inside of its testing package (sanic-testing) 😉.


---

## A fully annotated handler

For those that are using type annotations...

```python
from sanic.response import HTTPResponse, text
from sanic.request import Request

@app.get("/typed")
async def typed_handler(request: Request) -> HTTPResponse:
    return text("Done.")
```

## Naming your handlers

All handlers are named automatically. This is useful for debugging, and for generating URLs in templates. When not specified, the name that will be used is the name of the function.

.. column::

    For example, this handler will be named `foo_handler`.

.. column::

    ```python
    # Handler name will be "foo_handler"
    @app.get("/foo")
    async def foo_handler(request):
        return text("I said foo!")
    ```

.. column::

    However, you can override this by passing the `name` argument to the decorator.

.. column::

    ```python
    # Handler name will be "foo"
    @app.get("/foo", name="foo")
    async def foo_handler(request):
        return text("I said foo!")
    ```

.. column::

    In fact, as you will, there may be times when you **MUST** supply a name. For example, if you use two decorators on the same function, you will need to supply a name for at least one of them.
    
    If you do not, you will get an error and your app will not start. Names **must** be unique within your app.

.. column::

    ```python
    # Two handlers, same function,
    # different names:
    # - "foo_arg"
    # - "foo"
    @app.get("/foo/<arg>", name="foo_arg")
    @app.get("/foo")
    async def foo(request, arg=None):
        return text("I said foo!")
    ```

---

### Guide Content En Guide Basics Headers (`guide/content/en/guide/basics/headers.md`)

# Headers

Request and response headers are available in the `Request` and `HTTPResponse` objects, respectively. They make use of the [`multidict` package](https://multidict.readthedocs.io/en/stable/multidict.html#cimultidict) that allows a single key to have multiple values.


.. tip:: FYI

    Header keys are converted to *lowercase* when parsed. Capitalization is not considered for headers.


## Request

Sanic does attempt to do some normalization on request headers before presenting them to the developer, and also make some potentially meaningful extractions for common use cases.

.. column::

    #### Tokens

    Authorization tokens in the form `Token <token>` or `Bearer <token>` are extracted to the request object: `request.token`.

.. column::

    ```python
    @app.route("/")
    async def handler(request):
        return text(request.token)
    ```

    ```sh
    curl localhost:8000 \
        -H "Authorization: Token ABCDEF12345679"
    ABCDEF12345679
    ```

    ```sh
    curl localhost:8000 \
        -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c"
    eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
    ```

### Proxy headers

Sanic has special handling for proxy headers. See the [proxy headers](../advanced/proxy-headers.md) section for more details.

### Host header and dynamic URL construction

.. column::

    The *effective host* is available via `request.host`. This is not necessarily the same as the host header, as it prefers proxy-forwarded host and can be forced by the server name setting.

    Webapps should generally use this accessor so that they can function the same no matter how they are deployed. The actual host header, if needed, can be found via `request.headers`

    The effective host is also used in dynamic URL construction via `request.url_for`, which uses the request to determine the external address of a handler.

    .. tip:: Be wary of malicious clients

        These URLs can be manipulated by sending misleading host headers. `app.url_for` should be used instead if this is a concern.

.. column::

    ```python
    app.config.SERVER_NAME = "https://example.com"

    @app.route("/hosts", name="foo")
    async def handler(request):
        return json(
            {
                "effective host": request.host,
                "host header": request.headers.get("host"),
                "forwarded host": request.forwarded.get("host"),
                "you are here": request.url_for("foo"),
            }
        )
    ```

    ```sh
    curl localhost:8000/hosts
    {
      "effective host": "example.com",
      "host header": "localhost:8000",
      "forwarded host": null,
      "you are here": "https://example.com/hosts"
    }
    ```

### Other headers

.. column::


    All request headers are available on `request.headers`, and can be accessed in dictionary form. Capitalization is not considered for headers, and can be accessed using either uppercase or lowercase keys.

.. column::

    ```python
    @app.route("/")
    async def handler(request):
        return json(
            {
                "foo_weakref": request.headers["foo"],
                "foo_get": request.headers.get("Foo"),
                "foo_getone": request.headers.getone("FOO"),
                "foo_getall": request.headers.getall("fOo"),
                "all": list(request.headers.items()),
            }
        )
    ```

    ```sh
    curl localhost:9999/headers -H "Foo: one" -H "FOO: two"|jq
    {
      "foo_weakref": "one",
      "foo_get": "one",
      "foo_getone": "one",
      "foo_getall": [
        "one",
        "two"
      ],
      "all": [
        [
          "host",
          "localhost:9999"
        ],
        [
          "user-agent",
          "curl/7.76.1"
        ],
        [
          "accept",
          "*/*"
        ],
        [
          "foo",
          "one"
        ],
        [
          "foo",
          "two"
        ]
      ]
    }
    ```



.. tip:: FYI

    💡 The request.headers object is one of a few types that is a dictionary with each value being a list. This is because HTTP allows a single key to be reused to send multiple values.

    Most of the time you will want to use the .get() or .getone() methods to access the first element and not a list. If you do want a list of all items, you can use .getall().


### Request ID

.. column::

    Often it is convenient or necessary to track a request by its `X-Request-ID` header. You can easily access that as: `request.id`.

.. column::

    ```python
    @app.route("/")
    async def handler(request):
        return text(request.id)
    ```

    ```sh
    curl localhost:8000 \
        -H "X-Request-ID: ABCDEF12345679"
    ABCDEF12345679
    ```

## Response

Sanic will automatically set the following response headers (when appropriate) for you:

- `content-length`
- `content-type`
- `connection`
- `transfer-encoding`

In most circumstances, you should never need to worry about setting these headers.

.. column::

    Any other header that you would like to set can be done either in the route handler, or a response middleware.

.. column::

    ```python
    @app.route("/")
    async def handler(request):
        return text("Done.", headers={"content-language": "en-US"})

    @app.middleware("response")
    async def add_csp(request, response):
        response.headers["content-security-policy"] = "default-src 'none'; script-src 'self'; connect-src 'self'; img-src 'self'; style-src 'self';base-uri 'self';form-action 'self'"
    ```


.. column::

    A common [middleware](middleware.md) you might want is to add a `X-Request-ID` header to every response. As stated above: `request.id` will provide the ID from the incoming request. But, even if no ID was supplied in the request headers, one will be automatically supplied for you.

    [See API docs for more details](https://sanic.readthedocs.io/en/latest/sanic/api_reference.html#sanic.request.Request.id)

.. column::

    ```python
    @app.route("/")
    async def handler(request):
        return text(str(request.id))

    @app.on_response
    async def add_request_id_header(request, response):
        response.headers["X-Request-ID"] = request.id
    ```

    ```sh
    curl localhost:8000 -i
    HTTP/1.1 200 OK
    X-Request-ID: 805a958e-9906-4e7a-8fe0-cbe83590431b
    content-length: 36
    connection: keep-alive
    content-type: text/plain; charset=utf-8

    805a958e-9906-4e7a-8fe0-cbe83590431b
    ```

---

### Guide Content En Guide Basics Listeners (`guide/content/en/guide/basics/listeners.md`)

# Listeners

Sanic provides you with eight (8) opportunities to inject an operation into the life cycle of your application server. This does not include the [signals](../advanced/signals.md), which allow further injection customization.

There are two (2) that run **only** on your main Sanic process (ie, once per call to `sanic server.app`.)

- `main_process_start`
- `main_process_stop`

There are also two (2) that run **only** in a reloader process if auto-reload has been turned on.

- `reload_process_start`
- `reload_process_stop`

*Added `reload_process_start` and `reload_process_stop` in v22.3*

There are four (4) that enable you to execute startup/teardown code as your server starts or closes.

- `before_server_start`
- `after_server_start`
- `before_server_stop`
- `after_server_stop`

The life cycle of a worker process looks like this:

.. mermaid::

    sequenceDiagram
    autonumber
    participant Process
    participant Worker
    participant Listener
    participant Handler
    Note over Process: sanic server.app
    loop
        Process->>Listener: @app.main_process_start
        Listener->>Handler: Invoke event handler
    end
    Process->>Worker: Run workers
    loop Start each worker
        loop
            Worker->>Listener: @app.before_server_start
            Listener->>Handler: Invoke event handler
        end
        Note over Worker: Server status: started
        loop
            Worker->>Listener: @app.after_server_start
            Listener->>Handler: Invoke event handler
        end
        Note over Worker: Server status: ready
    end
    Process->>Worker: Graceful shutdown
    loop Stop each worker
        loop
            Worker->>Listener: @app.before_server_stop
            Listener->>Handler: Invoke event handler
        end
        Note over Worker: Server status: stopped
        loop
            Worker->>Listener: @app.after_server_stop
            Listener->>Handler: Invoke event handler
        end
        Note over Worker: Server status: closed
    end
    loop
        Process->>Listener: @app.main_process_stop
        Listener->>Handler: Invoke event handler
    end
    Note over Process: exit


The reloader process live outside of this worker process inside of a process that is responsible for starting and stopping the Sanic processes. Consider the following example:

```python
@app.reload_process_start
async def reload_start(*_):
    print(">>>>>> reload_start <<<<<<")

@app.main_process_start
async def main_start(*_):
    print(">>>>>> main_start <<<<<<")
	
@app.before_server_start
async def before_start(*_):
	print(">>>>>> before_start <<<<<<")
```

If this application were run with auto-reload turned on, the `reload_start` function would be called once when the reloader process starts. The `main_start` function would also be called once when the main process starts. **HOWEVER**, the `before_start` function would be called once for each worker process that is started, and subsequently every time that a file is saved and the worker is restarted.

## Attaching a listener

.. column::

    The process to setup a function as a listener is similar to declaring a route.

    The currently running `Sanic()` instance is injected into the listener.

.. column::

    ```python
    async def setup_db(app):
        app.ctx.db = await db_setup()

    app.register_listener(setup_db, "before_server_start")
    ```


.. column::

    The `Sanic` app instance also has a convenience decorator.

.. column::

    ```python
    @app.listener("before_server_start")
    async def setup_db(app):
        app.ctx.db = await db_setup()
    ```


.. column::

    Prior to v22.3, both the application instance and the current event loop were injected into the function. However, only the application instance is injected by default. If your function signature will accept both, then both the application and the loop will be injected as shown here.

.. column::

    ```python
    @app.listener("before_server_start")
    async def setup_db(app, loop):
        app.ctx.db = await db_setup()
    ```


.. column::

    You can shorten the decorator even further. This is helpful if you have an IDE with autocomplete.

.. column::

    ```python
    @app.before_server_start
    async def setup_db(app):
        app.ctx.db = await db_setup()
    ```

## Order of execution

Listeners are executed in the order they are declared during startup, and reverse order of declaration during teardown

|                       | Phase           | Order   |
|-----------------------|-----------------|---------|
| `main_process_start`  | main startup    | regular 🙂 ⬇️ |
| `before_server_start` | worker startup  | regular 🙂 ⬇️ |
| `after_server_start`  | worker startup  | regular 🙂 ⬇️ |
| `before_server_stop`  | worker shutdown | 🙃 ⬆️ reverse |
| `after_server_stop`   | worker shutdown | 🙃 ⬆️ reverse |
| `main_process_stop`   | main shutdown   | 🙃 ⬆️ reverse |

Given the following setup, we should expect to see this in the console if we run two workers.

.. column::

    ```python
    @app.listener("before_server_start")
    async def listener_1(app, loop):
        print("listener_1")

    @app.before_server_start
    async def listener_2(app, loop):
        print("listener_2")

    @app.listener("after_server_start")
    async def listener_3(app, loop):
        print("listener_3")

    @app.after_server_start
    async def listener_4(app, loop):
        print("listener_4")

    @app.listener("before_server_stop")
    async def listener_5(app, loop):
        print("listener_5")

    @app.before_server_stop
    async def listener_6(app, loop):
        print("listener_6")

    @app.listener("after_server_stop")
    async def listener_7(app, loop):
        print("listener_7")

    @app.after_server_stop
    async def listener_8(app, loop):
        print("listener_8")
    ```

.. column::

    ```bash
    [pid: 1000000] [INFO] Goin' Fast @ http://127.0.0.1:9999
    [pid: 1000000] [INFO] listener_0
    [pid: 1111111] [INFO] listener_1
    [pid: 1111111] [INFO] listener_2
    [pid: 1111111] [INFO] listener_3
    [pid: 1111111] [INFO] listener_4
    [pid: 1111111] [INFO] Starting worker [1111111]
    [pid: 1222222] [INFO] listener_1
    [pid: 1222222] [INFO] listener_2
    [pid: 1222222] [INFO] listener_3
    [pid: 1222222] [INFO] listener_4
    [pid: 1222222] [INFO] Starting worker [1222222]
    [pid: 1111111] [INFO] Stopping worker [1111111]
    [pid: 1222222] [INFO] Stopping worker [1222222]
    [pid: 1222222] [INFO] listener_6
    [pid: 1222222] [INFO] listener_5
    [pid: 1222222] [INFO] listener_8
    [pid: 1222222] [INFO] listener_7
    [pid: 1111111] [INFO] listener_6
    [pid: 1111111] [INFO] listener_5
    [pid: 1111111] [INFO] listener_8
    [pid: 1111111] [INFO] listener_7
    [pid: 1000000] [INFO] listener_9
    [pid: 1000000] [INFO] Server Stopped
    ```
    In the above example, notice how there are three processes running:

    - `pid: 1000000` - The *main* process
    - `pid: 1111111` - Worker 1
    - `pid: 1222222` - Worker 2

    *Just because our example groups all of one worker and then all of another, in reality since these are running on separate processes, the ordering between processes is not guaranteed. But, you can be sure that a single worker will **always** maintain its order.*



.. tip:: FYI

    The practical result of this is that if the first listener in `before_server_start` handler setups a database connection, listeners that are registered after it can rely upon that connection being alive both when they are started and stopped.

### Priority

In v23.12, the `priority` keyword argument was added to listeners. This allows for fine-tuning the order of execution of listeners. The default priority is `0`. Listeners with a higher priority will be executed first. Listeners with the same priority will be executed in the order they were registered. Furthermore, listeners attached to the `app` instance will be executed before listeners attached to a `Blueprint` instance.
	
Overall the rules for deciding the order of execution are as follows:

1. Priority in descending order
2. Application listeners before Blueprint listeners
3. Registration order

.. column::

    As an example, consider the following, which will print:

    ```bash
    third
    bp_third
    second
    bp_second
    first
    fourth
    bp_first
    ```

.. column::

    ```python
    @app.before_server_start
    async def first(app):
        print("first")

    @app.listener("before_server_start", priority=2)
    async def second(app):
        print("second")

    @app.before_server_start(priority=3)
    async def third(app):
        print("third")

    @bp.before_server_start
    async def bp_first(app):
        print("bp_first")

    @bp.listener("before_server_start", priority=2)
    async def bp_second(app):
        print("bp_second")

    @bp.before_server_start(priority=3)
    async def bp_third(app):
        print("bp_third")

    @app.before_server_start
    async def fourth(app):
        print("fourth")

    app.blueprint(bp)
    ```

## ASGI Mode

If you are running your application with an ASGI server, then make note of the following changes:

- `reload_process_start` and `reload_process_stop` will be **ignored**
- `main_process_start` and `main_process_stop` will be **ignored**
- `before_server_start` will run as early as it can, and will be before `after_server_start`, but technically, the server is already running at that point
- `after_server_stop` will run as late as it can, and will be after `before_server_stop`, but technically, the server is still running at that point

---

### Guide Content En Guide Basics Middleware (`guide/content/en/guide/basics/middleware.md`)

# Middleware

Whereas listeners allow you to attach functionality to the lifecycle of a worker process, middleware allows you to attach functionality to the lifecycle of an HTTP stream.

```python
@app.on_request
async def example(request):
	print("I execute before the handler.")
```

You can execute middleware either _before_ the handler is executed, or _after_.

```python
@app.on_response
async def example(request, response):
	print("I execute after the handler.")
```

.. mermaid::

    sequenceDiagram
    autonumber
    participant Worker
    participant Middleware
    participant MiddlewareHandler
    participant RouteHandler
    Note over Worker: Incoming HTTP request
    loop
        Worker->>Middleware: @app.on_request
        Middleware->>MiddlewareHandler: Invoke middleware handler
        MiddlewareHandler-->>Worker: Return response (optional)
    end
    rect rgba(255, 13, 104, .1)
    Worker->>RouteHandler: Invoke route handler
    RouteHandler->>Worker: Return response
    end
    loop
        Worker->>Middleware: @app.on_response
        Middleware->>MiddlewareHandler: Invoke middleware handler
        MiddlewareHandler-->>Worker: Return response (optional)
    end
    Note over Worker: Deliver response

## Attaching middleware

.. column::

    This should probably look familiar by now. All you need to do is declare when you would like the middleware to execute: on the `request` or on the `response`.

.. column::

    ```python
    async def extract_user(request):
        request.ctx.user = await extract_user_from_request(request)

    app.register_middleware(extract_user, "request")
    ```

.. column::

    Again, the `Sanic` app instance also has a convenience decorator.

.. column::

    ```python
    @app.middleware("request")
    async def extract_user(request):
        request.ctx.user = await extract_user_from_request(request)
    ```

.. column::

    Response middleware receives both the `request` and `response` arguments.

.. column::

    ```python
    @app.middleware('response')
    async def prevent_xss(request, response):
        response.headers["x-xss-protection"] = "1; mode=block"
    ```

.. column::

    You can shorten the decorator even further. This is helpful if you have an IDE with autocomplete.

    This is the preferred usage, and is what we will use going forward.

.. column::

    ```python
    @app.on_request
    async def extract_user(request):
        ...

    @app.on_response
    async def prevent_xss(request, response):
        ...
    ```

## Modification

Middleware can modify the request or response parameter it is given, _as long as it does not return it_.


.. column::

    #### Order of execution

    1. Request middleware: `add_key`
    2. Route handler: `index`
    3. Response middleware: `prevent_xss`
    4. Response middleware: `custom_banner`

.. column::

    ```python
    @app.on_request
    async def add_key(request):
        # Arbitrary data may be stored in request context:
        request.ctx.foo = "bar"

    @app.on_response
    async def custom_banner(request, response):
        response.headers["Server"] = "Fake-Server"

    @app.on_response
    async def prevent_xss(request, response):
        response.headers["x-xss-protection"] = "1; mode=block"

    @app.get("/")
    async def index(request):
        return text(request.ctx.foo)

    ```

.. column::

    You can modify the `request.match_info`. A useful feature that could be used, for example, in middleware to convert `a-slug` to `a_slug`.

.. column::

    ```python
    @app.on_request
    def convert_slug_to_underscore(request: Request):
        request.match_info["slug"] = request.match_info["slug"].replace("-", "_")

    @app.get("/<slug:slug>")
    async def handler(request, slug):
        return text(slug)
    ```
    ```
    $ curl localhost:9999/foo-bar-baz
    foo_bar_baz
    ```

## Responding early

.. column::

    If middleware returns a `HTTPResponse` object, the request will stop processing and the response will be returned. If this occurs to a request before the route handler is reached, the handler will **not** be called. Returning a response will also prevent any further middleware from running.

    

.. tip:: 

    You can return a `None` value to stop the execution of the middleware handler to allow the request to process as normal. This can be useful when using early return to avoid processing requests inside of that middleware handler.

.. column::

    ```python
    @app.on_request
    async def halt_request(request):
        return text("I halted the request")

    @app.on_response
    async def halt_response(request, response):
        return text("I halted the response")
    ```

## Order of execution

Request middleware is executed in the order declared. Response middleware is executed in **reverse order**.

Given the following setup, we should expect to see this in the console.

.. column::

    ```python
    @app.on_request
    async def middleware_1(request):
        print("middleware_1")

    @app.on_request
    async def middleware_2(request):
        print("middleware_2")

    @app.on_response
    async def middleware_3(request, response):
        print("middleware_3")

    @app.on_response
    async def middleware_4(request, response):
        print("middleware_4")
    
    @app.get("/handler")
    async def handler(request):
        print("~ handler ~")
        return text("Done.")
    ```

.. column::

    ```bash
    middleware_1
    middleware_2
    ~ handler ~
    middleware_4
    middleware_3
    [INFO][127.0.0.1:44788]: GET http://localhost:8000/handler  200 5
    ```

### Middleware priority

.. column::

    You can modify the order of execution of middleware by assigning it a higher priority. This happens inside of the middleware definition. The higher the value, the earlier it will execute relative to other middleware. The default priority for middleware is `0`.

.. column::

    ```python
    @app.on_request
    async def low_priority(request):
        ...

    @app.on_request(priority=99)
    async def high_priority(request):
        ...
    ```

*Added in v22.9*

---

### Guide Content En Guide Basics Request (`guide/content/en/guide/basics/request.md`)

# Request

See API docs: [sanic.request](/api/sanic.request)

The :class:`sanic.request.Request` instance contains **a lot** of helpful information available on its parameters. Refer to the [API documentation](https://sanic.readthedocs.io/) for full details.

As we saw in the section on [handlers](./handlers.md), the first argument in a route handler is usually the :class:`sanic.request.Request` object. Because Sanic is an async framework, the handler will run inside of a [`asyncio.Task`](https://docs.python.org/3/library/asyncio-task.html#asyncio.Task) and will be scheduled by the event loop. This means that the handler will be executed in an isolated context and the request object will be unique to that handler's task.

.. column::

    By convention, the argument is named `request`, but you can name it whatever you want. The name of the argument is not important. Both of the following handlers are valid.
    
.. column::

    ```python
    @app.get("/foo")
    async def typical_use_case(request):
        return text("I said foo!")
    ```

    ```python
    @app.get("/foo")
    async def atypical_use_case(req):
        return text("I said foo!")
    ```

.. column::

    Annotating a request object is super simple.
        
.. column::

    ```python
    from sanic.request import Request
    from sanic.response import text

    @app.get("/typed")
    async def typed_handler(request: Request):
        return text("Done.")
    ```

.. tip::
    
    For your convenience, assuming you are using a modern IDE, you should leverage type annotations to help with code completion and documentation. This is especially helpful when using the `request` object as it has **MANY** properties and methods.
        
    To see the full list of available properties and methods, refer to the [API documentation](/api/sanic.request).

## Body

The `Request` object allows you to access the content of the request body in a few different ways.

### JSON

.. column::

    **Parameter**: `request.json`  
    **Description**: The parsed JSON object

.. column::

    ```bash
    $ curl localhost:8000 -d '{"foo": "bar"}'
    ```

    ```python
    >>> print(request.json)
    {'foo': 'bar'}
    ```

### Raw

.. column::

    **Parameter**: `request.body`  
    **Description**: The raw bytes from the request body

.. column::

    ```bash
    $ curl localhost:8000 -d '{"foo": "bar"}'
    ```

    ```python
    >>> print(request.body)
    b'{"foo": "bar"}'
    ```

### Form

.. column::

    **Parameter**: `request.form`  
    **Description**: The form data

    .. tip:: FYI

        The `request.form` object is one of a few types that is a dictionary with each value being a list. This is because HTTP allows a single key to be reused to send multiple values.  

        Most of the time you will want to use the `.get()` method to access the first element and not a list. If you do want a list of all items, you can use `.getlist()`.

.. column::

    ```bash
    $ curl localhost:8000 -d 'foo=bar'
    ```

    ```python
    >>> print(request.body)
    b'foo=bar'

    >>> print(request.form)
    {'foo': ['bar']}

    >>> print(request.form.get("foo"))
    bar

    >>> print(request.form.getlist("foo"))
    ['bar']
    ```

### Uploaded

.. column::

    **Parameter**: `request.files`  
    **Description**: The files uploaded to the server

    .. tip:: FYI

        The `request.files` object is one of a few types that is a dictionary with each value being a list. This is because HTTP allows a single key to be reused to send multiple values.  

        Most of the time you will want to use the `.get()` method to access the first element and not a list. If you do want a list of all items, you can use `.getlist()`.

.. column::

    ```bash
    $ curl -F 'my_file=@/path/to/TEST' http://localhost:8000
    ```

    ```python
    >>> print(request.body)
    b'--------------------------cb566ad845ad02d3\r\nContent-Disposition: form-data; name="my_file"; filename="TEST"\r\nContent-Type: application/octet-stream\r\n\r\nhello\n\r\n--------------------------cb566ad845ad02d3--\r\n'

    >>> print(request.files)
    {'my_file': [File(type='application/octet-stream', body=b'hello\n', name='TEST')]}

    >>> print(request.files.get("my_file"))
    File(type='application/octet-stream', body=b'hello\n', name='TEST')

    >>> print(request.files.getlist("my_file"))
    [File(type='application/octet-stream', body=b'hello\n', name='TEST')]
    ```

## Context

### Request context

The `request.ctx` object is your playground to store whatever information you need to about the request. This lives only for the duration of the request and is unique to the request.

This can be constrasted with the `app.ctx` object which is shared across all requests. Be careful not to confuse them! 

The `request.ctx` object by default is a `SimpleNamespace` object allowing you to set arbitrary attributes on it. Sanic will not use this object for anything, so you are free to use it however you want without worrying about name clashes.

### Typical use case

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.on_request
async def run_before_handler(request):
    request.ctx.user = await fetch_user_by_token(request.token)

@app.route('/hi')
async def hi_my_name_is(request):
    if not request.ctx.user:
        return text("Hmm... I don't know you)
    return text(f"Hi, my name is {request.ctx.user.name}")
```

As you can see, the `request.ctx` object is a great place to store information that you need to access in multiple handlers making your code more DRY and easier to maintain. But, as we will learn in the [middleware section](./middleware.md), you can also use it to store information from one middleware that will be used in another.

### Connection context

.. column::

    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](../running/configuration.md#keep-alive-timeout).

    When multiple requests share a single connection, Sanic provides a context object to allow those requests to share state.

.. column::

    ```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={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::

    While this looks like a convenient place to store information between requests by a single HTTP connection, do not assume that all requests on a single connection came from a single end user. This is because HTTP proxies and load balancers can multiplex multiple connections into a single connection to your server.
    
    **DO NOT** use this to store information about a single user. Use the `request.ctx` object for that.

### Custom Request Objects

As discussed in [application customization](./app.md#custom-requests), you can create a subclass of :class:`sanic.request.Request` to add additional functionality to the request object. This is useful for adding additional attributes or methods that are specific to your application.

.. column::

    For example, imagine your application sends a custom header that contains a user ID. You can create a custom request object that will parse that header and store the user ID for you.

.. column::

    ```python
    from sanic import Sanic, Request

    class CustomRequest(Request):
        def __init__(self, *args, **kwargs):
            super().__init__(*args, **kwargs)
            self.user_id = self.headers.get("X-User-ID")

    app = Sanic("Example", request_class=CustomRequest)
    ```


.. column::

    Now, in your handlers, you can access the `user_id` attribute.

.. column::

    ```python
    @app.route("/")
    async def handler(request: CustomRequest):
        return text(f"User ID: {request.user_id}")
    ```


### Custom Request Context

By default, the request context (`request.ctx`) is a [`Simplenamespace`](https://docs.python.org/3/library/types.html#types.SimpleNamespace) object allowing you to set arbitrary attributes on it. While this is super helpful to reuse logic across your application, it can be difficult in the development experience since the IDE will not know what attributes are available.

To help with this, you can create a custom request context object that will be used instead of the default `SimpleNamespace`. This allows you to add type hints to the context object and have them be available in your IDE.

.. column::

    Start by subclassing the :class:`sanic.request.Request` class to create a custom request type. Then, you will need to add a `make_context()` method that returns an instance of your custom context object. *NOTE: the `make_context` method should be a static method.*

.. column::

    ```python
    from sanic import Sanic, Request
    from types import SimpleNamespace

    class CustomRequest(Request):
        def __init__(self, *args, **kwargs):
            super().__init__(*args, **kwargs)
            self.ctx.user_id = self.headers.get("X-User-ID")

        @staticmethod
        def make_context() -> CustomContext:
            return CustomContext()

    @dataclass
    class CustomContext:
        user_id: str = None
    ```

.. note::

    This is a Sanic poweruser feature that makes it super convenient in large codebases to have typed request context objects. It is of course not required, but can be very helpful.

*Added in v23.6*


## Parameters

.. column::

    Values that are extracted from the path parameters are injected into the handler as argumets, or more specifically as keyword arguments. There is much more detail about this in the [Routing section](./routing.md).

.. column::

    ```python
    @app.route('/tag/<tag>')
    async def tag_handler(request, tag):
        return text("Tag - {}".format(tag))
    
    # or, explicitly as keyword arguments
    @app.route('/tag/<tag>')
    async def tag_handler(request, *, tag):
        return text("Tag - {}".format(tag))
    ```


## Arguments

There are two attributes on the `request` instance to get query parameters:

- `request.args`
- `request.query_args`

These allow you to access the query parameters from the request path (the part after the `?` in the URL).

### Typical use case

In most use cases, you will want to use the `request.args` object to access the query parameters. This will be the parsed query string as a dictionary.

This is by far the most common pattern.

.. column::

    Consider the example where we have a `/search` endpoint with a `q` parameter that we want to use to search for something.

.. column::

    ```python
    @app.get("/search")
    async def search(request):
       query = request.args.get("q")
        if not query:
            return text("No query string provided")
        return text(f"Searching for: {query}")
    ```

### Parsing the query string

Sometimes, however, you may want to access the query string as a raw string or as a list of tuples. For this, you can use the `request.query_string` and `request.query_args` attributes. 

It also should be noted that HTTP allows multiple values for a single key. Although `request.args` may seem like a regular dictionary, it is actually a special type that allows for multiple values for a single key. You can access this by using the `request.args.getlist()` method.

- `request.query_string` - The raw query string
- `request.query_args` - The parsed query string as a list of tuples
- `request.args` - The parsed query string as a *special* dictionary
  - `request.args.get()` - Get the first value for a key (behaves like a regular dictionary)
  - `request.args.getlist()` - Get all values for a key

```sh
curl "http://localhost:8000?key1=val1&key2=val2&key1=val3"
```

```python
>>> print(request.args)
{'key1': ['val1', 'val3'], 'key2': ['val2']}

>>> print(request.args.get("key1"))
val1

>>> print(request.args.getlist("key1"))
['val1', 'val3']

>>> print(request.query_args)
[('key1', 'val1'), ('key2', 'val2'), ('key1', 'val3')]

>>> print(request.query_string)
key1=val1&key2=val2&key1=val3

```


.. tip:: FYI

    The `request.args` object is one of a few types that is a dictionary with each value being a list. This is because HTTP allows a single key to be reused to send multiple values.  

    Most of the time you will want to use the `.get()` method to access the first element and not a list. If you do want a list of all items, you can use `.getlist()`.

## Current request getter

Sometimes you may find that you need access to the current request in your application in a location where it is not accessible. A typical example might be in a `logging` format. You can use `Request.get_current()` to fetch the current request (if any).

Remember, the request object is confined to the single [`asyncio.Task`](https://docs.python.org/3/library/asyncio-task.html#asyncio.Task) that is running the handler. If you are not in that task, there is no request object.

```python
import logging

from sanic import Request, Sanic, json
from sanic.exceptions import SanicException
from sanic.log import LOGGING_CONFIG_DEFAULTS

LOGGING_FORMAT = (
    "%(asctime)s - (%(name)s)[%(levelname)s][%(host)s]: "
    "%(request_id)s %(request)s %(message)s %(status)d %(byte)d"
)

old_factory = logging.getLogRecordFactory()

def record_factory(*args, **kwargs):
    record = old_factory(*args, **kwargs)
    record.request_id = ""

    try:
        request = Request.get_current()
    except SanicException:
        ...
    else:
        record.request_id = str(request.id)

    return record

logging.setLogRecordFactory(record_factory)


LOGGING_CONFIG_DEFAULTS["formatters"]["access"]["format"] = LOGGING_FORMAT
app = Sanic("Example", log_config=LOGGING_CONFIG_DEFAULTS)
```

In this example, we are adding the `request.id` to every access log message.

*Added in v22.6*

---

### Guide Content En Guide Basics Response (`guide/content/en/guide/basics/response.md`)

# Response

All [handlers](./handlers.md) *usually* return a response object, and [middleware](./middleware.md) may optionally return a response object.

To clarify that statement:
- unless the handler is a streaming endpoint handling its own pattern for sending bytes to the client, the return value must be an instance of :class:`sanic.response.HTTPResponse` (to learn more about this exception see [streaming responses](../advanced/streaming.md#response-streaming)). In **most** use cases, you will need to return a response.
- if a middleware does return a response object, that will be used instead of whatever the handler would do (see [middleware](./middleware.md) to learn more).

A most basic handler would look like the following. The :class:`sanic.response.HTTPResponse` object will allow you to set the status, body, and headers to be returned to the client.

```python
from sanic import HTTPResponse, Sanic

app = Sanic("TestApp")

@app.route("")
def handler(_):
    return HTTPResponse()
```

However, usually it is easier to use one of the convenience methods discussed below.

## Methods

The easiest way to generate a response object is to use one of the convenience functions.

### Text

.. column::

    **Default Content-Type**: `text/plain; charset=utf-8`  
    **Description**: Returns plain text

.. column::

    ```python
    from sanic import text

    @app.route("/")
    async def handler(request):
        return text("Hi 😎")
    ```

### HTML

.. column::

    **Default Content-Type**: `text/html; charset=utf-8`  
    **Description**: Returns an HTML document

.. column::

    ```python
    from sanic import html

    @app.route("/")
    async def handler(request):
        return html('<!DOCTYPE html><html lang="en"><meta charset="UTF-8"><div>Hi 😎</div>')
    ```

### JSON

.. column::

    **Default Content-Type**: `application/json`  
    **Description**: Returns a JSON document

.. column::

    ```python
    from sanic import json

    @app.route("/")
    async def handler(request):
        return json({"foo": "bar"})
    ```

By default, Sanic ships with [`ujson`](https://github.com/ultrajson/ultrajson) as its JSON encoder of choice. If `ujson` is not installed, it will fall back to the standard library `json` module.

It is super simple to change this if you want.

```python
from sanic import json
from orjson import dumps

json({"foo": "bar"}, dumps=dumps)
```

You may additionally declare which implementation to use globally across your application at initialization:

```python
from orjson import dumps

app = Sanic(..., dumps=dumps)
```

### File

.. column::

    **Default Content-Type**: N/A  
    **Description**: Returns a file

.. column::

    ```python
    from sanic import file

    @app.route("/")
    async def handler(request):
        return await file("/path/to/whatever.png")
    ```

Sanic will examine the file, and try and guess its mime type and use an appropriate value for the content type. You could be explicit, if you would like:

```python
file("/path/to/whatever.png", mime_type="image/png")
```

You can also choose to override the file name:

```python
file("/path/to/whatever.png", filename="super-awesome-incredible.png")
```

### File Streaming

.. column::

    **Default Content-Type**: N/A  
    **Description**: Streams a file to a client, useful when streaming large files, like a video

.. column::

    ```python
    from sanic.response import file_stream

    @app.route("/")
    async def handler(request):
        return await file_stream("/path/to/whatever.mp4")
    ```

Like the `file()` method, `file_stream()` will attempt to determine the mime type of the file.



### Raw

.. column::

    **Default Content-Type**: `application/octet-stream`  
    **Description**: Send raw bytes without encoding the body

.. column::

    ```python
    from sanic import raw

    @app.route("/")
    async def handler(request):
        return raw(b"raw bytes")
    ```

### Redirect

.. column::

    **Default Content-Type**: `text/html; charset=utf-8`  
    **Description**: Send a `302` response to redirect the client to a different path

.. column::

    ```python
    from sanic import redirect

    @app.route("/")
    async def handler(request):
        return redirect("/login")
    ```

### Empty

.. column::

    **Default Content-Type**: N/A  
    **Description**: For responding with an empty message as defined by [RFC 2616](https://tools.ietf.org/search/rfc2616#section-7.2.1)

.. column::

    ```python
    from sanic import empty

    @app.route("/")
    async def handler(request):
        return empty()
    ```

    Defaults to a `204` status.

## Default status

The default HTTP status code for the response is `200`. If you need to change it, it can be done by the response method.

```python
@app.post("/")
async def create_new(request):
    new_thing = await do_create(request)
    return json({"created": True, "id": new_thing.thing_id}, status=201)
```

## Returning JSON data

Starting in v22.12, When you use the `sanic.json` convenience method, it will return a subclass of `HTTPResponse` called :class:`sanic.response.types.JSONResponse`. This object will 
have several convenient methods available to modify common JSON body.

```python
from sanic import json

resp = json(...)
```

- `resp.set_body(<raw_body>)` - Set the body of the JSON object to the value passed
- `resp.append(<value>)` - Append a value to the body like `list.append` (only works if the root JSON is an array)
- `resp.extend(<value>)` - Extend a value to the body like `list.extend` (only works if the root JSON is an array)
- `resp.update(<value>)` - Update the body with a value like `dict.update` (only works if the root JSON is an object)
- `resp.pop()` - Pop a value like `list.pop` or `dict.pop` (only works if the root JSON is an array or an object)

.. warning::

    The raw Python object is stored on the `JSONResponse` object as `raw_body`. While it is safe to overwrite this value with a new one, you should **not** attempt to mutate it. You should instead use the methods listed above.

```python
resp = json({"foo": "bar"})

# This is OKAY
resp.raw_body = {"foo": "bar", "something": "else"}

# This is better
resp.set_body({"foo": "bar", "something": "else"})

# This is also works well
resp.update({"something": "else"})

# This is NOT OKAY
resp.raw_body.update({"something": "else"})
```

```python
# Or, even treat it like a list
resp = json(["foo", "bar"])

# This is OKAY
resp.raw_body = ["foo", "bar", "something", "else"]

# This is better
resp.extend(["something", "else"])

# This is also works well
resp.append("something")
resp.append("else")

# This is NOT OKAY
resp.raw_body.append("something")
```

*Added in v22.9*

---

### Guide Content En Guide Basics Routing (`guide/content/en/guide/basics/routing.md`)

# Routing

.. column::

    So far we have seen a lot of this decorator in different forms.

    But what is it? And how do we use it?

.. column::

    ```python
    @app.route("/stairway")
        ...

    @app.get("/to")
        ...

    @app.post("/heaven")
        ...
    ```

## Adding a route

.. column::

    The most basic way to wire up a handler to an endpoint is with `app.add_route()`.

    See [API docs](https://sanic.readthedocs.io/en/stable/sanic/api_reference.html#sanic.app.Sanic.url_for) for more details.

.. column::

    ```python
    async def handler(request):
        return text("OK")

    app.add_route(handler, "/test")
    ```


.. column::

    By default, routes are available as an HTTP `GET` call. You can change a handler to respond to one or more HTTP methods.

.. column::

    ```python
    app.add_route(
        handler,
        '/test',
        methods=["POST", "PUT"],
    )
    ```


.. column::

    Using the decorator syntax, the previous example is identical to this.

.. column::

    ```python
    @app.route('/test', methods=["POST", "PUT"])
    async def handler(request):
        return text('OK')
    ```

## HTTP methods

Each of the standard HTTP methods has a convenience decorator.

### GET

```python
@app.get('/test')
async def handler(request):
    return text('OK')
```

[MDN Docs](https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/GET)

### POST

```python
@app.post('/test')
async def handler(request):
    return text('OK')
```

[MDN Docs](https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/POST)

### PUT

```python
@app.put('/test')
async def handler(request):
    return text('OK')
```

[MDN Docs](https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/PUT)

### PATCH

```python
@app.patch('/test')
async def handler(request):
    return text('OK')
```

[MDN Docs](https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/PATCH)

### DELETE

```python
@app.delete('/test')
async def handler(request):
    return text('OK')
```

[MDN Docs](https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/DELETE)

### HEAD

```python
@app.head('/test')
async def handler(request):
    return empty()
```

[MDN Docs](https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/HEAD)

### OPTIONS

```python
@app.options('/test')
async def handler(request):
    return empty()
```

[MDN Docs](https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/OPTIONS)


.. warning:: 

    By default, Sanic will **only** consume the incoming request body on non-safe HTTP methods: `POST`, `PUT`, `PATCH`, `DELETE`. If you want to receive data in the HTTP request on any other method, you will need to do one of the following two options:

    **Option #1 - Tell Sanic to consume the body using `ignore_body`**
    ```python
    @app.request("/path", ignore_body=False)
    async def handler(_):
        ...
    ```

    **Option #2 - Manually consume the body in the handler using `receive_body`**
    ```python
    @app.get("/path")
    async def handler(request: Request):
        await request.receive_body()
    ```


## Path parameters

.. column::

    Sanic allows for pattern matching, and for extracting values from URL paths. These parameters are then injected as keyword arguments in the route handler.

.. column::

    ```python
    @app.get("/tag/<tag>")
    async def tag_handler(request, tag):
        return text("Tag - {}".format(tag))
    ```

.. column::

    You can declare a type for the parameter. This will be enforced when matching, and also will type cast the variable.

.. column::

    ```python
    @app.get("/foo/<foo_id:uuid>")
    async def uuid_handler(request, foo_id: UUID):
        return text("UUID - {}".format(foo_id))
    ```

.. column::

    For some standard types like `str`, `int`, and `UUID`, Sanic can infer the path parameter type from the function signature. This means that it may not always be necessary to include the type in the path parameter definition.

.. column::

    ```python
    @app.get("/foo/<foo_id>")  # Notice there is no :uuid in the path parameter
    async def uuid_handler(request, foo_id: UUID):
        return text("UUID - {}".format(foo_id))
    ```

### Supported types

### `str`

.. column::

    **Regular expression applied**: `r"[^/]+"`  
    **Cast type**: `str`  
    **Example matches**:  

    - `/path/to/Bob`
    - `/path/to/Python%203`

    Beginning in v22.3 `str` will *not* match on empty strings. See `strorempty` for this behavior.

.. column::

    ```python
    @app.route("/path/to/<foo:str>")
    async def handler(request, foo: str):
        ...
    ```

### `strorempty`

.. column::

    **Regular expression applied**: `r"[^/]*"`  
    **Cast type**: `str`  
    **Example matches**:

    - `/path/to/Bob`
    - `/path/to/Python%203`
    - `/path/to/`

    Unlike the `str` path parameter type, `strorempty` can also match on an empty string path segment.

    *Added in v22.3*

.. column::

    ```python
    @app.route("/path/to/<foo:strorempty>")
    async def handler(request, foo: str):
        ...
    ```

### `int`

.. column::

    **Regular expression applied**: `r"-?\d+"`  
    **Cast type**: `int`  
    **Example matches**:  

    - `/path/to/10`
    - `/path/to/-10`

    _Does not match float, hex, octal, etc_

.. column::

    ```python
    @app.route("/path/to/<foo:int>")
    async def handler(request, foo: int):
        ...
    ```

### `float`

.. column::

    **Regular expression applied**: `r"-?(?:\d+(?:\.\d*)?|\.\d+)"`  
    **Cast type**: `float`  
    **Example matches**:  

    - `/path/to/10`
    - `/path/to/-10`
    - `/path/to/1.5`

.. column::

    ```python
    @app.route("/path/to/<foo:float>")
    async def handler(request, foo: float):
        ...
    ```

### `alpha`

.. column::

    **Regular expression applied**: `r"[A-Za-z]+"`  
    **Cast type**: `str`  
    **Example matches**:  

    - `/path/to/Bob`
    - `/path/to/Python`

    _Does not match a digit, or a space or other special character_

.. column::

    ```python
    @app.route("/path/to/<foo:alpha>")
    async def handler(request, foo: str):
        ...
    ```

### `slug`

.. column::

    **Regular expression applied**: `r"[a-z0-9]+(?:-[a-z0-9]+)*"`  
    **Cast type**: `str`  
    **Example matches**:  

    - `/path/to/some-news-story`
    - `/path/to/or-has-digits-123`

    *Added in v21.6*

.. column::


    ```python
    @app.route("/path/to/<article:slug>")
    async def handler(request, article: str):
        ...
    ```

### `path`

.. column::

    **Regular expression applied**: `r"[^/].*?"`  
    **Cast type**: `str`  
    **Example matches**:
    - `/path/to/hello`
    - `/path/to/hello.txt`
    - `/path/to/hello/world.txt`


.. column::

    ```python
    @app.route("/path/to/<foo:path>")
    async def handler(request, foo: str):
        ...
    ```
.. warning::

    Because this will match on `/`, you should be careful and thoroughly test your patterns that use `path` so they do not capture traffic intended for another endpoint. Additionally, depending on how you use this type, you may be creating a path traversal vulnerability in your application. It is your job to protect your endpoint against this, but feel free to ask in our community channels for help if you need it :)

### `ymd`

.. column::

    **Regular expression applied**: `r"^([12]\d{3}-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01]))"`  
    **Cast type**: `datetime.date`  
    **Example matches**:  

    - `/path/to/2021-03-28`

.. column::

    ```python
    @app.route("/path/to/<foo:ymd>")
    async def handler(request, foo: datetime.date):
        ...
    ```

### `uuid`

.. column::

    **Regular expression applied**: `r"[A-Fa-f0-9]{8}-[A-Fa-f0-9]{4}-[A-Fa-f0-9]{4}-[A-Fa-f0-9]{4}-[A-Fa-f0-9]{12}"`  
    **Cast type**: `UUID`  
    **Example matches**:  

    - `/path/to/123a123a-a12a-1a1a-a1a1-1a12a1a12345`

.. column::

    ```python
    @app.route("/path/to/<foo:uuid>")
    async def handler(request, foo: UUID):
        ...
    ```

### ext

.. column::

    **Regular expression applied**: n/a
    **Cast type**: *varies*
    **Example matches**:

.. column::

    ```python
    @app.route("/path/to/<foo:ext>")
    async def handler(request, foo: str, ext: str):
        ...
    ```

| definition                        | example     | filename    | extension  |
| --------------------------------- | ----------- | ----------- | ---------- |
| \<file:ext>                       | page.txt    | `"page"`    | `"txt"`    |
| \<file:ext=jpg>                   | cat.jpg     | `"cat"`     | `"jpg"`    |
| \<file:ext=jpg\|png\|gif\|svg>    | cat.jpg     | `"cat"`     | `"jpg"`    |
| <file=int:ext>                    | 123.txt     | `123`       | `"txt"`    |
| <file=int:ext=jpg\|png\|gif\|svg> | 123.svg     | `123`       | `"svg"`    |
| <file=float:ext=tar.gz>           | 3.14.tar.gz | `3.14`      | `"tar.gz"` |

File extensions can be matched using the special `ext` parameter type. It uses a special format that allows you to specify other types of parameter types as the file name, and one or more specific extensions as shown in the example table above.

It does *not* support the `path` parameter type.

*Added in v22.3*

### regex

.. column::

    **Regular expression applied**: _whatever you insert_  
    **Cast type**: `str`  
    **Example matches**:  

    - `/path/to/2021-01-01`

    This gives you the freedom to define specific matching patterns for your use case.

    In the example shown, we are looking for a date that is in `YYYY-MM-DD` format.

.. column::

    ```python
    @app.route(r"/path/to/<foo:([12]\d{3}-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01]))>")
    async def handler(request, foo: str):
        ...
    ```

### Regex Matching


More often than not, compared with complex routing, the above example is too simple, and we use a completely different routing matching pattern, so here we will explain the advanced usage of regex matching in detail.

Sometimes, you want to match a part of a route:

```text
/image/123456789.jpg
```

If you wanted to match the file pattern, but only capture the numeric portion, you need to do some regex fun 😄:

```python
app.route(r"/image/<img_id:(?P<img_id>\d+)\.jpg>")
```

Further, these should all be acceptable:

```python
@app.get(r"/<foo:[a-z]{3}.txt>")                # matching on the full pattern
@app.get(r"/<foo:([a-z]{3}).txt>")              # defining a single matching group
@app.get(r"/<foo:(?P<foo>[a-z]{3}).txt>")       # defining a single named matching group
@app.get(r"/<foo:(?P<foo>[a-z]{3}).(?:txt)>")   # defining a single named matching group, with one or more non-matching groups
```

Also, if using a named matching group, it must be the same as the segment label.

```python
@app.get(r"/<foo:(?P<foo>\d+).jpg>")  # OK
@app.get(r"/<foo:(?P<bar>\d+).jpg>")  # NOT OK
```

For more regular usage methods, please refer to [Regular expression operations](https://docs.python.org/3/library/re.html)

## Generating a URL

.. column::

    Sanic provides a method to generate URLs based on the handler method name: `app.url_for()`. This is useful if you want to avoid hardcoding url paths into your app; instead, you can just reference the handler name.

.. column::

    ```python
    @app.route('/')
    async def index(request):
        # generate a URL for the endpoint `post_handler`
        url = app.url_for('post_handler', post_id=5)

        # Redirect to `/posts/5`
        return redirect(url)

    @app.route('/posts/<post_id>')
    async def post_handler(request, post_id):
        ...
    ```


.. column::

    You can pass any arbitrary number of keyword arguments. Anything that is _not_ a request parameter will be implemented as a part of the query string.

.. column::

    ```python
    assert app.url_for(
        "post_handler",
        post_id=5,
        arg_one="one",
        arg_two="two",
    ) == "/posts/5?arg_one=one&arg_two=two"
    ```


.. column::

    Also supported is passing multiple values for a single query key.

.. column::

    ```python
    assert app.url_for(
        "post_handler",
        post_id=5,
        arg_one=["one", "two"],
    ) == "/posts/5?arg_one=one&arg_one=two"
    ```

### Special keyword arguments

See [API Docs]() for more details.

```python
app.url_for("post_handler", post_id=5, arg_one="one", _anchor="anchor")
# '/posts/5?arg_one=one#anchor'

# _external requires you to pass an argument _server or set SERVER_NAME in app.config if not url will be same as no _external
app.url_for("post_handler", post_id=5, arg_one="one", _external=True)
# '//server/posts/5?arg_one=one'

# when specifying _scheme, _external must be True
app.url_for("post_handler", post_id=5, arg_one="one", _scheme="http", _external=True)
# 'http://server/posts/5?arg_one=one'

# you can pass all special arguments at once
app.url_for("post_handler", post_id=5, arg_one=["one", "two"], arg_two=2, _anchor="anchor", _scheme="http", _external=True, _server="another_server:8888")
# 'http://another_server:8888/posts/5?arg_one=one&arg_one=two&arg_two=2#anchor'
```

### Customizing a route name

.. column::

    A custom route name can be used by passing a `name` argument while registering the route.

.. column::

    ```python
    @app.get("/get", name="get_handler")
    def handler(request):
        return text("OK")
    ```


.. column::

    Now, use this custom name to retrieve the URL

.. column::

    ```python
    assert app.url_for("get_handler", foo="bar") == "/get?foo=bar"
    ```

## Websockets routes

.. column::

    Websocket routing works similar to HTTP methods.

.. column::

    ```python
    async def handler(request, ws):
        message = "Start"
        while True:
            await ws.send(message)
            message = await ws.recv()

    app.add_websocket_route(handler, "/test")
    ```


.. column::

    It also has a convenience decorator.

.. column::

    ```python
    @app.websocket("/test")
    async def handler(request, ws):
        message = "Start"
        while True:
            await ws.send(message)
            message = await ws.recv()
    ```

Read the [websockets section](../advanced/websockets.md) to learn more about how they work.

## Strict slashes


.. column::

    Sanic routes can be configured to strictly match on whether or not there is a trailing slash: `/`. This can be configured at a few levels and follows this order of precedence:

    1. Route
    2. Blueprint
    3. BlueprintGroup
    4. Application

.. column::

    ```python
    # provide default strict_slashes value for all routes
    app = Sanic(__file__, strict_slashes=True)
    ```

    ```python
    # overwrite strict_slashes value for specific route
    @app.get("/get", strict_slashes=False)
    def handler(request):
        return text("OK")
    ```

    ```python
    # it also works for blueprints
    bp = Blueprint(__file__, strict_slashes=True)

    @bp.get("/bp/get", strict_slashes=False)
    def handler(request):
        return text("OK")
    ```

    ```python
    bp1 = Blueprint(name="bp1", url_prefix="/bp1")
    bp2 = Blueprint(
        name="bp2",
        url_prefix="/bp2",
        strict_slashes=False,
    )

    # This will enforce strict slashes check on the routes
    # under bp1 but ignore bp2 as that has an explicitly
    # set the strict slashes check to false
    group = Blueprint.group([bp1, bp2], strict_slashes=True)
    ```

## Static files

.. column::

    In order to serve static files from Sanic, use `app.static()`.

    The order of arguments is important:

    1. Route the files will be served from
    2. Path to the files on the server

    See [API docs](https://sanic.readthedocs.io/en/stable/sanic/api/app.html#sanic.app.Sanic.static) for more details.

.. column::

    ```python
    app.static("/static/", "/path/to/directory/")
    ```



.. tip:: 

    It is generally best practice to end your directory paths with a trailing slash (`/this/is/a/directory/`). This removes ambiguity by being more explicit.




.. column::

    You can also serve individual files.

.. column::

    ```python
    app.static("/", "/path/to/index.html")
    ```


.. column::

    It is also sometimes helpful to name your endpoint

.. column::

    ```python
    app.static(
        "/user/uploads/",
        "/path/to/uploads/",
        name="uploads",
    )
    ```


.. column::

    Retrieving the URLs works similar to handlers. But, we can also add the `filename` argument when we need a specific file inside a directory.

.. column::

    ```python
    assert app.url_for(
        "static",
        name="static",
        filename="file.txt",
    ) == "/static/file.txt"
    ```
    ```python
    assert app.url_for(
        "static",
        name="uploads",
        filename="image.png",
    ) == "/user/uploads/image.png"

    ```



.. tip:: 

    If you are going to have multiple `static()` routes, then it is *highly* suggested that you manually name them. This will almost certainly alleviate potential hard to discover bugs.

    ```python
    app.static("/user/uploads/", "/path/to/uploads/", name="uploads")
    app.static("/user/profile/", "/path/to/profile/", name="profile_pics")
    ```


#### Auto index serving

.. column::

    If you have a directory of static files that should be served by an index page, you can provide the filename of the index. Now, when reaching that directory URL, the index page will be served.

.. column::

    ```python
    app.static("/foo/", "/path/to/foo/", index="index.html")
    ```

*Added in v23.3*

#### File browser

.. column::

    When serving a directory from a static handler, Sanic can be configured to show a basic file browser instead using `directory_view=True`.

.. column::

    ```python
    app.static("/uploads/", "/path/to/dir", directory_view=True)
    ```

You now have a browsable directory in your web browser:



*Added in v23.3*

#### Symlink control

.. new:: New in v25.12

    This feature was added in version 25.12

.. column::

    By default, Sanic will not follow symlinks that point outside the static root directory for security reasons. You can enable external symlinks separately for files and directories using `follow_external_symlink_files` and `follow_external_symlink_dirs`.

.. column::

    ```python
    # Allow file symlinks pointing outside static root
    app.static(
        "/static",
        "/var/www/static",
        follow_external_symlink_files=True,
    )

    # Allow directory symlinks pointing outside static root
    app.static(
        "/static",
        "/var/www/static",
        follow_external_symlink_dirs=True,
    )
    ```

Symlinks within the static root always work regardless of these settings. Broken symlinks are always hidden from directory listings and return 404.

*Added in v25.12*

## Route context


.. column::

    When a route is defined, you can add any number of keyword arguments with a `ctx_` prefix. These values will be injected into the route `ctx` object.

.. column::

    ```python
    @app.get("/1", ctx_label="something")
    async def handler1(request):
        ...

    @app.get("/2", ctx_label="something")
    async def handler2(request):
        ...

    @app.get("/99")
    async def handler99(request):
        ...

    @app.on_request
    async def do_something(request):
        if request.route.ctx.label == "something":
            ...
    ```

*Added in v21.12*

---

### Guide Content En Guide Basics Tasks (`guide/content/en/guide/basics/tasks.md`)

---
title: Background tasks
---

# Background tasks

## Creating Tasks
It is often desirable and very convenient to make usage of [tasks](https://docs.python.org/3/library/asyncio-task.html#asyncio.create_task) in async Python. Sanic provides a convenient method to add tasks to the currently **running** loop. It is somewhat similar to `asyncio.create_task`. For adding tasks before the 'App' loop is running, see next section.

```python
async def notify_server_started_after_five_seconds():
    await asyncio.sleep(5)
    print('Server successfully started!')

app.add_task(notify_server_started_after_five_seconds())
```

.. column::

    Sanic will attempt to automatically inject the app, passing it as an argument to the task.

.. column::

    ```python
    async def auto_inject(app):
        await asyncio.sleep(5)
        print(app.name)

    app.add_task(auto_inject)
    ```


.. column::

    Or you can pass the `app` argument explicitly.

.. column::

    ```python
    async def explicit_inject(app):
        await asyncio.sleep(5)
        print(app.name)

    app.add_task(explicit_inject(app))
    ```

.. column::

    The `add_task` method returns the created `asyncio.Task` object, allowing you to await or check its result later.

    *Added in v25.12*

.. column::

    ```python
    task = app.add_task(some_coroutine())
    # Later...
    result = await task
    ```

## Adding tasks before `app.run`

It is possible to add background tasks before the App is run ie. before `app.run`. To add a task before the App is run, it is recommended to not pass the coroutine object (ie. one created by calling the `async` callable), but instead just pass the callable and Sanic will create the coroutine object on **each worker**. Note: the tasks that are added such are run as `before_server_start` jobs and thus run on every worker (and not in the main process). This has certain consequences, please read [this comment](https://github.com/sanic-org/sanic/issues/2139#issuecomment-868993668) on [this issue](https://github.com/sanic-org/sanic/issues/2139) for further details.

To add work on the main process, consider adding work to [`@app.main_process_start`](./listeners.md). Note: the workers won't start until this work is completed.

.. column::

    Example to add a task before `app.run`

.. column::

    ```python
    async def slow_work():
       ...
   
    async def even_slower(num):
       ...

    app = Sanic(...)
    app.add_task(slow_work) # Note: we are passing the callable and not coroutine object ...
    app.add_task(even_slower(10)) # ... or we can call the function and pass the coroutine.
    app.run(...)
    ```

## Named tasks

.. column::

    When creating a task, you can ask Sanic to keep track of it for you by providing a `name`.

.. column::

    ```python
    app.add_task(slow_work, name="slow_task")
    ```


.. column::

    You can now retrieve that task instance from anywhere in your application using `get_task`.

.. column::

    ```python
    task = app.get_task("slow_task")
    ```

.. column::

    If that task needs to be cancelled, you can do that with `cancel_task`. Make sure that you `await` it.

.. column::

    ```python
    await app.cancel_task("slow_task")
    ```

.. column::

    All registered tasks can be found in the `app.tasks` property. To prevent cancelled tasks from filling up, you may want to run `app.purge_tasks` that will clear out any completed or cancelled tasks.

.. column::

    ```python
    app.purge_tasks()
    ```

This pattern can be particularly useful with `websockets`:

```python
async def receiver(ws):
    while True:
        message = await ws.recv()
        if not message:
            break
        print(f"Received: {message}")

@app.websocket("/feed")
async def feed(request, ws):
    task_name = f"receiver:{request.id}"
    request.app.add_task(receiver(ws), name=task_name)
    try:
        while True:
            await request.app.event("my.custom.event")
            await ws.send("A message")
    finally:
        # When the websocket closes, let's cleanup the task
        await request.app.cancel_task(task_name)
        request.app.purge_tasks()
```

*Added in v21.12*

---

### Guide Content En Guide Best Practices Blueprints (`guide/content/en/guide/best-practices/blueprints.md`)

# Blueprints

## Overview

Blueprints are objects that can be used for sub-routing within an application. Instead of adding routes to the application instance, blueprints define similar methods for adding routes, which are then registered with the application in a flexible and pluggable manner.

Blueprints are especially useful for larger applications, where your application logic can be broken down into several groups or areas of responsibility.

## Creating and registering

.. column::

    First, you must create a blueprint. It has a very similar API as the `Sanic()` app instance with many of the same decorators.

.. column::

    ```python
    # ./my_blueprint.py
    from sanic.response import json
    from sanic import Blueprint

    bp = Blueprint("my_blueprint")

    @bp.route("/")
    async def bp_root(request):
        return json({"my": "blueprint"})
    ```



.. column::

    Next, you register it with the app instance.

.. column::

    ```python
    from sanic import Sanic
    from my_blueprint import bp

    app = Sanic(__name__)
    app.blueprint(bp)
    ```

Blueprints also have the same `websocket()` decorator and `add_websocket_route` method for implementing websockets.

.. column::

    Beginning in v21.12, a Blueprint may be registered before or after adding objects to it. Previously, only objects attached to the Blueprint at the time of registration would be loaded into application instance.

.. column::

    ```python
    app.blueprint(bp)

    @bp.route("/")
    async def bp_root(request):
        ...
    ```

## Copying

.. column::

    Blueprints along with everything that is attached to them can be copied to new instances using the `copy()` method. The only required argument is to pass it a new `name`. However, you could also use this to override any of the values from the old blueprint.

.. column::

    ```python
    v1 = Blueprint("Version1", version=1)

    @v1.route("/something")
    def something(request):
        pass

    v2 = v1.copy("Version2", version=2)

    app.blueprint(v1)
    app.blueprint(v2)
    ```

    ```
    Available routes:
    /v1/something
    /v2/something

    ```

*Added in v21.9*

## Blueprint groups

Blueprints may also be registered as part of a list or tuple, where the registrar will recursively cycle through any sub-sequences of blueprints and register them accordingly. The Blueprint.group method is provided to simplify this process, allowing a ‘mock’ backend directory structure mimicking what’s seen from the front end. Consider this (quite contrived) example:

```text
api/
├──content/
│ ├──authors.py
│ ├──static.py
│ └──__init__.py
├──info.py
└──__init__.py
app.py
```

.. column::

    #### First blueprint

.. column::

    ```python
    # api/content/authors.py
    from sanic import Blueprint

    authors = Blueprint("content_authors", url_prefix="/authors")
    ```


.. column::

    #### Second blueprint

.. column::

    ```python
    # api/content/static.py
    from sanic import Blueprint

    static = Blueprint("content_static", url_prefix="/static")
    ```


.. column::

    #### Blueprint group

.. column::

    ```python
    # api/content/__init__.py
    from sanic import Blueprint
    from .static import static
    from .authors import authors

    content = Blueprint.group(static, authors, url_prefix="/content")
    ```


.. column::

    #### Third blueprint

.. column::

    ```python
    # api/info.py
    from sanic import Blueprint

    info = Blueprint("info", url_prefix="/info")
    ```


.. column::

    #### Another blueprint group

.. column::

    ```python
    # api/__init__.py
    from sanic import Blueprint
    from .content import content
    from .info import info

    api = Blueprint.group(content, info, url_prefix="/api")
    ```


.. column::

    #### Main server

    All blueprints are now registered

.. column::

    ```python
    # app.py
    from sanic import Sanic
    from .api import api

    app = Sanic(__name__)
    app.blueprint(api)
    ```

### Blueprint group prefixes and composability

As shown in the code above, when you create a group of blueprints you can extend the URL prefix of all the blueprints in the group by passing the `url_prefix` argument to the `Blueprint.group` method. This is useful for creating a mock directory structure for your API.


In addition, there is a `name_prefix` argument that can be used to make blueprints reusable and composable. The is specifically necessary when applying a single blueprint to multiple groups. By doing this, the blueprint will be registered with a unique name for each group, which allows the blueprint to be registered multiple times and have its routes each properly named with a unique identifier.

.. column::

    Consider this example. The routes built will be named as follows:
    - `TestApp.group-a_bp1.route1`
    - `TestApp.group-a_bp2.route2`
    - `TestApp.group-b_bp1.route1`
    - `TestApp.group-b_bp2.route2`

.. column::

    ```python
    bp1 = Blueprint("bp1", url_prefix="/bp1")
    bp2 = Blueprint("bp2", url_prefix="/bp2")

    bp1.add_route(lambda _: ..., "/", name="route1")
    bp2.add_route(lambda _: ..., "/", name="route2")

    group_a = Blueprint.group(
        bp1, bp2, url_prefix="/group-a", name_prefix="group-a"
    )
    group_b = Blueprint.group(
        bp1, bp2, url_prefix="/group-b", name_prefix="group-b"
    )

    app = Sanic("TestApp")
    app.blueprint(group_a)
    app.blueprint(group_b)
    ```

*Name prefixing added in v23.6*


## Middleware

.. column::

    Blueprints can also have middleware that is specifically registered for its endpoints only.

.. column::

    ```python
    @bp.middleware
    async def print_on_request(request):
        print("I am a spy")

    @bp.middleware("request")
    async def halt_request(request):
        return text("I halted the request")

    @bp.middleware("response")
    async def halt_response(request, response):
        return text("I halted the response")
    ```


.. column::

    Similarly, using blueprint groups, it is possible to apply middleware to an entire group of nested blueprints.

.. column::

    ```python
    bp1 = Blueprint("bp1", url_prefix="/bp1")
    bp2 = Blueprint("bp2", url_prefix="/bp2")

    @bp1.middleware("request")
    async def bp1_only_middleware(request):
        print("applied on Blueprint : bp1 Only")

    @bp1.route("/")
    async def bp1_route(request):
        return text("bp1")

    @bp2.route("/<param>")
    async def bp2_route(request, param):
        return text(param)

    group = Blueprint.group(bp1, bp2)

    @group.middleware("request")
    async def group_middleware(request):
        print("common middleware applied for both bp1 and bp2")

    # Register Blueprint group under the app
    app.blueprint(group)
    ```

## Exceptions

.. column::

    Just like other [exception handling](./exceptions.md), you can define blueprint specific handlers.

.. column::

    ```python
    @bp.exception(NotFound)
    def ignore_404s(request, exception):
        return text("Yep, I totally found the page: {}".format(request.url))
    ```

## Static files

.. column::

    Blueprints can also have their own static handlers

.. column::

    ```python
    bp = Blueprint("bp", url_prefix="/bp")
    bp.static("/web/path", "/folder/to/serve")
    bp.static("/web/path", "/folder/to/server", name="uploads")
    ```


.. column::

    Which can then be retrieved using `url_for()`. See [routing](../basics/routing.md) for more information.

.. column::

    ```python
    >>> print(app.url_for("static", name="bp.uploads", filename="file.txt"))
    '/bp/web/path/file.txt'
    ```

## Listeners

.. column::

    Blueprints can also implement [listeners](../basics/listeners.md).

.. column::

    ```python
    @bp.listener("before_server_start")
    async def before_server_start(app, loop):
        ...

    @bp.listener("after_server_stop")
    async def after_server_stop(app, loop):
        ...
    ```

## Versioning

As discussed in the [versioning section](../advanced/versioning.md), blueprints can be used to implement different versions of a web API.

.. column::

    The `version` will be prepended to the routes as `/v1` or `/v2`, etc.

.. column::

    ```python
    auth1 = Blueprint("auth", url_prefix="/auth", version=1)
    auth2 = Blueprint("auth", url_prefix="/auth", version=2)
    ```


.. column::

    When we register our blueprints on the app, the routes `/v1/auth` and `/v2/auth` will now point to the individual blueprints, which allows the creation of sub-sites for each API version.

.. column::

    ```python
    from auth_blueprints import auth1, auth2

    app = Sanic(__name__)
    app.blueprint(auth1)
    app.blueprint(auth2)
    ```


.. column::

    It is also possible to group the blueprints under a `BlueprintGroup` entity and version multiple of them together at the
    same time.

.. column::

    ```python
    auth = Blueprint("auth", url_prefix="/auth")
    metrics = Blueprint("metrics", url_prefix="/metrics")

    group = Blueprint.group(auth, metrics, version="v1")

    # This will provide APIs prefixed with the following URL path
    # /v1/auth/ and /v1/metrics
    ```

## Composable

A `Blueprint` may be registered to multiple groups, and each of `BlueprintGroup` itself could be registered and nested further. This creates a limitless possibility `Blueprint` composition.

*Added in v21.6*

.. column::

    Take a look at this example and see how the two handlers are actually mounted as five (5) distinct routes.

.. column::

    ```python
    app = Sanic(__name__)
    blueprint_1 = Blueprint("blueprint_1", url_prefix="/bp1")
    blueprint_2 = Blueprint("blueprint_2", url_prefix="/bp2")
    group = Blueprint.group(
        blueprint_1,
        blueprint_2,
        version=1,
        version_prefix="/api/v",
        url_prefix="/grouped",
        strict_slashes=True,
    )
    primary = Blueprint.group(group, url_prefix="/primary")

    @blueprint_1.route("/")
    def blueprint_1_default_route(request):
        return text("BP1_OK")

    @blueprint_2.route("/")
    def blueprint_2_default_route(request):
        return text("BP2_OK")

    app.blueprint(group)
    app.blueprint(primary)
    app.blueprint(blueprint_1)

    # The mounted paths:
    # /api/v1/grouped/bp1/
    # /api/v1/grouped/bp2/
    # /api/v1/primary/grouped/bp1
    # /api/v1/primary/grouped/bp2
    # /bp1

    ```


## Generating a URL

When generating a url with `url_for()`, the endpoint name will be in the form:

```text
{blueprint_name}.{handler_name}
```

---

### Guide Content En Guide Best Practices Decorators (`guide/content/en/guide/best-practices/decorators.md`)

# Decorators

One of the best ways to create a consistent and DRY web API is to make use of decorators to remove functionality from the handlers, and make it repeatable across your views.

.. column::

    Therefore, it is very common to see a Sanic view handler with several decorators on it.

.. column::

    ```python
    @app.get("/orders")
    @authorized("view_order")
    @validate_list_params()
    @inject_user()
    async def get_order_details(request, params, user):
        ...
    ```


## Example

Here is a starter template to help you create decorators.

In this example, let’s say you want to check that a user is authorized to access a particular endpoint. You can create a decorator that wraps a handler function, checks a request if the client is authorized to access a resource, and sends the appropriate response.
```python
from functools import wraps
from sanic.response import json

def authorized():
    def decorator(f):
        @wraps(f)
        async def decorated_function(request, *args, **kwargs):
            # run some method that checks the request
            # for the client's authorization status
            is_authorized = await check_request_for_authorization_status(request)

            if is_authorized:
                # the user is authorized.
                # run the handler method and return the response
                response = await f(request, *args, **kwargs)
                return response
            else:
                # the user is not authorized.
                return json({"status": "not_authorized"}, 403)
        return decorated_function
    return decorator

@app.route("/")
@authorized()
async def test(request):
    return json({"status": "authorized"})
```

## Templates

Decorators are **fundamental** to building applications with Sanic. They increase the portability and maintainablity of your code. 

In paraphrasing the Zen of Python: "[decorators] are one honking great idea -- let's do more of those!"

To make it easier to implement them, here are three examples of copy/pastable code to get you started.

.. column::

    Don't forget to add these import statements. Although it is *not* necessary, using `@wraps` helps keep some of the metadata of your function intact. [See docs](https://docs.python.org/3/library/functools.html#functools.wraps). Also, we use the `isawaitable` pattern here to allow the route handlers to by regular or asynchronous functions.

.. column::

    ```python
    from inspect import isawaitable
    from functools import wraps
    ```

### With args

.. column::

    Often, you will want a decorator that will *always* need arguments. Therefore, when it is implemented you will always be calling it.

    ```python
    @app.get("/")
    @foobar(1, 2)
    async def handler(request: Request):
        return text("hi")
    ```

.. column::

    ```python
    def foobar(arg1, arg2):
        def decorator(f):
            @wraps(f)
            async def decorated_function(request, *args, **kwargs):

                response = f(request, *args, **kwargs)
                if isawaitable(response):
                    response = await response

                return response

            return decorated_function

        return decorator
    ```

### Without args

.. column::

    Sometimes you want a decorator that will not take arguments. When this is the case, it is a nice convenience not to have to call it

    ```python
    @app.get("/")
    @foobar
    async def handler(request: Request):
        return text("hi")
    ```

.. column::

    ```python
    def foobar(func):
        def decorator(f):
            @wraps(f)
            async def decorated_function(request, *args, **kwargs):

                response = f(request, *args, **kwargs)
                if isawaitable(response):
                    response = await response

                return response

            return decorated_function

        return decorator(func)
    ```

### With or Without args

.. column::

    If you want a decorator with the ability to be called or not, you can follow this pattern. Using keyword only arguments is not necessary, but might make implementation simpler.

    ```python
    @app.get("/")
    @foobar(arg1=1, arg2=2)
    async def handler(request: Request):
        return text("hi")
    ```

    ```python
    @app.get("/")
    @foobar
    async def handler(request: Request):
        return text("hi")
    ```

.. column::

    ```python
    def foobar(maybe_func=None, *, arg1=None, arg2=None):
        def decorator(f):
            @wraps(f)
            async def decorated_function(request, *args, **kwargs):

                response = f(request, *args, **kwargs)
                if isawaitable(response):
                    response = await response

                return response

            return decorated_function

        return decorator(maybe_func) if maybe_func else decorator
    ```

---

### Guide Content En Guide Best Practices Exceptions (`guide/content/en/guide/best-practices/exceptions.md`)

# Exceptions

## Using Sanic exceptions

Sometimes you just need to tell Sanic to halt execution of a handler and send back a status code response. You can raise a `SanicException` for this and Sanic will do the rest for you.

You can pass an optional `status_code` argument. By default, a SanicException will return an internal server error 500 response.

```python
from sanic.exceptions import SanicException

@app.route("/youshallnotpass")
async def no_no(request):
        raise SanicException("Something went wrong.", status_code=501)
```

Sanic provides a number of standard exceptions. They each automatically will raise the appropriate HTTP status code in your response. [Check the API reference](https://sanic.readthedocs.io/en/latest/sanic/api_reference.html#module-sanic.exceptions) for more details. 

.. column::

    The more common exceptions you _should_ implement yourself include:

    - `BadRequest` (400)
    - `Unauthorized` (401)
    - `Forbidden` (403)
    - `NotFound` (404)
    - `ServerError` (500)

.. column::

    ```python
    from sanic import exceptions

    @app.route("/login")
    async def login(request):
        user = await some_login_func(request)
        if not user:
            raise exceptions.NotFound(
                f"Could not find user with username={request.json.username}"
            )
    ```

## Exception properties

All exceptions in Sanic derive from `SanicException`. That class has a few properties on it that assist the developer in consistently reporting their exceptions across an application.

- `message`
- `status_code`
- `quiet`
- `headers`
- `context`
- `extra`

All of these properties can be passed to the exception when it is created, but the first three can also be used as class variables as we will see.

.. column::

    ### `message`

    The `message` property obviously controls the message that will be displayed as with any other exception in Python. What is particularly useful is that you can set the `message` property on the class definition allowing for easy standardization of language across an application

.. column::

    ```python
    class CustomError(SanicException):
        message = "Something bad happened"

    raise CustomError
    # or
    raise CustomError("Override the default message with something else")
    ```


.. column::

    ### `status_code`

    This property is used to set the response code when the exception is raised. This can particularly be useful when creating custom 400 series exceptions that are usually in response to bad information coming from the client.

.. column::

    ```python
    class TeapotError(SanicException):
        status_code = 418
        message = "Sorry, I cannot brew coffee"

    raise TeapotError
    # or
    raise TeapotError(status_code=400)
    ```


.. column::

    ### `quiet`

    By default, exceptions will be output by Sanic to the `error_logger`. Sometimes this may not be desirable, especially if you are using exceptions to trigger events in exception handlers (see [the following section](./exceptions.md#handling)). You can suppress the log output using `quiet=True`.

.. column::

    ```python
    class SilentError(SanicException):
        message = "Something happened, but not shown in logs"
        quiet = True

    raise SilentError
    # or
    raise InvalidUsage("blah blah", quiet=True)
    ```


.. column::

    Sometimes while debugging you may want to globally ignore the `quiet=True` property. You can force Sanic to log out all exceptions regardless of this property using `NOISY_EXCEPTIONS`

    *Added in v21.12*

.. column::

    ```python
    app.config.NOISY_EXCEPTIONS = True
    ```


.. column::

    ### `headers`

    Using `SanicException` as a tool for creating responses is super powerful. This is in part because not only can you control the `status_code`, but you can also control reponse headers directly from the exception.

.. column::

    ```python
    class MyException(SanicException):
        headers = {
          "X-Foo": "bar"
        }

    raise MyException
    # or
    raise InvalidUsage("blah blah", headers={
        "X-Foo": "bar"
    })
    ```


.. column::

    ### `extra`

    See [contextual exceptions](./exceptions.md#contextual-exceptions)

    *Added in v21.12*

.. column::

    ```python
    raise SanicException(..., extra={"name": "Adam"})
    ```


.. column::

    ### `context`

    See [contextual exceptions](./exceptions.md#contextual-exceptions)

    *Added in v21.12*

.. column::

    ```python
    raise SanicException(..., context={"foo": "bar"})
    ```


## Handling

Sanic handles exceptions automatically by rendering an error page, so in many cases you don't need to handle them yourself. However, if you would like more control on what to do when an exception is raised, you can implement a handler yourself.

Sanic provides a decorator for this, which applies to not only the Sanic standard exceptions, but **any** exception that your application might throw.

.. column::

    The easiest method to add a handler is to use `@app.exception()` and pass it one or more exceptions.

.. column::

    ```python
    from sanic.exceptions import NotFound

    @app.exception(NotFound, SomeCustomException)
    async def ignore_404s(request, exception):
        return text("Yep, I totally found the page: {}".format(request.url))
    ```


.. column::

    You can also create a catchall handler by catching `Exception`.

.. column::

    ```python
    @app.exception(Exception)
    async def catch_anything(request, exception):
        ...
    ```


.. column::

    You can also use `app.error_handler.add()` to add error handlers.

.. column::

    ```python
    async def server_error_handler(request, exception):
        return text("Oops, server error", status=500)

    app.error_handler.add(Exception, server_error_handler)
    ```

## Built-in error handling

Sanic ships with three formats for exceptions: HTML, JSON, and text. You can see examples of them below in the [Fallback handler](#fallback-handler) section.

.. column::

    You can control _per route_ which format to use with the `error_format` keyword argument.

    *Added in v21.9*

.. column::

    ```python
    @app.request("/", error_format="text")
    async def handler(request):
        ...
    ```


## Custom error handling

In some cases, you might want to add some more error handling functionality to what is provided by default. In that case, you can subclass Sanic's default error handler as such:

```python
from sanic.handlers import ErrorHandler

class CustomErrorHandler(ErrorHandler):
    def default(self, request: Request, exception: Exception) -> HTTPResponse:
        ''' handles errors that have no error handlers assigned '''
        # You custom error handling logic...
        status_code = getattr(exception, "status_code", 500)
        return json({
          "error": str(exception),
          "foo": "bar"
        }, status=status_code)

app.error_handler = CustomErrorHandler()
```

## Fallback handler

Sanic comes with three fallback exception handlers:

1. HTML
2. Text
3. JSON

These handlers present differing levels of detail depending upon whether your application is in [debug mode](../running/development.md) or not.

By default, Sanic will be in "auto" mode, which means that it will using the incoming request and potential matching handler to choose the appropriate response format. For example, when in a browser it should always provide an HTML error page. When using curl, you might see JSON or plain text.

### HTML

```python
app.config.FALLBACK_ERROR_FORMAT = "html"
```

.. column::

    ```python
    app.config.DEBUG = True
    ```

    

.. column::

    ```python
    app.config.DEBUG = False
    ```

    

### Text

```python
app.config.FALLBACK_ERROR_FORMAT = "text"
```

.. column::

    ```python
    app.config.DEBUG = True
    ```

    ```sh
    curl localhost:8000/exc -i
    HTTP/1.1 500 Internal Server Error
    content-length: 620
    connection: keep-alive
    content-type: text/plain; charset=utf-8

    ⚠️ 500 — Internal Server Error
    ==============================
    That time when that thing broke that other thing? That happened.

    ServerError: That time when that thing broke that other thing? That happened. while handling path /exc
    Traceback of TestApp (most recent call last):

      ServerError: That time when that thing broke that other thing? That happened.
        File /path/to/sanic/app.py, line 979, in handle_request
        response = await response

        File /path/to/server.py, line 16, in handler
        do_something(cause_error=True)

        File /path/to/something.py, line 9, in do_something
        raise ServerError(
    ```

.. column::

    ```python
    app.config.DEBUG = False
    ```

    ```sh
    curl localhost:8000/exc -i
    HTTP/1.1 500 Internal Server Error
    content-length: 134
    connection: keep-alive
    content-type: text/plain; charset=utf-8

    ⚠️ 500 — Internal Server Error
    ==============================
    That time when that thing broke that other thing? That happened.
    ```

### JSON

```python
app.config.FALLBACK_ERROR_FORMAT = "json"
```

.. column::

    ```python
    app.config.DEBUG = True
    ```

    ```sh
    curl localhost:8000/exc -i
    HTTP/1.1 500 Internal Server Error
    content-length: 572
    connection: keep-alive
    content-type: application/jso

    {
      "description": "Internal Server Error",
      "status": 500,
      "message": "That time when that thing broke that other thing? That happened.",
      "path": "/exc",
      "args": {},
      "exceptions": [
        {
          "type": "ServerError",
          "exception": "That time when that thing broke that other thing? That happened.",
          "frames": [
            {
              "file": "/path/to/sanic/app.py",
              "line": 979,
              "name": "handle_request",
              "src": "response = await response"
            },
            {
              "file": "/path/to/server.py",
              "line": 16,
              "name": "handler",
              "src": "do_something(cause_error=True)"
            },
            {
              "file": "/path/to/something.py",
              "line": 9,
              "name": "do_something",
              "src": "raise ServerError("
            }
          ]
        }
      ]
    }
    ```

.. column::

    ```python
    app.config.DEBUG = False
    ```

    ```sh
    curl localhost:8000/exc -i
    HTTP/1.1 500 Internal Server Error
    content-length: 129
    connection: keep-alive
    content-type: application/json

    {
      "description": "Internal Server Error",
      "status": 500,
      "message": "That time when that thing broke that other thing? That happened."
    }

    ```

### Auto

Sanic also provides an option for guessing which fallback option to use.

```python
app.config.FALLBACK_ERROR_FORMAT = "auto"
```
## Contextual Exceptions

Default exception messages that simplify the ability to consistently raise exceptions throughout your application.

```python
class TeapotError(SanicException):
    status_code = 418
    message = "Sorry, I cannot brew coffee"

raise TeapotError
```

But this lacks two things:

1. A dynamic and predictable message format
2. The ability to add additional context to an error message (more on this in a moment)

*Added in v21.12*

Using one of Sanic's exceptions, you have two options to provide additional details at runtime:

```python
raise TeapotError(extra={"foo": "bar"}, context={"foo": "bar"})
```

What's the difference and when should you decide to use each?

- `extra` - The object itself will **never** be sent to a production client. It is meant for internal use only. What could it be used for?
  - Generating (as we will see in a minute) a dynamic error message
  - Providing runtime details to a logger
  - Debug information (when in development mode, it is rendered)
- `context` - This object is **always** sent to production clients. It is generally meant to be used to send additional details about the context of what happened. What could it be used for?
  - Providing alternative values on a `BadRequest` validation issue
  - Responding with helpful details for your customers to open a support ticket
  - Displaying state information like current logged in user info

### Dynamic and predictable message using `extra`

Sanic exceptions can be raised using `extra` keyword arguments to provide additional information to a raised exception instance.

```python
class TeapotError(SanicException):
    status_code = 418

    @property
    def message(self):
        return f"Sorry {self.extra['name']}, I cannot make you coffee"

raise TeapotError(extra={"name": "Adam"})
```

The new feature allows the passing of `extra` meta to the exception instance, which can be particularly useful as in the above example to pass dynamic data into the message text. This `extra` info object **will be suppressed** when in `PRODUCTION` mode, but displayed in `DEVELOPMENT` mode.

.. column::

    **DEVELOPMENT**

    

.. column::

    **PRODUCTION**

    

### Additional `context` to an error message

Sanic exceptions can also be raised with a `context` argument to pass intended information along to the user about what happened. This is particularly useful when creating microservices or an API intended to pass error messages in JSON format. In this use case, we want to have some context around the exception beyond just a parseable error message to return details to the client.

```python
raise TeapotError(context={"foo": "bar"})
```

This is information **that we want** to always be passed in the error (when it is available). Here is what it should look like:

.. column::

    **PRODUCTION**

    ```json
    {
      "description": "I'm a teapot",
      "status": 418,
      "message": "Sorry Adam, I cannot make you coffee",
      "context": {
        "foo": "bar"
      }
    }
    ```

.. column::

    **DEVELOPMENT**

    ```json
    {
      "description": "I'm a teapot",
      "status": 418,
      "message": "Sorry Adam, I cannot make you coffee",
      "context": {
        "foo": "bar"
      },
      "path": "/",
      "args": {},
      "exceptions": [
        {
          "type": "TeapotError",
          "exception": "Sorry Adam, I cannot make you coffee",
          "frames": [
            {
              "file": "handle_request",
              "line": 83,
              "name": "handle_request",
              "src": ""
            },
            {
              "file": "/tmp/p.py",
              "line": 17,
              "name": "handler",
              "src": "raise TeapotError("
            }
          ]
        }
      ]
    }
    ```



## Error reporting

Sanic has a [signal](../advanced/signals.md#built-in-signals) that allows you to hook into the exception reporting process. This is useful if you want to send exception information to a third party service like Sentry or Rollbar. This can be conveniently accomplished by attaching an error reporting handler as show below:

```python
@app.report_exception
async def catch_any_exception(app: Sanic, exception: Exception):
print("Caught exception:", exception)
```

.. note::

    This handler will be dispatched into a background task and **IS NOT** intended for use to manipulate any response data. It is intended to be used for logging or reporting purposes only, and should not impact the ability of your application to return the error response to the client.

*Added in v23.6*

---

### Guide Content En Guide Best Practices Logging (`guide/content/en/guide/best-practices/logging.md`)

# Logging

Sanic allows you to do different types of logging (access log, error log) on the requests based on the [Python logging API](https://docs.python.org/3/howto/logging.html). You should have some basic knowledge on Python logging if you want to create a new configuration.

But, don't worry, out of the box Sanic ships with some sensible logging defaults. Out of the box it uses an `AutoFormatter` that will format the logs depending upon whether you are in debug mode or not. We will show you how to force this later on.

## Quick Start

Let's start by looking at what logging might look like in local development. For this, we will use the default logging configuration that Sanic provides and make sure to run Sanic in development mode.

.. column::

    A simple example using default settings would be like this:

.. column::

    ```python
    from sanic import Sanic
    from sanic.log import logger
    from sanic.response import text

    app = Sanic('logging_example')

    @app.route('/')
    async def test(request):
        logger.info('Here is your log')
        return text('Hello World!')
    ```

.. column::

    Because we are specifically trying to look at the development logs, we will make sure to run Sanic in development mode.

.. column::

    ```sh
    sanic path.to.server:app --dev
    ```    
    

After the server is running, you should see logs like this.



You can send a request to server and it will print the log messages.



Some important points to note:

- The default log level in **production** mode is `INFO`.
- The default log level in **debug** mode is `DEBUG`.
- When in **debug** mode, the log messages will not have a timestamp (except on access logs).
- Sanic will try to colorize the logs if the terminal supports it. If you are running in Docker with docker-compose, you may need to set `tty: true` in your `docker-compose.yml` file to see the colors.

## Sanic's loggers

Out of the box, Sanic ships with five loggers:

| **Logger Name**   | **Use Case**                  |
|-------------------|-------------------------------|
| `sanic.root`      | Used to log internal messages. |
| `sanic.error`     | Used to log error logs.       |
| `sanic.access`    | Used to log access logs.      |
| `sanic.server`    | Used to log server logs.      |
| `sanic.websockets`| Used to log websocket logs.   |

.. column::

    If you want to use these loggers yourself, you can import them from `sanic.log`.
    
.. column::

    ```python
    from sanic.log import logger, error_logger, access_logger, server_logger, websockets_logger
    
    logger.info('This is a root logger message')
    ```
    
.. warning::

    Feel free to use the root logger and the error logger yourself. But, you probably don't want to use the access logger, server logger, or websockets logger directly. These are used internally by Sanic and are configured to log in a specific way. If you want to change the way these loggers log, you should change the logging configuration.
    
## Default logging configuration

Sanic ships with a default logging configuration that is used when you do not provide your own. This configuration is stored in `sanic.log.LOGGING_CONFIG_DEFAULTS`.

```
/* Detailed source-code truncated for AI context efficiency. */
```

## Changing Sanic loggers

.. column::

    To use your own logging config, simply use `logging.config.dictConfig`, or pass `log_config` when you initialize Sanic app.

.. column::

    ```python
    app = Sanic('logging_example', log_config=LOGGING_CONFIG)

    if __name__ == "__main__":
        app.run(access_log=False)
    ```

.. column::

    But, what if you do not want to control the logging completely, just change the formatter for example? Here, we will import the default logging config and modify only the parts that we want to force (for example) to use the `ProdFormatter` all of the time.
    
.. column::

    ```python
    from sanic.log import LOGGING_CONFIG_DEFAULTS
    
    LOGGING_CONFIG_DEFAULTS['formatters']['generic']['class'] = 'sanic.logging.formatter.ProdFormatter'
    LOGGING_CONFIG_DEFAULTS['formatters']['access']['class'] = 'sanic.logging.formatter.ProdAccessFormatter'
    
    app = Sanic('logging_example', log_config=LOGGING_CONFIG_DEFAULTS)
    ```


.. tip:: FYI

    Logging in Python is a relatively cheap operation. However, if you are serving a high number of requests and performance is a concern, all of that time logging out access logs adds up and becomes quite expensive.  

    This is a good opportunity to place Sanic behind a proxy (like nginx) and to do your access logging there. You will see a *significant* increase in overall performance by disabling the `access_log`.  

    For optimal production performance, it is advised to run Sanic with `debug` and `access_log` disabled: `app.run(debug=False, access_log=False)`


## Access logger additional parameters

Sanic provides additional parameters to the access logger.

| Log Context Parameter | Parameter Value                       | Datatype |
|-----------------------|---------------------------------------|----------|
| `host`                | `request.ip`                          | `str`    |
| `request`             | `request.method + " " + request.url`  | `str`    |
| `status`              | `response`                            | `int`    |
| `byte`                | `len(response.body)`                  | `int`    |
| `duration`            | <calculated>                          | `float`  |

## Legacy logging

Many logging changes were introduced in Sanic 24.3. The main changes were related to logging formats. If you prefer the legacy logging format, you can use the `sanic.logging.formatter.LegacyFormatter` and `sanic.logging.formatter.LegacyAccessFormatter` formatters.

---

### Guide Content En Guide Best Practices Testing (`guide/content/en/guide/best-practices/testing.md`)

# Testing

See [sanic-testing](../../plugins/sanic-testing/getting-started.md)

---

### Guide Content En Guide Deployment Caddy (`guide/content/en/guide/deployment/caddy.md`)

# Caddy Deployment

## Introduction

Caddy is a state-of-the-art web server and proxy that supports up to HTTP/3. Its simplicity lies in its minimalistic configuration and the inbuilt ability to automatically procure TLS certificates for your domains from Let's Encrypt. In this setup, we will configure the Sanic application to serve locally at 127.0.0.1:8001, with Caddy playing the role of the public-facing server for the domain example.com.

You may install Caddy from your favorite package menager on Windows, Linux and Mac. The package is named `caddy`.

## Proxied Sanic app

```python
from sanic import Sanic
from sanic.response import text

app = Sanic("proxied_example")

@app.get("/")
def index(request):
    # This should display external (public) addresses:
    return text(
        f"{request.remote_addr} connected to {request.url_for('index')}\n"
        f"Forwarded: {request.forwarded}\n"
    )
```

To run this application, save as `proxied_example.py`, and use the sanic command-line interface as follows:

```bash
SANIC_PROXIES_COUNT=1 sanic proxied_example --port 8001
```

Setting the SANIC_PROXIES_COUNT environment variable instructs Sanic to trust the X-Forwarded-* headers sent by Caddy, allowing it to correctly identify the client's IP address and other information.

## Caddy is simple

If you have no other web servers running, you can simply run Caddy CLI (needs `sudo` on Linux):

```bash
caddy reverse-proxy --from example.com --to :8001
```

This is a complete server that includes a certificate for your domain, http-to-https redirect, proxy headers, streaming and WebSockets. Your Sanic application should now be available on the domain you specified by HTTP versions 1, 2 and 3. Remember to open up UDP/443 on your firewall to enable H3 communications.

All done?

Soon enough you'll be needing more than one server, or more control over details, which is where the configuration files come in. The above command is equivalent to this `Caddyfile`, serving as a good starting point for your install:

```
example.com {
    reverse_proxy localhost:8001
}
```

Some Linux distributions install Caddy such that it reads configuration from `/etc/caddy/Caddyfile`, which `import /etc/caddy/conf.d/*` for each site you are running. If not, you'll need to manually run `caddy run` as a system service, pointing it at the proper config file. Alternatively, use Caddy API mode with `caddy run --resume` for persistent config changes. Note that any Caddyfile loading will replace all prior configuration and thus `caddy-api` is not configurable in this traditional manner.

## Advanced configuration

At times, you might need to mix static files and handlers at the site root for cleaner URLs. In Sanic, you'd use `app.static("/", "static", index="index.html")` to achieve this. However, for improved performance, you can offload serving static files to Caddy:

```
app.example.com {
    # Look for static files first, proxy to Sanic if not found
    route {
        file_server {
            root /srv/sanicexample/static
            precompress br                     # brotli your large scripts and styles
            pass_thru
        }
        reverse_proxy unix//tmp/sanic.socket   # sanic --unix /tmp/sanic.socket
    }
}
```

Please refer to [Caddy documentation](https://caddyserver.com/docs/) for more options.

---

### Guide Content En Guide Deployment Docker (`guide/content/en/guide/deployment/docker.md`)

# Docker Deployment

## Introduction

For a long time, the environment has always been a difficult problem for deployment. If there are conflicting configurations in your project, you have to spend a lot of time resolving them. Fortunately, virtualization provides us with a good solution. Docker is one of them. If you don't know Docker, you can visit [Docker official website](https://www.docker.com/) to learn more.

## Build Image

Let's start with a simple project. We will use a Sanic project as an example. Assume the project path is `/path/to/SanicDocker`.

.. column::

    The directory structure looks like this:

.. column::

    ```text
    # /path/to/SanicDocker
    SanicDocker
    ├── requirements.txt
    ├── dockerfile
    └── server.py
    ```


.. column::

    And the `server.py` code looks like this:

.. column::

    ```python
    app = Sanic("MySanicApp")

    @app.get('/')
    async def hello(request):
        return text("OK!")

    if __name__ == '__main__':
        app.run(host='0.0.0.0', port=8000)
    ```



.. note:: 

    Please note that the host cannot be 127.0.0.1 . In docker container, 127.0.0.1 is the default network interface of the container, only the container can communicate with other containers. more information please visit [Docker network](https://docs.docker.com/engine/reference/commandline/network/)



Code is ready, let's write the `Dockerfile`:

```Dockerfile

FROM sanicframework/sanic:3.8-latest

WORKDIR /sanic

COPY . .

RUN pip install -r requirements.txt

EXPOSE 8000

CMD ["python", "server.py"]
```

Run the following command to build the image:

```shell
docker build -t my-sanic-image .
```

## Start Container

.. column::

    After the image built, we can start the container use `my-sanic-image`:

.. column::

    ```shell
    docker run --name mysanic -p 8000:8000 -d my-sanic-image
    ```


.. column::

    Now we can visit `http://localhost:8000` to see the result:

.. column::

    ```text
    OK!
    ```

## Use docker-compose

If your project consist of multiple services, you can use [docker-compose](https://docs.docker.com/compose/) to manage them.

for example, we will deploy `my-sanic-image` and `nginx`, achieve through nginx access sanic server.

.. column::

    First of all, we need prepare nginx configuration file. create a file named `mysanic.conf`:

.. column::

    ```nginx
    server {
        listen 80;
        listen [::]:80;
        location / {
          proxy_pass http://mysanic:8000/;
          proxy_set_header Upgrade $http_upgrade;
          proxy_set_header Connection upgrade;
          proxy_set_header Accept-Encoding gzip;
        }
    }
    ```


.. column::

    Then, we need to prepare `docker-compose.yml` file. The content follows:

.. column::

    ```yaml
    version: "3"

    services:
      mysanic:
        image: my-sanic-image
        ports:
          - "8000:8000"
        restart: always

      mynginx:
        image: nginx:1.13.6-alpine
        ports:
          - "80:80"
        depends_on:
          - mysanic
        volumes:
          - ./mysanic.conf:/etc/nginx/conf.d/mysanic.conf
        restart: always

    networks:
      default:
        driver: bridge
    ```


.. column::

    After that, we can start them:

.. column::

    ```shell
    docker-compose up -d
    ```


.. column::

    Now, we can visit `http://localhost:80` to see the result:

.. column::

    ```text
    OK!
    ```

---

### Guide Content En Guide Deployment Nginx (`guide/content/en/guide/deployment/nginx.md`)

# Nginx Deployment

## Introduction

Although Sanic can be run directly on Internet, it may be useful to use a proxy
server such as Nginx in front of it. This is particularly useful for running
multiple virtual hosts on the same IP, serving NodeJS or other services beside
a single Sanic app, and it also allows for efficient serving of static files.
TLS and HTTP/2 are also easily implemented on such proxy.

We are setting the Sanic app to serve only locally at 127.0.0.1:8001, while the
Nginx installation is responsible for providing the service to public Internet
on domain example.com. Static files will be served by Nginx for maximal
performance.

## Proxied Sanic app

```python
from sanic import Sanic
from sanic.response import text

app = Sanic("proxied_example")

@app.get("/")
def index(request):
    # This should display external (public) addresses:
    return text(
        f"{request.remote_addr} connected to {request.url_for('index')}\n"
        f"Forwarded: {request.forwarded}\n"
    )
```

Since this is going to be a system service, save your code to
`/srv/sanicservice/proxied_example.py`.

For testing, run your app in a terminal using the `sanic` CLI in the folder where you saved the file.

```bash
SANIC_FORWARDED_SECRET=_hostname sanic proxied_example --port 8001
```

We provide Sanic config `FORWARDED_SECRET` to identify which proxy it gets
the remote addresses from. Note the `_` in front of the local hostname.
This gives basic protection against users spoofing these headers and faking
their IP addresses and more.

## SSL certificates

Install Certbot and obtain a certicate for all your domains. This will spin up its own webserver on port 80 for a moment to verify you control the given domain names.

```bash
certbot -d example.com -d www.example.com
```

## Nginx configuration

Quite much configuration is required to allow fast transparent proxying, but
for the most part these don't need to be modified, so bear with me.


.. tip:: Note

    Separate upstream section, rather than simply adding the IP after `proxy_pass`
    as in most tutorials, is needed for HTTP keep-alive. We also enable streaming,
    WebSockets and Nginx serving static files.


The following config goes inside the `http` section of `nginx.conf` or if your
system uses multiple config files, `/etc/nginx/sites-available/default` or
your own files (be sure to symlink them to `sites-enabled`):

```
/* Detailed source-code truncated for AI context efficiency. */
```

Start or restart Nginx for changes to take effect. E.g.

```bash
systemctl restart nginx
```

You should be able to connect your app on `https://example.com`. Any 404
errors and such will be handled by Sanic's error pages, and whenever a static
file is present at a given path, it will be served by Nginx.

## Running as a service

This part is for Linux distributions based on `systemd`. Create a unit file
`/etc/systemd/system/sanicexample.service`

```
[Unit]
Description=Sanic Example

[Service]
DynamicUser=Yes
WorkingDirectory=/srv/sanicservice
Environment=SANIC_PROXY_SECRET=_hostname
ExecStart=sanic proxied_example --port 8001 --fast
Restart=always

[Install]
WantedBy=multi-user.target
```

Then reload service files, start your service and enable it on boot:

```bash
systemctl daemon-reload
systemctl start sanicexample
systemctl enable sanicexample
```


.. tip:: Note

    For brevity we skipped setting up a separate user account and a Python virtual environment or installing your app as a Python module. There are good tutorials on those topics elsewhere that easily apply to Sanic as well. The DynamicUser setting creates a strong sandbox which basically means your application cannot store its data in files, so you may consider setting `User=sanicexample` instead if you need that.

---

### Guide Content En Guide How To Authentication (`guide/content/en/guide/how-to/authentication.md`)

# Authentication

> How do I control authentication and authorization?

This is an _extremely_ complicated subject to cram into a few snippets. But, this should provide you with an idea on ways to tackle this problem. This example uses [JWTs](https://jwt.io/), but the concepts should be equally applicable to sessions or some other scheme.

## `server.py`

```python
from sanic import Sanic, text

from auth import protected
from login import login

app = Sanic("AuthApp")
app.config.SECRET = "KEEP_IT_SECRET_KEEP_IT_SAFE"
app.blueprint(login)

@app.get("/secret")
@protected
async def secret(request):
    return text("To go fast, you must be fast.")
```

## `login.py`

```python
import jwt
from sanic import Blueprint, text

login = Blueprint("login", url_prefix="/login")

@login.post("/")
async def do_login(request):
    token = jwt.encode({}, request.app.config.SECRET)
    return text(token)
```



## `auth.py`

```python
from functools import wraps

import jwt
from sanic import text

def check_token(request):
    if not request.token:
        return False

    try:
        jwt.decode(
            request.token, request.app.config.SECRET, algorithms=["HS256"]
        )
    except jwt.exceptions.InvalidTokenError:
        return False
    else:
        return True

def protected(wrapped):
    def decorator(f):
        @wraps(f)
        async def decorated_function(request, *args, **kwargs):
            is_authenticated = check_token(request)

            if is_authenticated:
                response = await f(request, *args, **kwargs)
                return response
            else:
                return text("You are unauthorized.", 401)

        return decorated_function

    return decorator(wrapped)
```
This decorator pattern is taken from the [decorators page](../best-practices/decorators.md).

---

```bash
$ curl localhost:9999/secret -i
HTTP/1.1 401 Unauthorized
content-length: 21
connection: keep-alive
content-type: text/plain; charset=utf-8

You are unauthorized.


$ curl localhost:9999/login -X POST
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.e30.rjxS7ztIGt5tpiRWS8BGLUqjQFca4QOetHcZTi061DE


$ curl localhost:9999/secret -i -H "Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.e30.rjxS7ztIGt5tpiRWS8BGLUqjQFca4QOetHcZTi061DE"
HTTP/1.1 200 OK
content-length: 29
connection: keep-alive
content-type: text/plain; charset=utf-8

To go fast, you must be fast.


$ curl localhost:9999/secret -i -H "Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.e30.BAD"                                        
HTTP/1.1 401 Unauthorized
content-length: 21
connection: keep-alive
content-type: text/plain; charset=utf-8

You are unauthorized.
```

Also, checkout some resources from the community:

- Awesome Sanic - [Authorization](https://github.com/mekicha/awesome-sanic/blob/master/README.md#authentication) & [Session](https://github.com/mekicha/awesome-sanic/blob/master/README.md#session)
- [EuroPython 2020 - Overcoming access control in web APIs](https://www.youtube.com/watch?v=Uqgoj43ky6A)

---

### Guide Content En Guide How To Autodiscovery (`guide/content/en/guide/how-to/autodiscovery.md`)

---
title: Autodiscovery
---

# Autodiscovery of Blueprints, Middleware, and Listeners

> How do I autodiscover the components I am using to build my application?

One of the first problems someone faces when building an application, is *how* to structure the project. Sanic makes heavy use of decorators to register route handlers, middleware, and listeners. And, after creating blueprints, they need to be mounted to the application.

A possible solution is a single file in which **everything** is imported and applied to the Sanic instance. Another is passing around the Sanic instance as a global variable. Both of these solutions have their drawbacks.

An alternative is autodiscovery. You point your application at modules (already imported, or strings), and let it wire everything up.

## `server.py`

```python
from sanic import Sanic
from sanic.response import empty

import blueprints
from utility import autodiscover

app = Sanic("auto", register=True)
autodiscover(
    app,
    blueprints,
    "parent.child",
    "listeners.something",
    recursive=True,
)

app.route("/")(lambda _: empty())
```
```bash
[2021-03-02 21:37:02 +0200] [880451] [INFO] Goin' Fast @ http://127.0.0.1:9999
[2021-03-02 21:37:02 +0200] [880451] [DEBUG] something
[2021-03-02 21:37:02 +0200] [880451] [DEBUG] something @ nested
[2021-03-02 21:37:02 +0200] [880451] [DEBUG] something @ level1
[2021-03-02 21:37:02 +0200] [880451] [DEBUG] something @ level3
[2021-03-02 21:37:02 +0200] [880451] [DEBUG] something inside __init__.py
[2021-03-02 21:37:02 +0200] [880451] [INFO] Starting worker [880451]
```

## `utility.py`

```python

from glob import glob
from importlib import import_module, util
from inspect import getmembers
from pathlib import Path
from types import ModuleType
from typing import Union

from sanic.blueprints import Blueprint

def autodiscover(
    app, *module_names: Union[str, ModuleType], recursive: bool = False
):
    mod = app.__module__
    blueprints = set()
    _imported = set()

    def _find_bps(module):
        nonlocal blueprints

        for _, member in getmembers(module):
            if isinstance(member, Blueprint):
                blueprints.add(member)

    for module in module_names:
        if isinstance(module, str):
            module = import_module(module, mod)
            _imported.add(module.__file__)
        _find_bps(module)

        if recursive:
            base = Path(module.__file__).parent
            for path in glob(f"{base}/**/*.py", recursive=True):
                if path not in _imported:
                    name = "module"
                    if "__init__" in path:
                        *_, name, __ = path.split("/")
                    spec = util.spec_from_file_location(name, path)
                    specmod = util.module_from_spec(spec)
                    _imported.add(path)
                    spec.loader.exec_module(specmod)
                    _find_bps(specmod)

    for bp in blueprints:
        app.blueprint(bp)
```

## `blueprints/level1.py`

```python
from sanic import Blueprint
from sanic.log import logger

level1 = Blueprint("level1")

@level1.after_server_start
def print_something(app, loop):
    logger.debug("something @ level1")
```

## `blueprints/one/two/level3.py`

```python
from sanic import Blueprint
from sanic.log import logger

level3 = Blueprint("level3")

@level3.after_server_start
def print_something(app, loop):
    logger.debug("something @ level3")
```

## `listeners/something.py`

```python
from sanic import Sanic
from sanic.log import logger

app = Sanic.get_app("auto")

@app.after_server_start
def print_something(app, loop):
    logger.debug("something")
```

## `parent/child/__init__.py`

```python
from sanic import Blueprint
from sanic.log import logger

bp = Blueprint("__init__")

@bp.after_server_start
def print_something(app, loop):
    logger.debug("something inside __init__.py")
```

## `parent/child/nested.py`

```python
from sanic import Blueprint
from sanic.log import logger

nested = Blueprint("nested")

@nested.after_server_start
def print_something(app, loop):
    logger.debug("something @ nested")
```

---

```text
here is the dir tree
generate with 'find . -type d -name "__pycache__" -exec rm -rf {} +; tree'

. # run 'sanic sever -d' here
├── blueprints
│   ├── __init__.py # you need add this file, just empty
│   ├── level1.py
│   └── one
│       └── two
│           └── level3.py
├── listeners
│   └── something.py
├── parent
│   └── child
│       ├── __init__.py
│       └── nested.py
├── server.py
└── utility.py
```

```sh
source ./.venv/bin/activate # activate the python venv which sanic is installed in
sanic sever -d # run this in the directory containing server.py
```

```text
you will see "something ***" like this:

[2023-07-12 11:23:36 +0000] [113704] [DEBUG] something
[2023-07-12 11:23:36 +0000] [113704] [DEBUG] something inside __init__.py
[2023-07-12 11:23:36 +0000] [113704] [DEBUG] something @ level3
[2023-07-12 11:23:36 +0000] [113704] [DEBUG] something @ level1
[2023-07-12 11:23:36 +0000] [113704] [DEBUG] something @ nested
```

---

### Guide Content En Guide How To Cors (`guide/content/en/guide/how-to/cors.md`)

---
title: CORS
---

# Cross-origin resource sharing (CORS)

> How do I configure my application for CORS?

.. note::

    🏆 The best solution is to use [Sanic Extensions](../../plugins/sanic-ext/http/cors.md). 
    
    However, if you would like to build your own version, you could use this limited example as a starting point.

### `server.py`

```python
from sanic import Sanic, text

from cors import add_cors_headers
from options import setup_options

app = Sanic("app")

@app.route("/", methods=["GET", "POST"])
async def do_stuff(request):
    return text("...")

# Add OPTIONS handlers to any route that is missing it
app.register_listener(setup_options, "before_server_start")

# Fill in CORS headers
app.register_middleware(add_cors_headers, "response")
```

## `cors.py`

```python
from typing import Iterable

def _add_cors_headers(response, methods: Iterable[str]) -> None:
    allow_methods = list(set(methods))
    if "OPTIONS" not in allow_methods:
        allow_methods.append("OPTIONS")
    headers = {
        "Access-Control-Allow-Methods": ",".join(allow_methods),
        "Access-Control-Allow-Origin": "mydomain.com",
        "Access-Control-Allow-Credentials": "true",
        "Access-Control-Allow-Headers": (
            "origin, content-type, accept, "
            "authorization, x-xsrf-token, x-request-id"
        ),
    }
    response.headers.extend(headers)

def add_cors_headers(request, response):
    if request.method != "OPTIONS":
        methods = [method for method in request.route.methods]
        _add_cors_headers(response, methods)
```

## `options.py`

```python
from collections import defaultdict
from typing import Dict, FrozenSet

from sanic import Sanic, response
from sanic.router import Route

from cors import _add_cors_headers

def _compile_routes_needing_options(
    routes: Dict[str, Route]
) -> Dict[str, FrozenSet]:
    needs_options = defaultdict(list)
    # This is 21.12 and later. You will need to change this for older versions.
    for route in routes.values():
        if "OPTIONS" not in route.methods:
            needs_options[route.uri].extend(route.methods)

    return {
        uri: frozenset(methods) for uri, methods in dict(needs_options).items()
    }

def _options_wrapper(handler, methods):
    def wrapped_handler(request, *args, **kwargs):
        nonlocal methods
        return handler(request, methods)

    return wrapped_handler

async def options_handler(request, methods) -> response.HTTPResponse:
    resp = response.empty()
    _add_cors_headers(resp, methods)
    return resp

def setup_options(app: Sanic, _):
    app.router.reset()
    needs_options = _compile_routes_needing_options(app.router.routes_all)
    for uri, methods in needs_options.items():
        app.add_route(
            _options_wrapper(options_handler, methods),
            uri,
            methods=["OPTIONS"],
        )
    app.router.finalize()
```

---

```
$ curl localhost:9999/ -i
HTTP/1.1 200 OK
Access-Control-Allow-Methods: OPTIONS,POST,GET
Access-Control-Allow-Origin: mydomain.com
Access-Control-Allow-Credentials: true
Access-Control-Allow-Headers: origin, content-type, accept, authorization, x-xsrf-token, x-request-id
content-length: 3
connection: keep-alive
content-type: text/plain; charset=utf-8

...

$ curl localhost:9999/ -i -X OPTIONS     
HTTP/1.1 204 No Content
Access-Control-Allow-Methods: GET,POST,OPTIONS
Access-Control-Allow-Origin: mydomain.com
Access-Control-Allow-Credentials: true
Access-Control-Allow-Headers: origin, content-type, accept, authorization, x-xsrf-token, x-request-id
connection: keep-alive
```
Also, checkout some resources from the community:

- [Awesome Sanic](https://github.com/mekicha/awesome-sanic/blob/master/README.md#frontend)

---

### Guide Content En Guide How To Mounting (`guide/content/en/guide/how-to/mounting.md`)

# Application Mounting

> How do I mount my application at some path above the root?

```python
# server.py
from sanic import Sanic, text

app = Sanic("app")
app.config.SERVER_NAME = "example.com/api"

@app.route("/foo")
def handler(request):
    url = app.url_for("handler", _external=True)
    return text(f"URL: {url}")
```

```yaml
# docker-compose.yml
version: "3.7"
services:
  app:
    image: nginx:alpine
    ports:
      - 80:80
    volumes:
      - type: bind
        source: ./conf
        target: /etc/nginx/conf.d/default.conf
```

```nginx
# conf
server {
    listen 80;

    # Computed data service
    location /api/ {
        proxy_pass http://<YOUR IP ADDRESS>:9999/;
        proxy_set_header Host example.com;
    }
}
```
```bash
$ docker-compose up -d
$ sanic server.app --port=9999 --host=0.0.0.0
```
```bash
$ curl localhost/api/foo
URL: http://example.com/api/foo
```

---

### Guide Content En Guide How To Orm (`guide/content/en/guide/how-to/orm.md`)

# ORM

>  How do I use SQLAlchemy with Sanic ?

All ORM tools can work with Sanic, but non-async ORM tool have a impact on Sanic performance.
There are some orm packages who support

At present, there are many ORMs that support Python's `async`/`await` keywords. Some possible choices include：

- [Mayim](https://ahopkins.github.io/mayim/)
- [SQLAlchemy 1.4](https://docs.sqlalchemy.org/en/14/changelog/changelog_14.html)
- [tortoise-orm](https://github.com/tortoise/tortoise-orm)

Integration in to your Sanic application is fairly simple:

## Mayim

Mayim ships with [an extension for Sanic Extensions](https://ahopkins.github.io/mayim/guide/extensions.html#sanic), which makes it super simple to get started with Sanic. It is certainly possible to run Mayim with Sanic without the extension, but it is recommended because it handles all of the [lifecycle events](https://sanic.dev/en/guide/basics/listeners.html) and [dependency injections](https://sanic.dev/en/plugins/sanic-ext/injection.html).

.. column::

    ### Dependencies

    First, we need to install the required dependencies. See [Mayim docs](https://ahopkins.github.io/mayim/guide/install.html#postgres) for the installation needed for your DB driver.

.. column::

    ```shell
    pip install sanic-ext
    pip install mayim[postgres]
    ```


.. column::

    ### Define ORM Model

    Mayim allows you to use whatever you want for models. Whether it is [dataclasses](https://docs.python.org/3/library/dataclasses.html), [pydantic](https://pydantic-docs.helpmanual.io/), [attrs](https://www.attrs.org/en/stable/), or even just plain `dict` objects. Since it works very nicely [out of the box with Pydantic](https://ahopkins.github.io/mayim/guide/pydantic.html), that is what we will use here.

.. column::

    ```python
    # ./models.py
    from pydantic import BaseModel

    class City(BaseModel):
        id: int
        name: str
        district: str
        population: int

    class Country(BaseModel):
        code: str
        name: str
        continent: str
        region: str
        capital: City
    ```


.. column::

    ### Define SQL

    If you are unfamiliar, Mayim is different from other ORMs in that it is one-way, SQL-first. This means you define your own queries either inline, or in a separate `.sql` file, which is what we will do here.

.. column::

    ```sql
    -- ./queries/select_all_countries.sql
    SELECT country.code,
        country.name,
        country.continent,
        country.region,
        (
            SELECT row_to_json(q)
            FROM (
                    SELECT city.id,
                        city.name,
                        city.district,
                        city.population
                ) q
        ) capital
    FROM country
        JOIN city ON country.capital = city.id
    ORDER BY country.name ASC
    LIMIT $limit OFFSET $offset;
    ```


.. column::

    ### Create Sanic App and Async Engine

    We need to create the app instance and attach the `SanicMayimExtension` with any executors.

.. column::

    ```python
    # ./server.py
    from sanic import Sanic, Request, json
    from sanic_ext import Extend
    from mayim.executor import PostgresExecutor
    from mayim.extensions import SanicMayimExtension
    from models import Country

    class CountryExecutor(PostgresExecutor):
        async def select_all_countries(
            self, limit: int = 4, offset: int = 0
        ) -> list[Country]:
            ...

    app = Sanic("Test")
    Extend.register(
        SanicMayimExtension(
            executors=[CountryExecutor],
            dsn="postgres://...",
        )
    )
    ```


.. column::

    ### Register Routes

    Because we are using Mayim's extension for Sanic, we have the automatic `CountryExecutor` injection into the route handler. It makes for an easy, type-annotated development experience.

.. column::

    ```python
    @app.get("/")
    async def handler(request: Request, executor: CountryExecutor):
        countries = await executor.select_all_countries()
        return json({"countries": [country.dict() for country in co
    ```


.. column::

    ### Send Requests

.. column::

    ```sh
    curl 'http://127.0.0.1:8000'
    {"countries":[{"code":"AFG","name":"Afghanistan","continent":"Asia","region":"Southern and Central Asia","capital":{"id":1,"name":"Kabul","district":"Kabol","population":1780000}},{"code":"ALB","name":"Albania","continent":"Europe","region":"Southern Europe","capital":{"id":34,"name":"Tirana","district":"Tirana","population":270000}},{"code":"DZA","name":"Algeria","continent":"Africa","region":"Northern Africa","capital":{"id":35,"name":"Alger","district":"Alger","population":2168000}},{"code":"ASM","name":"American Samoa","continent":"Oceania","region":"Polynesia","capital":{"id":54,"name":"Fagatogo","district":"Tutuila","population":2323}}]}
    ```


## SQLAlchemy

Because [SQLAlchemy 1.4](https://docs.sqlalchemy.org/en/14/changelog/changelog_14.html) has added native support for `asyncio`, Sanic can finally work well with SQLAlchemy. Be aware that this functionality is still considered *beta* by the SQLAlchemy project.


.. column::

    ### Dependencies

    First, we need to install the required dependencies. In the past, the dependencies installed were `sqlalchemy` and `pymysql`, but now `sqlalchemy` and `aiomysql` are needed.

.. column::

    ```shell
    pip install -U sqlalchemy
    pip install -U aiomysql
    ```


.. column::

    ### Define ORM Model

    ORM model creation remains the same.

.. column::

    ```python
    # ./models.py
    from sqlalchemy import INTEGER, Column, ForeignKey, String
    from sqlalchemy.orm import declarative_base, relationship

    Base = declarative_base()

    class BaseModel(Base):
        __abstract__ = True
        id = Column(INTEGER(), primary_key=True)

    class Person(BaseModel):
        __tablename__ = "person"
        name = Column(String())
        cars = relationship("Car")

        def to_dict(self):
            return {"name": self.name, "cars": [{"brand": car.brand} for car in self.cars]}

    class Car(BaseModel):
        __tablename__ = "car"

        brand = Column(String())
        user_id = Column(ForeignKey("person.id"))
        user = relationship("Person", back_populates="cars")
    ```


.. column::

    ### Create Sanic App and Async Engine

    Here we use mysql as the database, and you can also choose PostgreSQL/SQLite. Pay attention to changing the driver from `aiomysql` to `asyncpg`/`aiosqlite`.

.. column::

    ```python
    # ./server.py
    from sanic import Sanic
    from sqlalchemy.ext.asyncio import create_async_engine

    app = Sanic("my_app")

    bind = create_async_engine("mysql+aiomysql://root:root@localhost/test", echo=True)
    ```


.. column::

    ### Register Middlewares

    The request middleware creates an usable `AsyncSession` object and set it to `request.ctx` and `_base_model_session_ctx`.

    Thread-safe variable `_base_model_session_ctx` helps you to use the session object instead of fetching it from `request.ctx`.

.. column::

    ```python
    # ./server.py
    from contextvars import ContextVar

    from sqlalchemy.ext.asyncio import AsyncSession
    from sqlalchemy.orm import sessionmaker

    _sessionmaker = sessionmaker(bind, AsyncSession, expire_on_commit=False)

    _base_model_session_ctx = ContextVar("session")

    @app.middleware("request")
    async def inject_session(request):
        request.ctx.session = _sessionmaker()
        request.ctx.session_ctx_token = _base_model_session_ctx.set(request.ctx.session)

    @app.middleware("response")
    async def close_session(request, response):
        if hasattr(request.ctx, "session_ctx_token"):
            _base_model_session_ctx.reset(request.ctx.session_ctx_token)
            await request.ctx.session.close()
    ```


.. column::

    ### Register Routes

    According to sqlalchemy official docs, `session.query` will be legacy in 2.0, and the 2.0 way to query an ORM object is using `select`.

.. column::

    ```python
    # ./server.py
    from sqlalchemy import select
    from sqlalchemy.orm import selectinload
    from sanic.response import json

    from models import Car, Person

    @app.post("/user")
    async def create_user(request):
        session = request.ctx.session
        async with session.begin():
            car = Car(brand="Tesla")
            person = Person(name="foo", cars=[car])
            session.add_all([person])
        return json(person.to_dict())

    @app.get("/user/<pk:int>")
    async def get_user(request, pk):
        session = request.ctx.session
        async with session.begin():
            stmt = select(Person).where(Person.id == pk).options(selectinload(Person.cars))
            result = await session.execute(stmt)
            person = result.scalar()

        if not person:
            return json({})

        return json(person.to_dict())
    ```


.. column::

    ### Send Requests

.. column::

    ```sh
    curl --location --request POST 'http://127.0.0.1:8000/user'
    {"name":"foo","cars":[{"brand":"Tesla"}]}
    ```

    ```sh
    curl --location --request GET 'http://127.0.0.1:8000/user/1'
    {"name":"foo","cars":[{"brand":"Tesla"}]}
    ```


## Tortoise-ORM

.. column::

    ### Dependencies

    tortoise-orm's dependency is very simple, you just need install tortoise-orm.

.. column::

    ```shell
    pip install -U tortoise-orm
    ```


.. column::

    ### Define ORM Model

    If you are familiar with Django, you should find this part very familiar.

.. column::

    ```python
    # ./models.py
    from tortoise import Model, fields

    class Users(Model):
        id = fields.IntField(pk=True)
        name = fields.CharField(50)

        def __str__(self):
            return f"I am {self.name}"
    ```



.. column::

    ### Create Sanic App and Async Engine

    Tortoise-orm provides a set of registration interface, which is convenient for users, and you can use it to create database connection easily.

.. column::

    ```python
    # ./main.py

    from models import Users
    from tortoise.contrib.sanic import register_tortoise

    app = Sanic(__name__)

    register_tortoise(
        app, db_url="mysql://root:root@localhost/test", modules={"models": ["models"]}, generate_schemas=True
    )

    ```


.. column::

    ### Register Routes

.. column::

    ```python
    # ./main.py

    from models import Users
    from sanic import Sanic, response

    @app.route("/user")
    async def list_all(request):
        users = await Users.all()
        return response.json({"users": [str(user) for user in users]})

    @app.route("/user/<pk:int>")
    async def get_user(request, pk):
        user = await Users.query(pk=pk)
        return response.json({"user": str(user)})

    if __name__ == "__main__":
        app.run(port=5000)
    ```


.. column::

    ### Send Requests

.. column::

    ```sh
    curl --location --request POST 'http://127.0.0.1:8000/user'
    {"users":["I am foo", "I am bar"]}
    ```

    ```sh
    curl --location --request GET 'http://127.0.0.1:8000/user/1'
    {"user": "I am foo"}
    ```

---

### Guide Content En Guide How To Static Redirects (`guide/content/en/guide/how-to/static-redirects.md`)

# "Static" Redirects

> How do I configure static redirects?

## `app.py`

```python
### SETUP ###
import typing
import sanic, sanic.response

# Create the Sanic app
app = sanic.Sanic(__name__)

# This dictionary represents your "static"
# redirects. For example, these values
# could be pulled from a configuration file.
REDIRECTS = {
    '/':'/hello_world',                     # Redirect '/' to '/hello_world'
    '/hello_world':'/hello_world.html'      # Redirect '/hello_world' to 'hello_world.html'
}

# This function will return another function
# that will return the configured value
# regardless of the arguments passed to it.
def get_static_function(value:typing.Any) -> typing.Callable[..., typing.Any]:
    return lambda *_, **__: value

### ROUTING ###
# Iterate through the redirects
for src, dest in REDIRECTS.items():                            
    # Create the redirect response object         
    response:sanic.HTTPResponse = sanic.response.redirect(dest)

    # Create the handler function. Typically,
    # only a sanic.Request object is passed
    # to the function. This object will be 
    # ignored.
    handler = get_static_function(response)

    # Route the src path to the handler
    app.route(src)(handler)

# Route some file and client resources
app.static('/files/', 'files')
app.static('/', 'client')

### RUN ###
if __name__ == '__main__':
    app.run(
        '127.0.0.1',
        10000
    )
```

## `client/hello_world.html`

```html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Hello World</title>
</head>
<link rel="stylesheet" href="/hello_world.css">
<body>
    <div id='hello_world'>
        Hello world!
    </div>
</body>
</html>
```

## `client/hello_world.css`

```css
#hello_world {
    width: 1000px;
    margin-left: auto;
    margin-right: auto;
    margin-top: 100px;

    padding: 100px;
    color: aqua;
    text-align: center;
    font-size: 100px;
    font-family: monospace;

    background-color: rgba(0, 0, 0, 0.75);

    border-radius: 10px;
    box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.75);
}

body {
    background-image: url("/files/grottoes.jpg");
    background-repeat: no-repeat;
    background-size: cover;
}
```

## `files/grottoes.jpg`



---

Also, checkout some resources from the community:

- [Static Routing Example](https://github.com/Perzan/sanic-static-routing-example)

---

### Guide Content En Guide How To Table Of Contents (`guide/content/en/guide/how-to/table-of-contents.md`)

---
title: Table of Contents
---

# Table of Contents

We have compiled fully working examples to answer common questions and user cases. For the most part, the examples are as minimal as possible, but should be complete and runnable solutions.

| Page | How do I ... |
|:-----|:------------|
| [Application mounting](./mounting.md)       | ... mount my application at some path above the root? |
| [Authentication](./authentication.md)       | ... control authentication and authorization? |
| [Autodiscovery](./autodiscovery.md)         | ... autodiscover the components I am using to build my application? |
| [CORS](./cors.md)                           | ... configure my application for CORS? |
| [ORM](./orm)                                | ... use an ORM with Sanic? |
| ["Static" Redirects](./static-redirects.md) | ... configure static redirects |
| [TLS/SSL/HTTPS](./tls.md)                   | ... run Sanic via HTTPS?<br> ... redirect HTTP to HTTPS? |

---

### Guide Content En Guide How To Tls (`guide/content/en/guide/how-to/tls.md`)

---
title: TLS/SSL/HTTPS
---

# TLS/SSL/HTTPS

> How do I run Sanic via HTTPS? 

If you do not have TLS certificates yet, [see the end of this page](./tls.md#get-certificates-for-your-domain-names).

## Single domain and single certificate

.. column::

    Let Sanic automatically load your certificate files, which need to be named `fullchain.pem` and `privkey.pem` in the given folder:

.. column::

    ```sh
    sudo sanic myserver:app -H :: -p 443 \
      --tls /etc/letsencrypt/live/example.com/
    ```
    ```python
    app.run("::", 443, ssl="/etc/letsencrypt/live/example.com/")
    ```


.. column::

    Or, you can pass cert and key filenames separately as a dictionary:

    Additionally, `password` may be added if the key is encrypted, all fields except for the password are passed to `request.conn_info.cert`.

.. column::

    ```python
    ssl = {
        "cert": "/path/to/fullchain.pem",
        "key": "/path/to/privkey.pem",
        "password": "for encrypted privkey file",   # Optional
    }
    app.run(host="0.0.0.0", port=8443, ssl=ssl)
    ```


.. column::

    Alternatively, [`ssl.SSLContext`](https://docs.python.org/3/library/ssl.html) may be passed, if you need full control over details such as which crypto algorithms are permitted. By default Sanic only allows secure algorithms, which may restrict access from very old devices.

.. column::

    ```python
    import ssl

    context = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH)
    context.load_cert_chain("certs/fullchain.pem", "certs/privkey.pem")

    app.run(host="0.0.0.0", port=8443, ssl=context)
    ```


## Multiple domains with separate certificates

.. column::

    A list of multiple certificates may be provided, in which case Sanic chooses the one matching the hostname the user is connecting to. This occurs so early in the TLS handshake that Sanic has not sent any packets to the client yet.

    If the client sends no SNI (Server Name Indication), the first certificate on the list will be used even though on the client browser it will likely fail with a TLS error due to name mismatch. To prevent this fallback and to cause immediate disconnection of clients without a known hostname, add `None` as the first entry on the list. `--tls-strict-host` is the equivalent CLI option.

.. column::

    ```python
    ssl = ["certs/example.com/", "certs/bigcorp.test/"]
    app.run(host="0.0.0.0", port=8443, ssl=ssl)
    ```
    ```sh
    sanic myserver:app
        --tls certs/example.com/
        --tls certs/bigcorp.test/
        --tls-strict-host
    ```

.. tip:: 

    You may also use `None` in front of a single certificate if you do not wish to reveal your certificate, true hostname or site content to anyone connecting to the IP address instead of the proper DNS name.

.. column::

    Dictionaries can be used on the list. This allows also specifying which domains a certificate matches to, although the names present on the certificate itself cannot be controlled from here. If names are not specified, the names from the certificate itself are used.

    To only allow connections to the main domain **example.com** and only to subdomains of **bigcorp.test**:

.. column::

    ```python
    ssl = [
        None,  # No fallback if names do not match!
        {
            "cert": "certs/example.com/fullchain.pem",
            "key": "certs/example.com/privkey.pem",
            "names": ["example.com", "*.bigcorp.test"],
        }
    ]
    app.run(host="0.0.0.0", port=8443, ssl=ssl)
    ```

## Accessing TLS information in handlers via `request.conn_info` fields

* `.ssl` - is the connection secure (bool)
* `.cert` - certificate info and dict fields of the currently active cert (dict)
* `.server_name` - the SNI sent by the client (str, may be empty)

Do note that all `conn_info` fields are per connection, where there may be many requests over time. If a proxy is used in front of your server, these requests on the same pipe may even come from different users.

## Redirect HTTP to HTTPS, with certificate requests still over HTTP

In addition to your normal server(s) running HTTPS, run another server for redirection, `http_redir.py`:

```python
from sanic import Sanic, exceptions, response

app = Sanic("http_redir")

# Serve ACME/certbot files without HTTPS, for certificate renewals
app.static("/.well-known", "/var/www/.well-known", resource_type="dir")

@app.exception(exceptions.NotFound, exceptions.MethodNotSupported)
def redirect_everything_else(request, exception):
    server, path = request.server_name, request.path
    if server and path.startswith("/"):
        return response.redirect(f"https://{server}{path}", status=308)
    return response.text("Bad Request. Please use HTTPS!", status=400)
```

It is best to setup this as a systemd unit separate of your HTTPS servers. You may need to run HTTP while initially requesting your certificates, while you cannot run the HTTPS server yet. Start for IPv4 and IPv6:

```
sanic http_redir:app -H 0.0.0.0 -p 80
sanic http_redir:app -H :: -p 80
```

Alternatively, it is possible to run the HTTP redirect application from the main application:

```python
# app == Your main application
# redirect == Your http_redir application
@app.before_server_start
async def start(app, _):
    app.ctx.redirect = await redirect.create_server(
        port=80, return_asyncio_server=True
    )
    app.add_task(runner(redirect, app.ctx.redirect))

@app.before_server_stop
async def stop(app, _):
    await app.ctx.redirect.close()

async def runner(app, app_server):
    app.state.is_running = True
    try:
        app.signalize()
        app.finalize()
        app.state.is_started = True
        await app_server.serve_forever()
    finally:
        app.state.is_running = False
        app.state.is_stopping = True
```

## Get certificates for your domain names

You can get free certificates from [Let's Encrypt](https://letsencrypt.org/). Install [certbot](https://certbot.eff.org/) via your package manager, and request a certificate:

```sh
sudo certbot certonly --key-type ecdsa --preferred-chain "ISRG Root X1" -d example.com -d www.example.com
```

Multiple domain names may be added by further `-d` arguments, all stored into a single certificate which gets saved to `/etc/letsencrypt/live/example.com/` as per **the first domain** that you list here.

The key type and preferred chain options are necessary for getting a minimal size certificate file, essential for making your server run as *fast* as possible. The chain will still contain one RSA certificate until when Let's Encrypt gets their new EC chain trusted in all major browsers.

---

### Guide Content En Guide Running App Loader (`guide/content/en/guide/running/app-loader.md`)

---
title: Dynamic Applications
---

# Dynamic Applications

Running Sanic has been optimized to work with the CLI. If you have not read it yet, you should read [Running Sanic](./running.md#sanic-server) to become familiar with the options. 

.. column::

    This includes running it as a global scope object...

.. column::

    ```sh
    sanic path.to.server:app
    ```
    ```python
    # server.py
    app = Sanic("TestApp")

    @app.get("/")
    async def handler(request: Request):
        return json({"foo": "bar"})
    ```



.. column::

    ...or, a factory function that creates the `Sanic` application object.

.. column::

    ```sh
    sanic path.to.server:create_app --factory
    ```
    ```python
    # server.py
    def create_app():
        app = Sanic("TestApp")

        @app.get("/")
        async def handler(request: Request):
            return json({"foo": "bar"})

        return app
    ```


**Sometimes, this is not enough ... 🤔**

Introduced in [v22.9](../../release-notes/2022/v22.9.md), Sanic has an `AppLoader` object that is responsible for creating an application in the various [worker processes](./manager.md#how-sanic-server-starts-processes). You can take advantage of this if you need to create a more dynamic startup experience for your application.

.. column::

    An `AppLoader` can be passed a callable that returns a `Sanic` instance. That `AppLoader` could be used with the low-level application running API.

.. column::

    ```python
    import sys
    from functools import partial

    from sanic import Request, Sanic, json
    from sanic.worker.loader import AppLoader

    def attach_endpoints(app: Sanic):
        @app.get("/")
        async def handler(request: Request):
            return json({"app_name": request.app.name})

    def create_app(app_name: str) -> Sanic:
        app = Sanic(app_name)
        attach_endpoints(app)
        return app

    if __name__ == "__main__":
        app_name = sys.argv[-1]
        loader = AppLoader(factory=partial(create_app, app_name))
        app = loader.load()
        app.prepare(port=9999, dev=True)
        Sanic.serve(primary=app, app_loader=loader)
    ```
    ```sh
    python path/to/server.py MyTestAppName
    ```

In the above example, the `AppLoader` is created with a `factory` that can be used to create copies of the same application across processes. When doing this, you should explicitly use the `Sanic.serve` pattern shown above so that the `AppLoader` that you create is not replaced.

---

### Guide Content En Guide Running Configuration (`guide/content/en/guide/running/configuration.md`)

# Configuration

## Basics


.. column::

    Sanic holds the configuration in the config attribute of the application object. The configuration object is merely an object that can be modified either using dot-notation or like a dictionary.

.. column::

    ```python
    app = Sanic("myapp")
    app.config.DB_NAME = "appdb"
    app.config["DB_USER"] = "appuser"
    ```


.. column::

    You can also use the `update()` method like on regular dictionaries.

.. column::

    ```python
    db_settings = {
        'DB_HOST': 'localhost',
        'DB_NAME': 'appdb',
        'DB_USER': 'appuser'
    }
    app.config.update(db_settings)
    ```



.. note:: 

    It is standard practice in Sanic to name your config values in **uppercase letters**. Indeed, you may experience weird behaviors if you start mixing uppercase and lowercase names.



## Loading

### Environment variables

.. column::

    Any environment variables defined with the `SANIC_` prefix will be applied to the Sanic config. For example, setting `SANIC_REQUEST_TIMEOUT` will be loaded by the application automatically and fed into the `REQUEST_TIMEOUT` config variable.

.. column::

    ```bash
    $ export SANIC_REQUEST_TIMEOUT=10
    ```
    ```python
    >>> print(app.config.REQUEST_TIMEOUT)
    10
    ```


.. column::

    You can change the prefix that Sanic is expecting at startup.

.. column::

    ```bash
    $ export MYAPP_REQUEST_TIMEOUT=10
    ```
    ```python
    >>> app = Sanic(__name__, env_prefix='MYAPP_')
    >>> print(app.config.REQUEST_TIMEOUT)
    10
    ```


.. column::

    You can also disable environment variable loading completely.

.. column::

    ```python
    app = Sanic(__name__, load_env=False)
    ```

### Using Sanic.update_config

The `Sanic` instance has a _very_ versatile method for loading config: `app.update_config`. You can feed it a path to a file, a dictionary, a class, or just about any other sort of object.

#### From a file

.. column::

    Let's say you have `my_config.py` file that looks like this.

.. column::

    ```python
    # my_config.py
    A = 1
    B = 2
    ```


.. column::

    You can load this as config values by passing its path to `app.update_config`.

.. column::

    ```python
    >>> app.update_config("/path/to/my_config.py")
    >>> print(app.config.A)
    1
    ```


.. column::

    This path also accepts bash style environment variables.

.. column::

    ```bash
    $ export my_path="/path/to"
    ```
    ```python
    app.update_config("${my_path}/my_config.py")
    ```



.. note:: 
    
    Just remember that you have to provide environment variables in the format `${environment_variable}` and that `$environment_variable` is not expanded (is treated as "plain" text).



#### From a dict

.. column::

    The `app.update_config` method also works on plain dictionaries.

.. column::

    ```python
    app.update_config({"A": 1, "B": 2})
    ```

#### From a class or object

.. column::

    You can define your own config class, and pass it to `app.update_config`

.. column::

    ```python
    class MyConfig:
        A = 1
        B = 2

    app.update_config(MyConfig)
    ```


.. column::

    It even could be instantiated.

.. column::

    ```python
    app.update_config(MyConfig())
    ```

### Type casting

When loading from environment variables, Sanic will attempt to cast the values to expected Python types. This particularly applies to:

- `int`
- `float`
- `bool`

In regards to `bool`, the following _case insensitive_ values are allowed:

- **`True`**: `y`, `yes`, `yep`, `yup`, `t`, `true`, `on`, `enable`, `enabled`, `1`
- **`False`**: `n`, `no`, `f`, `nope`, `false`, `off`, `disable`, `disabled`, `0`

If a value cannot be cast, it will default to a `str`.

.. column::

    Additionally, Sanic can be configured to cast additional types using additional type converters. This should be any callable that returns the value or raises a `ValueError`.

    *Added in v21.12*

.. column::

    ```python
    app = Sanic(..., config=Config(converters=[UUID]))
    ```

#### Advanced Type Converters

.. new:: New in v25.12

    This feature was added in version 25.12

.. column::

    For more sophisticated conversion logic that needs access to the full environment variable context, you can use `DetailedConverter`. This abstract base class provides access to the full environment variable key, the raw value, and the current config defaults.

    This is useful when you need to:
    - Cast values to the type of their defaults
    - Perform validation based on the variable name pattern
    - Use default values for fallback logic
    - Access configuration context during conversion

.. column::

    ```python
    from sanic.config import DetailedConverter

    class DefaultsTypeCastingConverter(DetailedConverter):
        def __call__(self, full_key: str, config_key: str, value: str, defaults: dict):
            try:
                if config_key in defaults:
                    return type(defaults[config_key])(value)
            except (ValueError, TypeError) as e:
                raise TypeError(f"Configuration environment variable '{full_key}' type mismatch: expected"
                                f" {type(defaults[config_key]).__name__}, got {type(value).__name__}") from e

    app = Sanic(..., config=Config(converters=[DefaultsTypeCastingConverter()]))
    ```

.. column::

    The `DetailedConverter.__call__` method receives four parameters:

    - `full_key`: The full environment variable name with prefix (e.g., "SANIC_DATABASE_URL")
    - `config_key`: The config key without prefix (e.g., "DATABASE_URL")
    - `value`: The raw string value from the environment
    - `defaults`: The current default configuration values

.. column::

    ```python
    class ValidationConverter(DetailedConverter):
        def __call__(self, full_key: str, config_key: str, value: str, defaults: dict):
            if config_key.endswith('_PORT'):
                port = int(value)
                if not 1 <= port <= 65535:
                    raise ValueError(f"Invalid port: {port}")
                return port
            raise ValueError  # Let other converters handle it
    ```

## Builtin values

| **Variable**              | **Default**      | **Description**                                                                                                                       |
|---------------------------|------------------|---------------------------------------------------------------------------------------------------------------------------------------|
| ACCESS_LOG                | True             | Disable or enable access log                                                                                                          |
| AUTO_EXTEND               | True             | Control whether [Sanic Extensions](../../plugins/sanic-ext/getting-started.md) will load if it is in the existing virtual environment |
| AUTO_RELOAD               | True             | Control whether the application will automatically reload when a file changes                                                         |
| EVENT_AUTOREGISTER        | True             | When `True` using the `app.event()` method on a non-existing signal will automatically create it and not raise an exception           |
| FALLBACK_ERROR_FORMAT     | html             | Format of error response if an exception is not caught and handled                                                                    |
| FORWARDED_FOR_HEADER      | X-Forwarded-For  | The name of "X-Forwarded-For" HTTP header that contains client and proxy ip                                                           |
| FORWARDED_SECRET          | None             | Used to securely identify a specific proxy server (see below)                                                                         |
| GRACEFUL_SHUTDOWN_TIMEOUT | 15.0             | How long to wait to force close non-idle connection (sec)                                                                             |
| INSPECTOR                 | False            | Whether to enable the Inspector                                                                                                       |
| INSPECTOR_HOST            | localhost        | The host for the Inspector                                                                                                            |
| INSPECTOR_PORT            | 6457             | The port for the Inspector                                                                                                            |
| INSPECTOR_TLS_KEY         | -                | The TLS key for the Inspector                                                                                                         |
| INSPECTOR_TLS_CERT        | -                | The TLS certificate for the Inspector                                                                                                 |
| INSPECTOR_API_KEY         | -                | The API key for the Inspector                                                                                                         |
| KEEP_ALIVE_TIMEOUT        | 120              | How long to hold a TCP connection open (sec)                                                                                          |
| KEEP_ALIVE                | True             | Disables keep-alive when False                                                                                                        |
| MOTD                      | True             | Whether to display the MOTD (message of the day) at startup                                                                           |
| MOTD_DISPLAY              | {}               | Key/value pairs to display additional, arbitrary data in the MOTD                                                                     |
| NOISY_EXCEPTIONS          | False            | Force all `quiet` exceptions to be logged                                                                                             |
| PROXIES_COUNT             | None             | The number of proxy servers in front of the app (e.g. nginx; see below)                                                               |
| REAL_IP_HEADER            | None             | The name of "X-Real-IP" HTTP header that contains real client ip                                                                      |
| REGISTER                  | True             | Whether the app registry should be enabled                                                                                            |
| REQUEST_BUFFER_SIZE       | 65536            | Request buffer size before request is paused, default is 64 Kib                                                                       |
| REQUEST_ID_HEADER         | X-Request-ID     | The name of "X-Request-ID" HTTP header that contains request/correlation ID                                                           |
| REQUEST_MAX_SIZE          | 100000000        | How big a request may be (bytes), default is 100 megabytes                                                                            |
| REQUEST_MAX_HEADER_SIZE   | 8192            | How big a request header may be (bytes), default is 8192 bytes                                                                         |
| REQUEST_TIMEOUT           | 60               | How long a request can take to arrive (sec)                                                                                           |
| RESPONSE_TIMEOUT          | 60               | How long a response can take to process (sec)                                                                                         |
| USE_UVLOOP                | True             | Whether to override the loop policy to use `uvloop`. Supported only with `app.run`.                                                   |
| WEBSOCKET_MAX_SIZE        | 2^20             | Maximum size for incoming messages (bytes)                                                                                            |
| WEBSOCKET_PING_INTERVAL   | 20               | A Ping frame is sent every ping_interval seconds.                                                                                     |
| WEBSOCKET_PING_TIMEOUT    | 20               | Connection is closed when Pong is not received after ping_timeout seconds                                                             |


.. tip:: FYI

    - The `USE_UVLOOP` value will be ignored if running with Gunicorn. Defaults to `False` on non-supported platforms (Windows).
    - The `WEBSOCKET_` values will be ignored if in ASGI mode.
    - v21.12 added: `AUTO_EXTEND`, `MOTD`, `MOTD_DISPLAY`, `NOISY_EXCEPTIONS`
    - v22.9 added: `INSPECTOR`
    - v22.12 added: `INSPECTOR_HOST`, `INSPECTOR_PORT`, `INSPECTOR_TLS_KEY`, `INSPECTOR_TLS_CERT`, `INSPECTOR_API_KEY`


## Timeouts

### REQUEST_TIMEOUT

A request timeout measures the duration of time between the instant when a new open TCP connection is passed to the
Sanic backend server, and the instant when the whole HTTP request is received. If the time taken exceeds the
`REQUEST_TIMEOUT` value (in seconds), this is considered a Client Error so Sanic generates an `HTTP 408` response
and sends that to the client. Set this parameter's value higher if your clients routinely pass very large request payloads
or upload requests very slowly.

### RESPONSE_TIMEOUT

A response timeout measures the duration of time between the instant the Sanic server passes the HTTP request to the Sanic App, and the instant a HTTP response is sent to the client. If the time taken exceeds the `RESPONSE_TIMEOUT` value (in seconds), this is considered a Server Error so Sanic generates an `HTTP 503` response and sends that to the client. Set this parameter's value higher if your application is likely to have long-running process that delay the
generation of a response.

### KEEP_ALIVE_TIMEOUT

#### What is Keep Alive? And what does the Keep Alive Timeout value do?

`Keep-Alive` is a HTTP feature introduced in `HTTP 1.1`. When sending a HTTP request, the client (usually a web browser application) can set a `Keep-Alive` header to indicate the http server (Sanic) to not close the TCP connection after it has send the response. This allows the client to reuse the existing TCP connection to send subsequent HTTP requests, and ensures more efficient network traffic for both the client and the server.

The `KEEP_ALIVE` config variable is set to `True` in Sanic by default. If you don't need this feature in your application, set it to `False` to cause all client connections to close immediately after a response is sent, regardless of the `Keep-Alive` header on the request.

The amount of time the server holds the TCP connection open is decided by the server itself. In Sanic, that value is configured using the `KEEP_ALIVE_TIMEOUT` value. By default, **it is set to 120 seconds**. This means that if the client sends a `Keep-Alive` header, the server will hold the TCP connection open for 120 seconds after sending the response, and the client can reuse the connection to send another HTTP request within that time.

For reference:

* Apache httpd server default keepalive timeout = 5 seconds
* Nginx server default keepalive timeout = 75 seconds
* Nginx performance tuning guidelines uses keepalive = 15 seconds
* Caddy server default keepalive timeout = 120 seconds
* IE (5-9) client hard keepalive limit = 60 seconds
* Firefox client hard keepalive limit = 115 seconds
* Opera 11 client hard keepalive limit = 120 seconds
* Chrome 13+ client keepalive limit > 300+ seconds

## Proxy configuration

See [proxy configuration section](../advanced/proxy-headers.md)

---

### Guide Content En Guide Running Development (`guide/content/en/guide/running/development.md`)

# Development

The first thing that should be mentioned is that the webserver that is integrated into Sanic is **not** just a development server. 

It is production ready out-of-the-box, *unless you enable in debug mode*.

## Debug mode

By setting the debug mode, Sanic will be more verbose in its output and will disable several run-time optimizations.

```python
# server.py
from sanic import Sanic
from sanic.response import json

app = Sanic(__name__)

@app.route("/")
async def hello_world(request):
    return json({"hello": "world"})
```
```sh
sanic server:app --host=0.0.0.0 --port=1234 --debug
```


.. danger:: 
    
    Sanic's debug mode will slow down the server's performance, and is **NOT** intended for production environments.

    **DO NOT** enable debug mode in production.



## Automatic Reloader

.. column::

    Sanic offers a way to enable or disable the Automatic Reloader. The easiest way to enable it is using the CLI's `--reload` argument to activate the Automatic Reloader. Every time a Python file is changed, the reloader will restart your application automatically. This is very convenient while developing.

    .. note:: 
    
        The reloader is only available when using Sanic's [worker manager](./manager.md). If you have disabled it using `--single-process` then the reloader will not be available to you.

.. column::

    ```sh
    sanic path.to:app --reload
    ```
    You can also use the shorthand property
    ```sh
    sanic path.to:app -r
    ```


.. column::

    If you have additional directories that you would like to automatically reload on file save (for example, a directory of HTML templates), you can add that using `--reload-dir`.

.. column::

    ```sh
    sanic path.to:app --reload --reload-dir=/path/to/templates
    ```
    Or multiple directories, shown here using the shorthand properties
    ```sh
    sanic path.to:app -r -R /path/to/one -R /path/to/two
    ```


## Development REPL

The Sanic CLI comes with a REPL (aka "read-eval-print loop") that can be used to interact with your application. This is useful for debugging and testing. A REPL is the interactive shell that you get when you run `python` without any arguments.

.. column::

    You can start the REPL by passing the `--repl` argument to the Sanic CLI.

.. column::

    ```sh
    sanic path.to.server:app --repl
    ```

.. column::

    Or, perhaps more conveniently, when you run `--dev`, Sanic will automatically start the REPL for you. However, in this case you might be prompted to hit the "ENTER" key before actually starting the REPL.

.. column::

    ```sh
    sanic path.to.server:app --dev
    ```



As seen in the screenshot above, the REPL will automatically add a few variables to the global namespace. These are:

- `app` - The Sanic application instance. This is the same instance that is passed to the `sanic` CLI.
- `sanic` - The `sanic` module. This is the same module that is imported when you run `import sanic`.
- `do` - A function that will create a mock `Request` object and pass it to your application. This is useful for testing your application from the REPL.
- `client` - An instance of `httpx.Client` that is configured to make requests to your application. This is useful for testing your application from the REPL. **Note:** This is only available if `httpx` is installed in your environment.

### Async/Await support

.. column::

    The REPL supports `async`/`await` syntax. This means that you can use `await` in the REPL to wait for asynchronous operations to complete. This is useful for testing asynchronous code.

.. column::

    ```python
    >>> await app.ctx.db.fetchval("SELECT 1")
    1 
    ```

### The `app` variable

You need to keep in mind that the `app` variable is your app instance as it existed when the REPL was started. It is the instance that is loaded when running the CLI command. This means that any changes that are made to your source code and subsequently reloaded in the workers will not be reflected in the `app` variable. If you want to interact with the reloaded app instance, you will need to restart the REPL.

However, it is also very useful to have access to the original app instance in the REPL for adhoc testing and debugging.

### The `client` variable

When [httpx](https://www.python-httpx.org/) is installed in your environment, the `client` variable will be available in the REPL. This is an instance of `httpx.Client` that is configured to make requests to your running application.

.. column::

    To use it, simply call one of the HTTP methods on the client. See the [httpx documentation](https://www.python-httpx.org/api/#client) for more information.

.. column::

    ```python
    >>> client.get("/")
    <Response [200 OK]>
    ```

### The `do` function

As discussed above, the `app` instance exists as it did at the time the REPL was started, and as was modified inside the REPL. Any changes to the instance that cause a server to be reloaded will not be reflected in the `app` variable. This is where the `do` function comes in.

Let's say that you have modified your application inside the REPL to add a new route:

```python
>>> @app.get("/new-route")
... async def new_route(request):
...     return sanic.json({"hello": "world"})
...
>>>
```

You can use the `do` function to mock out a request, and pass it to the application as if it were a real HTTP request. This will allow you to test your new route without having to restart the REPL.

```python
>>> await do("/new-route")
Result(request=<Request: GET /new-route>, response=<JSONResponse: 200 application/json>)
```

The `do` function returns a `Result` object that contains the `Request` and `Response` objects that were returned by your application. It is a `NamedTuple`, so you can access the values by name:

```python
>>> result = await do("/new-route")
>>> result.request
<Request: GET /new-route>
>>> result.response
<JSONResponse: 200 application/json>
```

Or, by destructuring the tuple:

```python
>>> request, response = await do("/new-route")
>>> request
<Request: GET /new-route>
>>> response
<JSONResponse: 200 application/json>
```

### When to use `do` vs `client`?

.. column::

    **Use `do` when ...**

    - You want to test a route that does not exist in the running application
    - You want to test a route that has been modified in the REPL
    - You make a change to your application inside the REPL

.. column::

    **Use `client` when ...**

    - You want to test a route that already exists in the running application
    - You want to test a route that has been modified in your source code
    - You want to send an actual HTTP request to your application

*Added in v23.12*

## Complete development mode

.. column::

    If you would like to be in debug mode **and** have the Automatic Reloader running, you can pass `dev=True`. This is equivalent to **debug + auto reload + REPL**.

    *Added in v22.3*

.. column::

    ```sh
    sanic path.to:app --dev
    ```
    You can also use the shorthand property
    ```sh
    sanic path.to:app -d
    ```

Added to the `--dev` flag in v23.12 is the ability to start a REPL. See the [Development REPL](./development.md#development-repl) section for more information.
    
As of v23.12, the `--dev` flag is roughly equivalent to `--debug --reload --repl`. Using `--dev` will require you to expressly begin the REPL by hitting "ENTER", while passing the `--repl` flag explicitly starts it.
Before v23.12, the `--dev` flag is more similar to `--debug --reload`.
	
.. column::

    If you would like to disable the REPL while using the `--dev` flag, you can pass `--no-repl`.

.. column::

    ```sh
    sanic path.to:app --dev --no-repl
    ```

## Automatic TLS certificate

When running in `DEBUG` mode, you can ask Sanic to handle setting up localhost temporary TLS certificates. This is helpful if you want to access your local development environment with `https://`.

This functionality is provided by either [mkcert](https://github.com/FiloSottile/mkcert) or [trustme](https://github.com/python-trio/trustme). Both are good choices, but there are some differences. `trustme` is a Python library and can be installed into your environment with `pip`. This makes for easy envrionment handling, but it is not compatible when running a HTTP/3 server. `mkcert` might be a more involved installation process, but can install a local CA and make it easier to use.

.. column::

    You can choose which platform to use by setting `config.LOCAL_CERT_CREATOR`. When set to `"auto"`, it will select either option, preferring `mkcert` if possible.

.. column::

    ```python
    app.config.LOCAL_CERT_CREATOR = "auto"
    app.config.LOCAL_CERT_CREATOR = "mkcert"
    app.config.LOCAL_CERT_CREATOR = "trustme"
    ```

.. column::

    Automatic TLS can be enabled at Sanic server run time:

.. column::

    ```sh
    sanic path.to.server:app --auto-tls --debug
    ```

.. warning:: 

    Localhost TLS certificates (like those generated by both `mkcert` and `trustme`) are **NOT** suitable for production environments. If you are not familiar with how to obtain a *real* TLS certificate, checkout the [How to...](../how-to/tls.md) section.

*Added in v22.6*

---

### Guide Content En Guide Running Inspector (`guide/content/en/guide/running/inspector.md`)

# Inspector

The Sanic Inspector is a feature of Sanic Server. It is *only* available when running Sanic with the built-in [worker manager](./manager.md).

It is an HTTP application that *optionally* runs in the background of your application to allow you to interact with the running instance of your application.


.. tip:: INFO

    The Inspector was introduced in limited capacity in v22.9, but the documentation on this page assumes you are using v22.12 or higher.


## Getting Started

The inspector is disabled by default. To enable it, you have two options.

.. column::

    Set a flag when creating your application instance.

.. column::

    ```python
    app = Sanic("TestApp", inspector=True)
    ```


.. column::

    Or, set a configuration value.

.. column::

    ```python
    app = Sanic("TestApp")
    app.config.INSPECTOR = True
    ```



.. warning:: 

    If you are using the configuration value, it *must* be done early and before the main worker process starts. This means that it should either be an environment variable, or it should be set shortly after creating the application instance as shown above.



## Using the Inspector

Once the inspector is running, you will have access to it via the CLI or by directly accessing its web API via HTTP.

.. column::

    **Via CLI**
    ```sh
    sanic inspect
    ```

.. column::

    **Via HTTP**
    ```sh
    curl http://localhost:6457
    ```



.. note:: 

    Remember, the Inspector is not running on your Sanic application. It is a seperate process, with a seperate application, and exposed on a seperate socket.



## Built-in Commands

The Inspector comes with the following built-in commands. 

| CLI Command        | HTTP Action                        | Description                                                              |
|--------------------|------------------------------------|--------------------------------------------------------------------------|
| `inspect`          | `GET /`                            | Display basic details about the running application.                     |
| `inspect reload`   | `POST /reload`                     | Trigger a reload of all server workers.                                  |
| `inspect shutdown` | `POST /shutdown`                   | Trigger a shutdown of all processes.                                     |
| `inspect scale N`  | `POST /scale`<br>`{"replicas": N}` | Scale the number of workers. Where `N` is the target number of replicas. |

## Custom Commands

The Inspector is easily extendable to add custom commands (and endpoints).

.. column::

    Subclass the `Inspector` class and create arbitrary methods. As long as the method name is not preceded by an underscore (`_`), then the name of the method will be a new subcommand on the inspector.

.. column::

    ```python
    from sanic import json
    from sanic.worker.inspector import Inspector

    class MyInspector(Inspector):
        async def something(self, *args, **kwargs):
            print(args)
            print(kwargs)

    app = Sanic("TestApp", inspector_class=MyInspector, inspector=True)
    ```

This will expose custom methods in the general pattern:

- CLI: `sanic inspect <method_name>`
- HTTP: `POST /<method_name>`

It is important to note that the arguments that the new method accepts are derived from how you intend to use the command. For example, the above `something` method accepts all positional and keyword based parameters.

.. column::

    In the CLI, the positional and keyword parameters are passed as either positional or keyword arguments to your method. All values will be a `str` with the following exceptions:

    - A keyword parameter with no assigned value will be: `True`
    - Unless the parameter is prefixed with `no-`, then it will be: `False`

.. column::

    ```sh
    sanic inspect something one two three --four --no-five --six=6
    ```
    In your application log console, you will see:
    ```
    ('one', 'two', 'three')
    {'four': True, 'five': False, 'six': '6'}
    ```


.. column::

    The same can be achieved by hitting the API directly. You can pass arguments to the method by exposing them in a JSON payload. The only thing to note is that the positional arguments should be exposed as `{"args": [...]}`.

.. column::

    ```sh
    curl http://localhost:6457/something \
      --json '{"args":["one", "two", "three"], "four":true, "five":false, "six":6}'
    ```
    In your application log console, you will see:
    ```
    ('one', 'two', 'three')
    {'four': True, 'five': False, 'six': 6}
    ```


## Using in production


.. danger:: 

    Before exposing the Inspector on a product, please consider all of the options in this section carefully.


When running Inspector on a remote production instance, you can protect the endpoints by requiring TLS encryption, and requiring API key authentication.

### TLS encryption

.. column::

    To the Inspector HTTP instance over TLS, pass the paths to your certificate and key.

.. column::

    ```python
    app.config.INSPECTOR_TLS_CERT = "/path/to/cert.pem"
    app.config.INSPECTOR_TLS_KEY = "/path/to/key.pem"
    ```


.. column::

    This will require use of the `--secure` flag, or `https://`.

.. column::

    ```sh
    sanic inspect --secure --host=<somewhere>
    ```
    ```sh
    curl https://<somewhere>:6457
    ```

### API Key Authentication

.. column::

    You can secure the API with bearer token authentication.

.. column::

    ```python
    app.config.INSPECTOR_API_KEY = "Super-Secret-200"
    ```


.. column::

    This will require the `--api-key` parameter, or bearer token authorization header.

.. column::

    ```sh
    sanic inspect --api-key=Super-Secret-200
    ```
    ```sh
    curl http://localhost:6457  -H "Authorization: Bearer Super-Secret-200"
    ```

## Configuration

See [configuration](./configuration.md)

---

### Guide Content En Guide Running Manager (`guide/content/en/guide/running/manager.md`)

---
title: Worker Manager
---

# Worker Manager

The worker manager and its functionality was introduced in version 22.9.

*The details of this section are intended for more advanced usages and **not** necessary to get started.*

The purpose of the manager is to create consistency and flexibility between development and production environments. Whether you intend to run a single worker, or multiple workers, whether with, or without auto-reload: the experience will be the same.

In general it looks like this:



When you run Sanic, the main process instantiates a `WorkerManager`. That manager is in charge of running one or more `WorkerProcess`. There generally are two kinds of processes:

- server processes, and
- non-server processes.

For the sake of ease, the User Guide generally will use the term "worker" or "worker process" to mean a server process, and "Manager" to mean the single worker manager running in your main process.

## How Sanic Server starts processes

Sanic will start processes using the [spawn](https://docs.python.org/3/library/multiprocessing.html#contexts-and-start-methods) start method. This means that for every process/worker, the global scope of your application will be run on its own thread. The practical impact of this that *if* you do not run Sanic with the CLI, you will need to nest the execution code inside a block to make sure it only runs on `__main__`.

```python
if __name__ == "__main__":
    app.run()
```

If you do not, you are likely to see an error message like this:

```
sanic.exceptions.ServerError: Sanic server could not start: [Errno 98] Address already in use.

This may have happened if you are running Sanic in the global scope and not inside of a `if __name__ == "__main__"` block.

See more information: https://sanic.dev/en/guide/deployment/manager.html#how-sanic-server-starts-processes
```

The likely fix for this problem is nesting your Sanic run call inside of the `__name__ == "__main__"` block. If you continue to receive this message after nesting, or if you see this while using the CLI, then it means the port you are trying to use is not available on your machine and you must select another port.

### Starting a worker

All worker processes *must* send an acknowledgement when starting. This happens under the hood, and you as a developer do not need to do anything. However, the Manager will exit with a status code `1` if one or more workers do not send that `ack` message, or a worker process throws an exception while trying to start. If no exceptions are encountered, the Manager will wait for up to thirty (30) seconds for the acknowledgement.

.. column::

    In the situation when you know that you will need more time to start, you can monkeypatch the Manager. The threshold does not include anything inside of a listener, and is limited to the execution time of everything in the global scope of your application.

    If you run into this issue, it may indicate a need to look deeper into what is causing the slow startup.

.. column::

    ```python
    from sanic.worker.manager import WorkerManager

    WorkerManager.THRESHOLD = 100  # Value is in 0.1s
    ```

See [worker ack](#worker-ack) for more information.

.. column::

    As stated above, Sanic will use [spawn](https://docs.python.org/3/library/multiprocessing.html#contexts-and-start-methods) to start worker processes. If you would like to change this behavior and are aware of the implications of using different start methods, you can modify as shown here.

.. column::

    ```python
    from sanic import Sanic

    Sanic.start_method = "fork"
    ```


### Worker ack

When all of your workers are running in a subprocess a potential problem is created: deadlock. This can occur when the child processes cease to function, but the main process is unaware that this happened. Therefore, Sanic servers will automatically send an `ack` message (short for acknowledge) to the main process after startup.

In version 22.9, the `ack` timeout was short and limited to `5s`. In version 22.12, the timeout was lengthened to `30s`. If your application is shutting down after thirty seconds then it might be necessary to manually increase this threshhold.

.. column::

    The value of `WorkerManager.THRESHOLD` is in `0.1s` increments. Therefore, to set it to one minute, you should set the value to `600`.

    This value should be set as early as possible in your application, and should ideally happen in the global scope.  Setting it after the main process has started will not work.

.. column::

    ```python
    from sanic.worker.manager import WorkerManager

    WorkerManager.THRESHOLD = 600
    ```

### Zero downtime restarts

By default, when restarting workers, Sanic will teardown the existing process first before starting a new one. 

If you are intending to use the restart functionality in production then you may be interested in having zero-downtime reloading. This can be accomplished by forcing the reloader to change the order to start a new process, wait for it to [ack](#worker-ack), and then teardown the old process.

.. column::

    From the multiplexer, use the `zero_downtime` argument

.. column::

    ```python
    app.m.restart(zero_downtime=True)
    ```

*Added in v22.12*

## Using shared context between worker processes

Python provides a few methods for [exchanging objects](https://docs.python.org/3/library/multiprocessing.html#exchanging-objects-between-processes), [synchronizing](https://docs.python.org/3/library/multiprocessing.html#synchronization-between-processes), and [sharing state](https://docs.python.org/3/library/multiprocessing.html#sharing-state-between-processes) between processes. This usually involves objects from the `multiprocessing` and `ctypes` modules.

If you are familiar with these objects and how to work with them, you will be happy to know that Sanic provides an API for sharing these objects between your worker processes. If you are not familiar, you are encouraged to read through the Python documentation linked above and try some of the examples before proceeding with implementing shared context.

Similar to how [application context](../basics/app.md#application-context) allows an applicaiton to share state across the lifetime of the application with `app.ctx`, shared context provides the same for the special objects mentioned above. This context is available as `app.shared_ctx` and should **ONLY** be used to share objects intended for this purpose.

The `shared_ctx` will:

- *NOT* share regular objects like `int`, `dict`, or `list`
- *NOT* share state between Sanic instances running on different machines
- *NOT* share state to non-worker processes
- **only** share state between server workers managed by the same Manager

Attaching an inappropriate object to `shared_ctx` will likely result in a warning, and not an error. You should be careful to not accidentally add an unsafe object to `shared_ctx` as it may not work as expected. If you are directed here because of one of those warnings, you might have accidentally used an unsafe object in `shared_ctx`.

.. column::

    In order to create a shared object you **must** create it in the main process and attach it inside of the `main_process_start` listener.

.. column::

    ```python
    from multiprocessing import Queue

    @app.main_process_start
    async def main_process_start(app):
        app.shared_ctx.queue = Queue()
    ```

Trying to attach to the `shared_ctx` object outside of this listener may result in a `RuntimeError`.

.. column::

    After creating the objects in the `main_process_start` listener and attaching to the `shared_ctx`, they will be available in your workers wherever the application instance is available (example: listeners, middleware, request handlers).

.. column::

    ```python
    from multiprocessing import Queue

    @app.get("")
    async def handler(request):
        request.app.shared_ctx.queue.put(1)
        ...
    ```

## Access to the multiplexer

The application instance has access to an object that provides access to interacting with the Manager and other worker processes. The object is attached as the `app.multiplexer` property, but it is more easily accessed by its alias: `app.m`.

.. column::

    For example, you can get access to the current worker state.

.. column::

    ```python
    @app.on_request
    async def print_state(request: Request):
        print(request.app.m.name)
        print(request.app.m.pid)
        print(request.app.m.state)
    ```
    ```
    Sanic-Server-0-0
    99999
    {'server': True, 'state': 'ACKED', 'pid': 99999, 'start_at': datetime.datetime(2022, 10, 1, 0, 0, 0, 0, tzinfo=datetime.timezone.utc), 'starts': 2, 'restart_at': datetime.datetime(2022, 10, 1, 0, 0, 12, 861332, tzinfo=datetime.timezone.utc)}
    ```


.. column::

    The `multiplexer` also has access to terminate the Manager, or restart worker processes

.. column::

    ```python
    # shutdown the entire application and all processes
    app.m.name.terminate()

    # restart the current worker only
    app.m.name.restart()

    # restart specific workers only (comma delimited)
    app.m.name.restart("Sanic-Server-4-0,Sanic-Server-7-0")

    # restart ALL workers
    app.m.name.restart(all_workers=True)  # Available v22.12+
    ```

## Worker state

.. column::

    As shown above, the `multiplexer` has access to report upon the state of the current running worker. However, it also contains the state for ALL processes running.

.. column::

    ```python
    @app.on_request
    async def print_state(request: Request):
        print(request.app.m.workers)
    ```
    ```
    {
        'Sanic-Main': {'pid': 99997},
        'Sanic-Server-0-0': {
            'server': True,
            'state': 'ACKED',
            'pid': 9999,
            'start_at': datetime.datetime(2022, 10, 1, 0, 0, 0, 0, tzinfo=datetime.timezone.utc),
            'starts': 2,
            'restart_at': datetime.datetime(2022, 10, 1, 0, 0, 12, 861332, tzinfo=datetime.timezone.utc)
        },
        'Sanic-Reloader-0': {
            'server': False,
            'state': 'STARTED',
            'pid': 99998,
            'start_at': datetime.datetime(2022, 10, 1, 0, 0, 0, 0, tzinfo=datetime.timezone.utc),
            'starts': 1
        }
    }
    ```

The possible states are:

- `NONE` - The worker has been created, but there is no process yet
- `IDLE` - The process has been created, but is not running yet
- `STARTING` - The process is starting
- `STARTED` - The process has started
- `ACKED` - The process has started and sent an acknowledgement (usually only for server processes)
- `JOINED` - The process has exited and joined the main process
- `TERMINATED` - The process has exited and terminated
- `RESTARTING` - The process is restarting
- `FAILED` - The process encountered an exception and is no longer running
- `COMPLETED` - The process has completed its work and exited successfully

## Built-in non-server processes

As mentioned, the Manager also has the ability to run non-server processes. Sanic comes with two built-in types of non-server processes, and allows for [creating custom processes](#running-custom-processes).

The two built-in processes are

- the [auto-reloader](./development.md#automatic-reloader), optionally enabled to watch the file system for changes and trigger a restart
- [inspector](#inspector), optionally enabled to provide external access to the state of the running instance

## Inspector

Sanic has the ability to expose the state and the functionality of the `multiplexer` to the CLI. Currently, this requires the CLI command to be run on the same machine as the running Sanic instance. By default the inspector is disabled.

.. column::

    To enable it, set the config value to `True`.

.. column::

    ```python
    app.config.INSPECTOR = True
    ```

You will now have access to execute any of these CLI commands:

```
sanic inspect reload                      Trigger a reload of the server workers
sanic inspect shutdown                    Shutdown the application and all processes
sanic inspect scale N                     Scale the number of workers to N
sanic inspect <custom>                    Run a custom command
```



.. column::

    This works by exposing a small HTTP service on your machine. You can control the location using configuration values:

.. column::

    ```python
    app.config.INSPECTOR_HOST =  "localhost"
    app.config.INSPECTOR_PORT =  6457
    ```

[Learn more](./inspector.md) to find out what is possible with the Inspector.

## Running custom processes

To run a managed custom process on Sanic, you must create a callable. If that process is meant to be long-running, then it should handle a shutdown call by a `SIGINT` or `SIGTERM` signal.

.. column::

    The simplest method for doing that in Python will be to just wrap your loop in `KeyboardInterrupt`.

    If you intend to run another application, like a bot, then it is likely that it already has capability to handle this signal and you likely do not need to do anything.

.. column::

    ```python
    from time import sleep

    def my_process(foo):
        try:
            while True:
                sleep(1)
        except KeyboardInterrupt:
            print("done")
    ```


.. column::

    That callable must be registered in the `main_process_ready` listener. It is important to note that is is **NOT** the same location that you should register [shared context](#using-shared-context-between-worker-processes) objects.

.. column::

    ```python
    @app.main_process_ready
    async def ready(app: Sanic, _):
    #   app.manager.manage(<name>, <callable>, <kwargs>)
        app.manager.manage("MyProcess", my_process, {"foo": "bar"})
    ```

### Transient v. durable processes

.. column::

    When you manage a process with the `manage` method, you have the option to make it transient or durable. A transient process will be restarted by the auto-reloader, and a durable process will not.
    
    By default, all processes are durable.
    
.. column::

    ```python
    @app.main_process_ready
    async def ready(app: Sanic, _):
        app.manager.manage(
            "MyProcess",
            my_process,
            {"foo": "bar"},
            transient=True,
        )
    ```


### Tracked v. untracked processes

Out of the box, Sanic will track the state of all processes. This means that you can access the state of the process from the [multiplexer](./manager.md#access-to-the-multiplexer) object, or from the [Inspector](./manager.md#inspector).

See [worker state](./manager.md#worker-state) for more information.
    
Sometimes it is helpful to run background processes that are not long-running. You run them once until completion and then they exit. Upon completion, they will either be in `FAILED` or `COMPLETED` state.
    
.. column::

    When you are running a non-long-running process, you can opt out of tracking it by setting `tracked=False` in the `manage` method. This means that upon completion of the process it will be removed from the list of tracked processes. You will only be able to check the state of the process while it is running.
    
.. column::

    ```python
    @app.main_process_ready
    async def ready(app: Sanic, _):
        app.manager.manage(
            "OneAndDone",
            do_once,
            {},
            tracked=False,
        )
    ```

*Added in v23.12*

### Restartable custom processes

A custom process that is transient will **always** be restartable. That means the auto-restart will work as expected. However, what if you want to be able to *manually* restart a process, but not have it be restarted by the auto-reloader?
    
.. column::

    In this scenario, you can set `restartable=True` in the `manage` method. This will allow you to manually restart the process, but it will not be restarted by the auto-reloader.
    
.. column::

    ```python
    @app.main_process_ready
    async def ready(app: Sanic, _):
        app.manager.manage(
            "MyProcess",
            my_process,
            {"foo": "bar"},
            restartable=True,
        )
    ```
    
.. column::

    You could now manually restart that process from the multiplexer.
    
.. column::

    ```python
    @app.get("/restart")
    async def restart_handler(request: Request):
        request.app.m.restart("Sanic-MyProcess-0")
        return json({"foo": request.app.m.name})
    ```
    
*Added in v23.12*

### On the fly process management

Custom processes are usually added in the `main_process_ready` listener. However, there may be times when you want to add a process after the application has started. For example, you may want to add a process from a request handler. The multiplexer provides a method for doing this.
    
.. column::

    Once you have a reference to the multiplexer, you can call `manage` to add a process. It works the same as the `manage` method on the Manager.
    
.. column::

    ```python
    @app.post("/start")
    async def start_handler(request: Request):
        request.app.m.manage(
            "MyProcess",
            my_process,
            {"foo": "bar"},
            workers=2,
        )
        return json({"foo": request.app.m.name})
    ```
    
*Added in v23.12*

## Single process mode

.. column::

    If you would like to opt out of running multiple processes, you can run Sanic in a single process only. In this case, the Manager will not run. You will also not have access to any features that require processes (auto-reload, the inspector, etc).

.. column::

    ```sh
    sanic path.to.server:app --single-process
    ```
    ```python
    if __name__ == "__main__":
        app.run(single_process=True)
    ```
    ```python
    if __name__ == "__main__":
        app.prepare(single_process=True)
        Sanic.serve_single()
    ```

## Sanic and multiprocessing

Sanic makes heavy use of the [`multiprocessing` module](https://docs.python.org/3/library/multiprocessing.html) to manage the worker processes. You should generally avoid lower level usage of this module (like setting the start method) as it may interfere with the functionality of Sanic.

### Start methods in Python

Before explaining what Sanic tries to do, it is important to understand what the `start_method` is and why it is important. Python generally allows for three different methods of starting a process:

- `fork`
- `spawn`
- `forkserver`

The `fork` and `forkserver` methods are only available on Unix systems, and `spawn` is the only method available on Windows. On Unix systems where you have a choice, `fork` is generally the default system method.

You are encouraged to read the [Python documentation](https://docs.python.org/3/library/multiprocessing.html#contexts-and-start-methods) to learn more about the differences between these methods. However, the important thing to know is that `fork` basically copies the entire memory of the parent process into the child process, whereas `spawn` will create a new process and then load the application into that process. This is the reason why you need to nest your Sanic `run` call inside of the `__name__ == "__main__"` block if you are not using the CLI.

### Sanic and start methods

By default, Sanic will try and use `spawn` as the start method. This is because it is the only method available on Windows, and it is the safest method on Unix systems. 

.. column::

    However, if you are running Sanic on a Unix system and you would like to use `fork` instead, you can do so by setting the `start_method` on the `Sanic` class. You will want to do this as early as possible in your application, and ideally in the global scope before you import any other modules.

.. column::

    ```python
    from sanic import Sanic
    
    Sanic.start_method = "fork"
    ```

### Overcoming a `RuntimeError`

You might have received a `RuntimeError` that looks like this:

```
RuntimeError: Start method 'spawn' was requested, but 'fork' was already set.
```

If so, that means somewhere in your application you are trying to set the start method that conflicts with what Sanic is trying to do. You have a few options to resolve this:

.. column::

    **OPTION 1:** You can tell Sanic that the start method has been set and to not try and set it again.

.. column::

    ```python
    from sanic import Sanic

    Sanic.START_METHOD_SET = True
    ```

.. column::

    **OPTION 2:** You could tell Sanic that you intend to use `fork` and to not try and set it to `spawn`.

.. column::

    ```python
    from sanic import Sanic

    Sanic.start_method = "fork"
    ```

.. column::

    **OPTION 3:** You can tell Python to use `spawn` instead of `fork` by setting the `multiprocessing` start method.

.. column::

    ```python
    import multiprocessing

    multiprocessing.set_start_method("spawn")
    ```

In any of these options, you should run this code as early as possible in your application. Depending upon exactly what your specific scenario is, you may need to combine some of the options.

.. note::

    The potential issues that arise from this problem are usually easily solved by just allowing Sanic to be in charge of multiprocessing. This usually means making use of the `main_process_start` and `main_process_ready` listeners to deal with multiprocessing issues. For example, you should move instantiating multiprocessing primitives that do a lot of work under the hood from the global scope and into a listener.
    
    ```python
    # This is BAD; avoid the global scope
    from multiprocessing import Queue
    
    q = Queue()
    ```
    
    ```python
    # This is GOOD; the queue is made in a listener and shared to all the processes on the shared_ctx
    from multiprocessing import Queue

    @app.main_process_start
    async def main_process_start(app):
        app.shared_ctx.q = Queue()
    ```

---

### Guide Content En Guide Running Running (`guide/content/en/guide/running/running.md`)

---
title: Running Sanic
---

# Running Sanic

Sanic ships with its own internal web server. Under most circumstances, this is the preferred method for deployment. In addition, you can also deploy Sanic as an ASGI app bundled with an ASGI-able web server.

## Sanic Server

The main way to run Sanic is to use the included [CLI](#sanic-cli).

```sh
sanic path.to.server:app
```

In this example, Sanic is instructed to look for a python module called `path.to.server`. Inside of that module, it will look for a global variable called `app`, which should be an instance of `Sanic(...)`.

```python
# ./path/to/server.py
from sanic import Sanic, Request, json

app = Sanic("TestApp")

@app.get("/")
async def handler(request: Request):
    return json({"foo": "bar"})
```

You may also dropdown to the [lower level API](#low-level-apprun) to call `app.run` as a script. However, if you choose this option you should be more comfortable handling issues that may arise with `multiprocessing`.

### Workers

.. column::

    By default, Sanic runs a main process and a single worker process (see [worker manager](./manager.md) for more details).

    To crank up the juice, just specify the number of workers in the run arguments.

.. column::

    ```sh
    sanic server:app --host=0.0.0.0 --port=1337 --workers=4
    ```

Sanic will automatically spin up multiple processes and route traffic between them. We recommend as many workers as you have available processors.

.. column::

    The easiest way to get the maximum CPU performance is to use the `--fast` option. This will automatically run the maximum number of workers given the system constraints.

    *Added in v21.12*

.. column::

    ```sh
    sanic server:app --host=0.0.0.0 --port=1337 --fast
    ```

In version 22.9, Sanic introduced a new worker manager to provide more consistency and flexibility between development and production servers. Read [about the manager](./manager.md) for more details about workers.

.. column::

    If you only want to run Sanic with a single process, specify `single_process` in the run arguments. This means that auto-reload, and the worker manager will be unavailable.

    *Added in v22.9*

.. column::

    ```sh
    sanic server:app --host=0.0.0.0 --port=1337 --single-process
    ```

### Running via command

#### Sanic CLI

Use `sanic --help` to see all the options.


.. attrs::
    :title: Sanic CLI help output
    :class: details

    ```
/* Detailed source-code truncated for AI context efficiency. */
```


#### As a module

.. column::

    Sanic applications can also be called directly as a module.

.. column::

    ```bash
    python -m sanic server.app --host=0.0.0.0 --port=1337 --workers=4
    ```

#### Using a factory

A very common solution is to develop your application *not* as a global variable, but instead using the factory pattern. In this context, "factory" means a function that returns an instance of `Sanic(...)`.

.. column::

    Suppose that you have this in your `server.py`

.. column::

    ```python
    from sanic import Sanic

    def create_app() -> Sanic:
        app = Sanic("MyApp")

        return app
    ```


.. column::

    You can run this application now by referencing it in the CLI explicitly as a factory:

.. column::

    ```sh
    sanic server:create_app --factory
    ```
    Or, explicitly like this:
    ```sh
    sanic "server:create_app()"
    ```
    Or, implicitly like this:
    ```sh
    sanic server:create_app
    ```

    *Implicit command added in v23.3*

### Low level `app.run`

When using `app.run` you will just call your Python file like any other script.

.. column::

    `app.run` must be properly nested inside of a name-main block.

.. column::

    ```python
    # server.py
    app = Sanic("MyApp")

    if __name__ == "__main__":
        app.run()
    ```



.. danger:: 

    Be *careful* when using this pattern. A very common mistake is to put too much logic inside of the `if __name__ == "__main__":` block.

    🚫 This is a mistake

    ```python
    from sanic import Sanic
    from my.other.module import bp

    app = Sanic("MyApp")

    if __name__ == "__main__":
        app.blueprint(bp)
        app.run()
    ```

    If you do this, your [blueprint](../best-practices/blueprints.md) will not be attached to your application. This is because the `__main__` block will only run on Sanic's main worker process, **NOT** any of its [worker processes](../deployment/manager.md). This goes for anything else that might impact your application (like attaching listeners, signals, middleware, etc). The only safe operations are anything that is meant for the main process, like the `app.main_*` listeners.

    Perhaps something like this is more appropriate:

    ```python
    from sanic import Sanic
    from my.other.module import bp

    app = Sanic("MyApp")

    if __name__ == "__mp_main__":
        app.blueprint(bp)
    elif __name__ == "__main__":
        app.run()
    ```


To use the low-level `run` API, after defining an instance of `sanic.Sanic`, we can call the run method with the following keyword arguments:

|       Parameter       |     Default      |                                           Description                                     |
| :-------------------: | :--------------: | :---------------------------------------------------------------------------------------- |
|  **host**             | `"127.0.0.1"`    | Address to host the server on.                                                            |
|  **port**             | `8000`           | Port to host the server on.                                                               |
|  **unix**             | `None`           | Unix socket name to host the server on (instead of TCP).                                  |
|  **dev**              | `False`          | Equivalent to `debug=True` and `auto_reload=True`.                                        |
|  **debug**            | `False`          | Enables debug output (slows server).                                                      |
|  **ssl**              | `None`           | SSLContext for SSL encryption of worker(s).                                               |
|  **sock**             | `None`           | Socket for the server to accept connections from.                                         |
|  **workers**          | `1`              | Number of worker processes to spawn. Cannot be used with fast.                            |
|  **loop**             | `None`           | An asyncio-compatible event loop. If none is specified, Sanic creates its own event loop. |
|  **protocol**         | `HttpProtocol`   | Subclass of asyncio.protocol.                                                             |
|  **version**          | `HTTP.VERSION_1` | The HTTP version to use (`HTTP.VERSION_1` or `HTTP.VERSION_3`).                           |
|  **access_log**       | `True`           | Enables log on handling requests (significantly slows server).                            |
|  **auto_reload**      | `None`           | Enables auto-reload on the source directory.                                              |
|  **reload_dir**       | `None`           | A path or list of paths to directories the auto-reloader should watch.                    |
|  **noisy_exceptions** | `None`           | Whether to set noisy exceptions globally. None means leave as default.                    |
|  **motd**             | `True`           | Whether to display the startup message.                                                   |
|  **motd_display**     | `None`           | A dict with extra key/value information to display in the startup message                 |
|  **fast**             | `False`          | Whether to maximize worker processes.  Cannot be used with workers.                       |
|  **verbosity**        | `0`              | Level of logging detail. Max is 2.                                                        |
|  **auto_tls**         | `False`          | Whether to auto-create a TLS certificate for local development. Not for production.       |
|  **single_process**   | `False`          | Whether to run Sanic in a single process.                                                 |

.. column::

    For example, we can turn off the access log in order to increase performance, and bind to a custom host and port.

.. column::

    ```python
    # server.py
    app = Sanic("MyApp")

    if __name__ == "__main__":
        app.run(host='0.0.0.0', port=1337, access_log=False)
    ```


.. column::

    Now, just execute the python script that has `app.run(...)`

.. column::

    ```sh
    python server.py
    ```

For a slightly more advanced implementation, it is good to know that `app.run` will call `app.prepare` and `Sanic.serve` under the hood.

.. column::

    Therefore, these are equivalent:

.. column::

    ```python
    if __name__ == "__main__":
        app.run(host='0.0.0.0', port=1337, access_log=False)
    ```
    ```python
    if __name__ == "__main__":
        app.prepare(host='0.0.0.0', port=1337, access_log=False)
        Sanic.serve()
    ```

.. column::

    This can be useful if you need to bind your appliction(s) to multiple ports.

.. column::

    ```python
    if __name__ == "__main__":
        app1.prepare(host='0.0.0.0', port=9990)
        app1.prepare(host='0.0.0.0', port=9991)
        app2.prepare(host='0.0.0.0', port=5555)
        Sanic.serve()
    ```

### Sanic Simple Server

.. column::

    Sometimes you just have a directory of static files that need to be served. This especially can be handy for quickly standing up a localhost server. Sanic ships with a Simple Server, where you only need to point it at a directory.

.. column::

    ```sh
    sanic ./path/to/dir --simple
    ```


.. column::

    This could also be paired with auto-reloading.

.. column::

    ```sh
    sanic ./path/to/dir --simple --reload --reload-dir=./path/to/dir
    ```

*Added in v21.6*

### Daemon mode

.. new:: New in v25.12

    This feature was added in version 25.12

.. column::

    Sanic can run as a background daemon process. Use the `-D` or `--daemon` flag to start the server in the background.

.. column::

    ```sh
    sanic path.to.server:app --daemon
    sanic path.to.server:app -D
    ```

.. column::

    You can manage the daemon with additional commands:

.. column::

    ```sh
    sanic path.to.server:app status   # Check if running
    sanic path.to.server:app stop     # Stop the daemon
    ```

.. column::

    Additional options are available for daemon configuration:

.. column::

    ```sh
    sanic path.to.server:app -D --pidfile=/var/run/sanic.pid
    sanic path.to.server:app -D --logfile=/var/log/sanic.log
    sanic path.to.server:app -D --user=www-data
    sanic path.to.server:app -D --group=www-data
    ```

Lower-level commands are also available to manage processes by PID:

```sh
sanic kill --pid=<PID>
sanic kill --pidfile=/var/run/sanic.pid
sanic status --pid=<PID>
sanic status --pidfile=/var/run/sanic.pid
```

*Added in v25.12*

### HTTP/3

Sanic server offers HTTP/3 support using [aioquic](https://github.com/aiortc/aioquic). This **must** be installed to use HTTP/3:

```sh
pip install sanic aioquic
```

```sh
pip install sanic[http3]
```

To start HTTP/3, you must explicitly request it when running your application.

.. column::

    ```sh
    sanic path.to.server:app --http=3
    ```

    ```sh
    sanic path.to.server:app -3
    ```

.. column::

    ```python
    app.run(version=3)
    ```

To run both an HTTP/3 and HTTP/1.1 server simultaneously, you can use [application multi-serve](../../release-notes/2022/v22.3.md#application-multi-serve) introduced in v22.3. This will automatically add an [Alt-Svc](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Alt-Svc) header to your HTTP/1.1 requests to let the client know that it is also available as HTTP/3.


.. column::

    ```sh
    sanic path.to.server:app --http=3 --http=1
    ```

    ```sh
    sanic path.to.server:app -3 -1
    ```

.. column::

    ```python
    app.prepare(version=3)
    app.prepare(version=1)
    Sanic.serve()
    ```

Because HTTP/3 requires TLS, you cannot start a HTTP/3 server without a TLS certificate. You should [set it up yourself](../how-to/tls.md) or use `mkcert` if in `DEBUG` mode. Currently, automatic TLS setup for HTTP/3 is not compatible with `trustme`. See [development](./development.md) for more details.

*Added in v22.6*

## ASGI

Sanic is also ASGI-compliant. This means you can use your preferred ASGI webserver to run Sanic. The three main implementations of ASGI are [Daphne](http://github.com/django/daphne), [Uvicorn](https://www.uvicorn.org/), and [Hypercorn](https://pgjones.gitlab.io/hypercorn/index.html).


.. warning:: 

    Daphne does not support the ASGI `lifespan` protocol, and therefore cannot be used to run Sanic. See [Issue #264](https://github.com/django/daphne/issues/264) for more details.



Follow their documentation for the proper way to run them, but it should look something like:

```sh
uvicorn myapp:app
```
```sh
hypercorn myapp:app
```

A couple things to note when using ASGI:

1. When using the Sanic webserver, websockets will run using the `websockets` package. In ASGI mode, there is no need for this package since websockets are managed in the ASGI server. 
2. The ASGI lifespan protocol <https://asgi.readthedocs.io/en/latest/specs/lifespan.html>, supports only two server events: startup and shutdown. Sanic has four: before startup, after startup, before shutdown, and after shutdown. Therefore, in ASGI mode, the startup and shutdown events will run consecutively and not actually around the server process beginning and ending (since that is now controlled by the ASGI server). Therefore, it is best to use `after_server_start` and `before_server_stop`.

### Trio

Sanic has experimental support for running on Trio with:

```sh
hypercorn -k trio myapp:app
```

## Gunicorn

[Gunicorn](http://gunicorn.org/) ("Green Unicorn") is a WSGI HTTP Server for UNIX based operating systems. It is a pre-fork worker model ported from Ruby’s Unicorn project.

In order to run Sanic application with Gunicorn, you need to use it with the adapter from [uvicorn](https://www.uvicorn.org/). Make sure uvicorn is installed and run it with `uvicorn.workers.UvicornWorker` for Gunicorn worker-class argument:

```sh
gunicorn myapp:app --bind 0.0.0.0:1337 --worker-class uvicorn.workers.UvicornWorker
```

See the [Gunicorn Docs](http://docs.gunicorn.org/en/latest/settings.html#max-requests) for more information.


.. warning:: 

    It is generally advised to not use `gunicorn` unless you need it. The Sanic Server is primed for running Sanic in production. Weigh your considerations carefully before making this choice. Gunicorn does provide a lot of configuration options, but it is not the best choice for getting Sanic to run at its fastest.



## Performance considerations

.. column::

    When running in production, make sure you turn off `debug`.

.. column::

    ```sh
    sanic path.to.server:app
    ```


.. column::

    Sanic will also perform fastest if you turn off `access_log`.

    If you still require access logs, but want to enjoy this performance boost, consider using [Nginx as a proxy](./../deployment/nginx.md), and letting that handle your access logging. It will be much faster than anything Python can handle.

.. column::

    ```sh
    sanic path.to.server:app --no-access-logs
    ```

---

### Guide Content En Plugins Sanic Ext Configuration (`guide/content/en/plugins/sanic-ext/configuration.md`)

---
title: Sanic Extensions - Configuration
---

# Configuration

Sanic Extensions can be configured in all of the same ways that [you can configure Sanic](../../guide/running/configuration.md). That makes configuring Sanic Extensions very easy.

```python
app = Sanic("MyApp")
app.config.OAS_URL_PREFIX = "/apidocs"
```

However, there are a few more configuration options that should be considered.

## Manual `extend`

.. column:: 

    Even though Sanic Extensions will automatically attach to your application, you can manually choose `extend`. When you do that, you can pass all of the configuration values as a keyword arguments (lowercase).

.. column:: 

    ```python
    app = Sanic("MyApp")
    app.extend(oas_url_prefix="/apidocs")
    ```

.. column:: 

    Or, alternatively they could be passed all at once as a single `dict`.

.. column:: 

    ```python
    app = Sanic("MyApp")
    app.extend(config={"oas_url_prefix": "/apidocs"})
    ```

.. column:: 

    Both of these solutions suffers from the fact that the names of the configuration settings are not discoverable by an IDE. Therefore, there is also a type annotated object that you can use. This should help the development experience.

.. column:: 

    ```python
    from sanic_ext import Config

    app = Sanic("MyApp")
    app.extend(config=Config(oas_url_prefix="/apidocs"))
    ```

## Settings

.. note::

    Often, the easiest way to change these for an application (since they likely are not going to change dependent upon an environment), is to set them directly on the `app.config` object.

    Simply use the capitalized version of the configuration key as shown here:

    ```python
    app = Sanic("MyApp")
    app.config.OAS_URL_PREFIX = "/apidocs"
    ```

### `cors`

- **Type**: `bool`
- **Default**: `True`
- **Description**: Whether to enable CORS protection

### `cors_allow_headers`

- **Type**: `str`
- **Default**: `"*"`
- **Description**: Value of the header: `access-control-allow-headers`

### `cors_always_send`

- **Type**: `bool`
- **Default**: `True`
- **Description**: Whether to always send the header: `access-control-allow-origin`

### `cors_automatic_options`

- **Type**: `bool`
- **Default**: `True`
- **Description**: Whether to automatically generate `OPTIONS` endpoints for routes that do *not* already have one defined

### `cors_expose_headers`

- **Type**: `str`
- **Default**: `""`
- **Description**: Value of the header: `access-control-expose-headers`

### `cors_max_age`

- **Type**: `int`
- **Default**: `5`
- **Description**: Value of the header: `access-control-max-age`

### `cors_methods`

- **Type**: `str`
- **Default**: `""`
- **Description**: Value of the header: `access-control-access-control-allow-methods`

### `cors_origins`

- **Type**: `str`
- **Default**: `""`
- **Description**: Value of the header: `access-control-allow-origin`


.. warning:: 
    
    Be very careful if you place `*` here. Do not do this unless you know what you are doing as it can be a security issue.


### `cors_send_wildcard`

- **Type**: `bool`
- **Default**: `False`
- **Description**: Whether to send a wildcard origin instead of the incoming request origin

### `cors_supports_credentials`

- **Type**: `bool`
- **Default**: `False`
- **Description**: Value of the header: `access-control-allow-credentials`

### `cors_vary_header`

- **Type**: `bool`
- **Default**: `True`
- **Description**: Whether to add the `vary` header

### `http_all_methods`

- **Type**: `bool`
- **Default**: `True`
- **Description**: Adds the HTTP `CONNECT` and `TRACE` methods as allowable

### `http_auto_head`

- **Type**: `bool`
- **Default**: `True`
- **Description**: Automatically adds `HEAD` handlers to any `GET` routes

### `http_auto_options`

- **Type**: `bool`
- **Default**: `True`
- **Description**: Automatically adds `OPTIONS` handlers to any routes without

### `http_auto_trace`

- **Type**: `bool`
- **Default**: `False`
- **Description**: Automatically adds `TRACE` handlers to any routes without

### `oas`

- **Type**: `bool`
- **Default**: `True`
- **Description**: Whether to enable OpenAPI specification generation

### `oas_autodoc`

- **Type**: `bool`
- **Default**: `True`
- **Description**: Whether to automatically extract OpenAPI details from the docstring of a route function

### `oas_ignore_head`

- **Type**: `bool`
- **Default**: `True`
- **Description**: WHen `True`, it will not add `HEAD` endpoints into the OpenAPI specification

### `oas_ignore_options`

- **Type**: `bool`
- **Default**: `True`
- **Description**: WHen `True`, it will not add `OPTIONS` endpoints into the OpenAPI specification

### `oas_path_to_redoc_html`

- **Type**: `Optional[str]`
- **Default**: `None`
- **Description**: Path to HTML file to override the existing Redoc HTML

### `oas_path_to_swagger_html`

- **Type**: `Optional[str]`
- **Default**: `None`
- **Description**: Path to HTML file to override the existing Swagger HTML

### `oas_ui_default`

- **Type**: `Optional[str]`
- **Default**: `"redoc"`
- **Description**: Which OAS documentation to serve on the bare `oas_url_prefix` endpoint; when `None` there will be no documentation at that location

### `oas_ui_redoc`

- **Type**: `bool`
- **Default**: `True`
- **Description**: Whether to enable the Redoc UI

### `oas_ui_swagger`

- **Type**: `bool`
- **Default**: `True`
- **Description**: Whether to enable the Swagger UI

### `oas_ui_swagger_version`

- **Type**: `str`
- **Default**: `"4.1.0"`
- **Description**: Which Swagger version to use

### `oas_uri_to_config`

- **Type**: `str`
- **Default**: `"/swagger-config"`
- **Description**: Path to serve the Swagger configuration

### `oas_uri_to_json`

- **Type**: `str`
- **Default**: `"/openapi.json"`
- **Description**: Path to serve the OpenAPI JSON

### `oas_uri_to_redoc`

- **Type**: `str`
- **Default**: `"/redoc"`
- **Description**: Path to Redoc

### `oas_uri_to_swagger`

- **Type**: `str`
- **Default**: `"/swagger"`
- **Description**: Path to Swagger

### `oas_url_prefix`

- **Type**: `str`
- **Default**: `"/docs"`
- **Description**: URL prefix for the Blueprint that all of the OAS documentation witll attach to

### `swagger_ui_configuration`

- **Type**: `Dict[str, Any]`
- **Default**: `{"apisSorter": "alpha", "operationsSorter": "alpha", "docExpansion": "full"}`
- **Description**: The Swagger documentation to be served to the frontend

### `templating_enable_async`

- **Type**: `bool`
- **Default**: `True`
- **Description**: Whether to set `enable_async` on the Jinja `Environment`

### `templating_path_to_templates`

- **Type**: `Union[str, os.PathLike, Sequence[Union[str, os.PathLike]]] `
- **Default**: `templates`
- **Description**: A single path, or multiple paths to where your template files are located

### `trace_excluded_headers`

- **Type**: `Sequence[str]`
- **Default**: `("authorization", "cookie")`
- **Description**: Which headers should be suppresed from responses to `TRACE` requests

---

### Guide Content En Plugins Sanic Ext Convenience (`guide/content/en/plugins/sanic-ext/convenience.md`)

---
title: Sanic Extensions - Convenience
---

# Convenience

## Fixed serializer

.. column::

    Often when developing an application, there will be certain routes that always return the same sort of response. When this is the case, you can predefine the return serializer and on the endpoint, and then all that needs to be returned is the content.

.. column::

    ```python
    from sanic_ext import serializer

    @app.get("/<name>")
    @serializer(text)
    async def hello_world(request, name: str):
        if name.isnumeric():
            return "hello " * int(name)
        return f"Hello, {name}"
    ```



.. column::

    The `serializer` decorator also can add status codes.

.. column::

    ```python
    from sanic_ext import serializer

    @app.post("/")
    @serializer(text, status=202)
    async def create_something(request):
        ...
    ```

## Custom serializer

.. column::

    Using the `@serializer` decorator, you can also pass your own custom functions as long as they also return a valid type (`HTTPResonse`).

.. column::

    ```python
    def message(retval, request, action, status):
        return json(
            {
                "request_id": str(request.id),
                "action": action,
                "message": retval,
            },
            status=status,
        )

    @app.post("/<action>")
    @serializer(message)
    async def do_action(request, action: str):
        return "This is a message"
    ```


.. column::

    Now, returning just a string should return a nice serialized output.

.. column::

    ```python
    $ curl localhost:8000/eat_cookies -X POST
    {
      "request_id": "ef81c45b-235c-46dd-9dbd-b550f8fa77f9",
      "action": "eat_cookies",
      "message": "This is a message"
    }

    ```


## Request counter

.. column::

    Sanic Extensions comes with a subclass of `Request` that can be setup to automatically keep track of the number of requests processed per worker process. To enable this, you should pass the `CountedRequest` class to your application contructor.

.. column::

    ```python
    from sanic_ext import CountedRequest

    app = Sanic(..., request_class=CountedRequest)
    ```


.. column::

    You will now have access to the number of requests served during the lifetime of the worker process.

.. column::

    ```python
    @app.get("/")
    async def handler(request: CountedRequest):
        return json({"count": request.count})
    ```

If possible, the request count will also be added to the [worker state](../../guide/running/manager.md#worker-state).

---

### Guide Content En Plugins Sanic Ext Custom (`guide/content/en/plugins/sanic-ext/custom.md`)

---
title: Sanic Extensions - Custom
---

# Custom extensions

It is possible to create your own custom extensions.

Version 22.9 added the `Extend.register` [method](#extension-preregistration). This makes it extremely easy to add custom expensions to an application.

## Anatomy of an extension

All extensions must subclass `Extension`.

### Required

- `name`: By convention, the name is an all-lowercase string
- `startup`: A method that runs when the extension is added

### Optional

- `label`: A method that returns additional information about the extension in the MOTD
- `included`: A method that returns a boolean whether the extension should be enabled or not (could be used for example to check config state)

### Example

```python
from sanic import Request, Sanic, json
from sanic_ext import Extend, Extension

app = Sanic(__name__)
app.config.MONITOR = True

class AutoMonitor(Extension):
    name = "automonitor"

    def startup(self, bootstrap) -> None:
        if self.included():
            self.app.before_server_start(self.ensure_monitor_set)
            self.app.on_request(self.monitor)

    @staticmethod
    async def monitor(request: Request):
        if request.route and request.route.ctx.monitor:
            print("....")

    @staticmethod
    async def ensure_monitor_set(app: Sanic):
        for route in app.router.routes:
            if not hasattr(route.ctx, "monitor"):
                route.ctx.monitor = False

    def label(self):
        has_monitor = [
            route
            for route in self.app.router.routes
            if getattr(route.ctx, "monitor", None)
        ]
        return f"{len(has_monitor)} endpoint(s)"

    def included(self):
        return self.app.config.MONITOR

Extend.register(AutoMonitor)

@app.get("/", ctx_monitor=True)
async def handler(request: Request):
    return json({"foo": "bar"})
```

## Extension preregistration

.. column::

    `Extend.register` simplifies the addition of custom extensions.

.. column::

    ```python
    from sanic_ext import Extend, Extension

    class MyCustomExtension(Extension):
        ...

    Extend.register(MyCustomExtension())
    ```

*Added in v22.9*

---

### Guide Content En Plugins Sanic Ext Health Monitor (`guide/content/en/plugins/sanic-ext/health-monitor.md`)

---
title: Sanic Extensions - Health Monitor
---

# Health monitor

The health monitor requires both `sanic>=22.9` and `sanic-ext>=22.9`.

You can setup Sanic Extensions to monitor the health of your worker processes. This requires that you not be in [single process mode](../../guide/running/manager.md#single-process-mode).

## Setup

.. column::

    Out of the box, the health monitor is disabled. You will need to opt-in and enable the endpoint if you would like to use it.

.. column::

    ```python
    app.config.HEALTH = True
    app.config.HEALTH_ENDPOINT = True
    ```

## How does it work

The monitor sets up a new background process that will periodically receive acknowledgements of liveliness from each worker process. If a worker process misses a report too many times, then the monitor will restart that one worker.

## Diagnostics endpoint

.. column::

    The health monitor will also enable a diagnostics endpoint that outputs the [worker state](../../guide/running/manager.md#worker-state). By default is id disabled.

    .. danger:: 

        The diagnostics endpoint is not secured. If you are deploying it in a production environment, you should take steps to protect it with a proxy server if you are using one. If not, you may want to consider disabling this feature in production since it will leak details about your server state.

.. column::

    ```
    $ curl http://localhost:8000/__health__
    {
        'Sanic-Main': {'pid': 99997},
        'Sanic-Server-0-0': {
            'server': True,
            'state': 'ACKED',
            'pid': 9999,
            'start_at': datetime.datetime(2022, 10, 1, 0, 0, 0, 0, tzinfo=datetime.timezone.utc),
            'starts': 2,
            'restart_at': datetime.datetime(2022, 10, 1, 0, 0, 12, 861332, tzinfo=datetime.timezone.utc)
        },
        'Sanic-Reloader-0': {
            'server': False,
            'state': 'STARTED',
            'pid': 99998,
            'start_at': datetime.datetime(2022, 10, 1, 0, 0, 0, 0, tzinfo=datetime.timezone.utc),
            'starts': 1
        }
    }
    ```


## Configuration

| Key | Type | Default| Description |
|--|--|--|--|
| HEALTH | `bool` | `False` | Whether to enable this extension. |
| HEALTH_ENDPOINT | `bool` | `False` | Whether to enable the diagnostics endpoint. |
| HEALTH_MAX_MISSES | `int` | `3` | The number of consecutive misses before a worker process is restarted. |
| HEALTH_MISSED_THRESHHOLD | `int` | `10` | The number of seconds the monitor checks for worker process health. |
| HEALTH_MONITOR | `bool` | `True` | Whether to enable the health monitor. |
| HEALTH_REPORT_INTERVAL | `int` | `5` | The number of seconds between reporting each acknowledgement of liveliness. |
| HEALTH_URI_TO_INFO | `str` | `""` | The URI path of the diagnostics endpoint. |
| HEALTH_URL_PREFIX | `str` | `"/__health__"` | The URI prefix of the diagnostics blueprint. |

---

### Guide Content En Plugins Sanic Ext Injection (`guide/content/en/plugins/sanic-ext/injection.md`)

---
title: Sanic Extensions - Dependency Injection
---

# Dependency Injection

Dependency injection is a method to add arguments to a route handler based upon the defined function signature. Specifically, it looks at the **type annotations** of the arguments in the handler. This can be useful in a number of cases like:

- Fetching an object based upon request headers (like the current session user)
- Recasting certain objects into a specific type
- Using the request object to prefetch data
- Auto inject services

The `Extend` instance has two basic methods on it used for dependency injection: a lower level `add_dependency`, and a higher level `dependency`. 

**Lower level**: `app.ext.add_dependency(...)`

- `type: Type,`: some unique class that will be the type of the object
- `constructor: Optional[Callable[..., Any]],` (OPTIONAL): a function that will return that type

**Higher level**: `app.ext.dependency(...)`

- `obj: Any`: any object that you would like injected
- `name: Optional[str]`: some name that could alternately be used as a reference

Let's explore some use cases here.


.. warning:: 

    If you used dependency injection prior to v21.12, the lower level API method was called `injection`. It has since been renamed to `add_dependency` and starting in v21.12 `injection` is an alias for `add_dependency`. The `injection` method has been deprecated for removal in v22.6.



## Basic implementation

The simplest use case would be simply to recast a value.

.. column::

    This could be useful if you have a model that you want to generate based upon the matched path parameters.

.. column::

    ```python
    @dataclass
    class IceCream:
        flavor: str

        def __str__(self) -> str:
            return f"{self.flavor.title()} (Yum!)"

    app.ext.add_dependency(IceCream)

    @app.get("/<flavor:str>")
    async def ice_cream(request, flavor: IceCream):
        return text(f"You chose: {flavor}")
    ```

    ```
    $ curl localhost:8000/chocolate
    You chose Chocolate (Yum!)
    ```


.. column::

    This works by passing a keyword argument to the constructor of the `type` argument. The previous example is equivalent to this.

.. column::

    ```python
    flavor = IceCream(flavor="chocolate")
    ```

## Additional constructors

.. column::

    Sometimes you may need to also pass a constructor. This could be a function, or perhaps even a classmethod that acts as a constructor. In this example, we are creating an injection that will call `Person.create` first.

    Also important to note on this example, we are actually injecting **two (2)** objects! It of course does not need to be this way, but we will inject objects based upon the function signature.

.. column::

    ```python
    @dataclass
    class PersonID:
        person_id: int

    @dataclass
    class Person:
        person_id: PersonID
        name: str
        age: int

        @classmethod
        async def create(cls, request: Request, person_id: int):
            return cls(person_id=PersonID(person_id), name="noname", age=111)


    app.ext.add_dependency(Person, Person.create)
    app.ext.add_dependency(PersonID)

    @app.get("/person/<person_id:int>")
    async def person_details(
        request: Request, person_id: PersonID, person: Person
    ):
        return text(f"{person_id}\n{person}")
    ```

    ```
    $ curl localhost:8000/person/123
    PersonID(person_id=123)
    Person(person_id=PersonID(person_id=123), name='noname', age=111)
    ```

When a `constructor` is passed to `ext.add_dependency` (like in this example) that will be called. If not, then the object will be created by calling the `type`. A couple of important things to note about passing a `constructor`:

1. A positional `request: Request` argument is *usually* expected. See the `Person.create` method above as an example using a `request` and [arbitrary constructors](#arbitrary-constructors) for how to use a callable that does not require a `request`.
1. All matched path parameters are injected as keyword arguments.
1. Dependencies can be chained and nested. Notice how in the previous example the `Person` dataclass has a `PersonID`? That means that `PersonID` will be called first, and that value is added to the keyword arguments when calling `Person.create`.

## Arbitrary constructors

.. column::

    Sometimes you may want to construct your injectable _without_ the `Request` object. This is useful if you have arbitrary classes or functions that create your objects. If the callable does have any required arguments, then they should themselves be injectable objects.

    This is very useful if you have services or other types of objects that should only exist for the lifetime of a single request. For example, you might use this pattern to pull a single connection from your database pool.

.. column::

    ```python
    class Alpha:
        ...

    class Beta:
        def __init__(self, alpha: Alpha) -> None:
            self.alpha = alpha

    app.ext.add_dependency(Alpha)
    app.ext.add_dependency(Beta)

    @app.get("/beta")
    async def handler(request: Request, beta: Beta):
        assert isinstance(beta.alpha, Alpha)
    ```

*Added in v22.9*

## Objects from the `Request`

.. column::

    Sometimes you may want to extract details from the request and preprocess them. You could, for example, cast the request JSON to a Python object, and then add some additional logic based upon DB queries.

    .. warning:: 

        If you plan to use this method, you should note that the injection actually happens *before* Sanic has had a chance to read the request body. The headers should already have been consumed. So, if you do want access to the body, you will need to manually consume as seen in this example.

        ```python
            await request.receive_body()
        ```


        This could be used in cases where you otherwise might:

        - use middleware to preprocess and add something to the `request.ctx`
        - use decorators to preprocess and inject arguments into the request handler

        In this example, we are using the `Request` object in the `compile_profile` constructor to run a fake DB query to generate and return a `UserProfile` object.

.. column::

    ```python
    @dataclass
    class User:
        name: str

    @dataclass
    class UserProfile:
        user: User
        age: int = field(default=0)
        email: str = field(default="")

        def __json__(self):
            return ujson.dumps(
                {
                    "name": self.user.name,
                    "age": self.age,
                    "email": self.email,
                }
            )

    async def fake_request_to_db(body):
        today = date.today()
        email = f'{body["name"]}@something.com'.lower()
        difference = today - date.fromisoformat(body["birthday"])
        age = int(difference.days / 365)
        return UserProfile(
            User(body["name"]),
            age=age,
            email=email,
        )

    async def compile_profile(request: Request):
        await request.receive_body()
        profile = await fake_request_to_db(request.json)
        return profile

    app.ext.add_dependency(UserProfile, compile_profile)

    @app.patch("/profile")
    async def update_profile(request, profile: UserProfile):
        return json(profile)
    ```

    ```
    $ curl localhost:8000/profile -X PATCH -d '{"name": "Alice", "birthday": "2000-01-01"}'
    {
        "name":"Alice",
        "age":21,
        "email":"alice@something.com"
    }
    ```

## Injecting services

It is a common pattern to create things like database connection pools and store them on the `app.ctx` object. This makes them available throughout your application, which is certainly a convenience. One downside, however, is that you no longer have a typed object to work with. You can use dependency injections to fix this. First we will show the concept using the lower level `add_dependency` like we have been using in the previous examples. But, there is a better way using the higher level `dependency` method.

### The lower level API using `add_dependency`

.. column::


    This works very similar to the [last example](#objects-from-the-request) where the goal is the extract something from the `Request` object. In this example, a database object was created on the `app.ctx` instance, and is being returned in the dependency injection constructor.

.. column::

    ```python
    class FakeConnection:
        async def execute(self, query: str, **arguments):
            return "result"

    @app.before_server_start
    async def setup_db(app, _):
        app.ctx.db_conn = FakeConnection()
        app.ext.add_dependency(FakeConnection, get_db)

    def get_db(request: Request):
        return request.app.ctx.db_conn



    @app.get("/")
    async def handler(request, conn: FakeConnection):
        response = await conn.execute("...")
        return text(response)
    ```
    ```
    $ curl localhost:8000/
    result
    ```

### The higher level API using `dependency`

.. column::

    Since we have an actual *object* that is available when adding the dependency injection, we can use the higher level `dependency` method. This will make the pattern much easier to write.

    This method should always be used when you want to inject something that exists throughout the lifetime of the application instance and is not request specific. It is very useful for services, third party clients, and connection pools since they are not request specific.

.. column::

    ```python
    class FakeConnection:
        async def execute(self, query: str, **arguments):
            return "result"

    @app.before_server_start
    async def setup_db(app, _):
        db_conn = FakeConnection()
        app.ext.dependency(db_conn)

    @app.get("/")
    async def handler(request, conn: FakeConnection):
        response = await conn.execute("...")
        return text(response)
    ```
    ```
    $ curl localhost:8000/
    result
    ```

## Generic types

Be carefule when using a [generic type](https://docs.python.org/3/library/typing.html#typing.Generic). The way that Sanic's dependency injection works is by matching the entire type definition. Therefore, `Foo` is not the same as `Foo[str]`. This can be particularly tricky when trying to use the [higher-level `dependency` method](#the-higher-level-api-using-dependency) since the type is inferred.

.. column::

    For example, this will **NOT** work as expected since there is no definition for `Test[str]`.

.. column::

    ```python
    import typing
    from sanic import Sanic, text

    T = typing.TypeVar("T")

    class Test(typing.Generic[T]):
        test: T

    app = Sanic("testapp")
    app.ext.dependency(Test())

    @app.get("/")
    def test(request, test: Test[str]):
        ...
    ```


.. column::

    To get this example to work, you will need to add an explicit definition for the type you intend to be injected.

.. column::

    ```python
    import typing
    from sanic import Sanic, text

    T = typing.TypeVar("T")

    class Test(typing.Generic[T]):
        test: T

    app = Sanic("testapp")
    _singleton = Test()
    app.ext.add_dependency(Test[str], lambda: _singleton)

    @app.get("/")
    def test(request, test: Test[str]):
        ...
    ```

## Configuration

.. column::

    By default, dependencies will be injected after the `http.routing.after` [signal](../../guide/advanced/signals.md#built-in-signals). Starting in v22.9, you can change this to the `http.handler.before` signal.

.. column::

    ```python
    app.config.INJECTION_SIGNAL = "http.handler.before"
    ```

*Added in v22.9*

---

--- METRICS ---
- Files Extracted: 79
- Estimated Token Budget: ~126214 tokens
- Canonical Reference: https://codewiki.google/github.com/sanic-org/sanic
