Asyncio Support =============== With the rise of :keyword:`async`/:keyword:`await` in Python and popular web frameworks like FastAPI, it's important to support asyncio. This section will cover how to use the asyncio client, as well as recommended patterns for using it with libraries like FastAPI. Installation ------------ Async support is not included in the default installation. You can install it via: .. code-block:: bash pip install autumn-py[aio] This will install the :mod:`aiohttp` library, which is required for async support. You may optionally choose to install some speedups provided by the :mod:`aiohttp` library. Note that these speedups are not required for the library to work, but they may improve performance, but may not be available on all platforms. .. code-block:: bash pip install aiohttp[speedups] .. warning:: View the :mod:`aiohttp` `documentation `_ for more information on the speedups. Windows users may need to adjust their event loop. Usage ----- Autumn supports asyncio. You can use the :class:`~autumn.aio.client.AsyncClient` class to interact with the API asynchronously. Basic Usage ^^^^^^^^^^^ The basic usage of the asyncio client is the same as the sync client. You can use the :class:`~autumn.aio.client.AsyncClient` class to interact with the API asynchronously. .. code-block:: python import asyncio from autumn import Autumn # from autumn.aio import AsyncClient async def main(): client = Autumn(token="your_api_key") await client.attach( "customer_id", product_id="chat_messages" ) asyncio.run(main()) ASGI compatible frameworks ^^^^^^^^^^^^^^^^^^^^^^^^^^ The Python SDK now supports automatic mounting of backend routes that the `autumn-js `_ JavaSript library uses. This means you can easily use a stack where you have a React frontend and a Python backend. .. note:: The ``starlette`` and ``aiohttp`` libraries are required for ASGI support. You can install them via pip. You must provide an asynchronous ``identify`` method that takes in a Starlette ``Request`` object. You are required to return your logged in user's information, specifically their ``name``, their internal ``user_id`` (the User ID on **your** systems) and their ``email``. Examples have been provided below. .. warning:: You **must** mount the ``AutumnASGI`` app at ``/api/autumn``. Any other route will cause ``autumn-js`` to break. .. tabs:: .. tab:: Litestar .. code-block:: python from __future__ import annotations import os from typing import TYPE_CHECKING from litestar import Litestar from litestar.handlers import asgi from litestar.config.cors import CORSConfig from autumn.asgi import AutumnASGI if TYPE_CHECKING: from starlette.requests import Request from autumn.asgi import AutumnIdentifyData async def identify(request: Request) -> AutumnIdentifyData: # db = request.state.postgres # session = request.session return { "customer_id": "user_123", "customer_data": {"name": "John Doe", "email": "djohn@gmail.com"}, } autumn = AutumnASGI(token=os.environ["AUTUMN_KEY"], identify=identify) async def close_autumn(_): await autumn.close() autumn_asgi = asgi(path="/api/autumn", is_mount=True, copy_scope=True)(autumn) # CORS must be configured correctly. # You must allow the GET, POST and OPTIONS methods at a minimum. # Pass your frontend url here. DOMAINS = [""] app = Litestar( debug=True, route_handlers=[autumn_asgi], cors_config=CORSConfig( allow_origins=DOMAINS, allow_credentials=True, allow_headers=["*"], allow_methods=["*"], ), on_shutdown=[close_autumn], ) .. tab:: Starlette/FastAPI .. code-block:: python from __future__ import annotations import os import contextlib from typing import TYPE_CHECKING from starlette.applications import Starlette from starlette.middleware.cors import CORSMiddleware from starlette.middleware import Middleware from autumn.asgi import AutumnASGI if TYPE_CHECKING: from starlette.requests import Request from autumn.asgi import AutumnIdentifyData async def identify(request: Request) -> AutumnIdentifyData: # db = request.state.postgres # session = request.session # This is where you are responsible for identifying the logged-in user. # You must return a dictionary in the format shown below. return { "customer_id": "user_123", "customer_data": {"name": "John Doe", "email": "djohn@gmail.com"}, } autumn = AutumnASGI(token=os.environ["AUTUMN_KEY"], identify=identify) @contextlib.asynccontextmanager async def lifespan(_): yield await autumn.close() # CORS must be configured correctly. # You must allow the GET, POST and OPTIONS methods at a minimum. # Pass your frontend url here. DOMAINS = [""] middleware = [ Middleware( CORSMiddleware, allow_methods=["*"], allow_headers=["*"], allow_credentials=True, allow_origins=DOMAINS, ) ] app = Starlette(debug=True, middleware=middleware, lifespan=lifespan) app.mount("/api/autumn", autumn) Finally, on your frontend, simply adjust the ```` component's ``backendUrl`` attribute to the URL of your Python API. For a complete example, check out the `python-ssr-autumn-template `_. That's it! Enjoy using Autumn!