Litestar ASGI API Framework

repository·main·Indexed 11 days ago

https://github.com/litestar-org/litestar

A production-ready, highly performant, and extensible ASGI framework for building APIs. Litestar features built-in support for data validation, dependency injection, ORM integration, and class-based controllers. It automatically generates OpenAPI 3.1.0 schemas and integrates with documentation tools like Swagger-UI and ReDoc. Version 3.0.0b0 leverages Python type hints and msgspec for high-performance JSON serialization.

Tokens
127.7K
Snippets
404
Records
539
Agent score
92%

What's inside Litestar

  1. Overview of OpenAPI support in Litestar

    main

    Litestar provides first-class support for the OpenAPI specification (supporting the latest versions, including 3.1.0). It automatically generates OpenAPI schemas in both YAML and JSON formats.

    Key capabilities include:

    • Automatic Schema Generation: Uses Python dataclasses, typing.TypedDict, Pydantic, and msgspec models to build the specification.
    • Extensibility: Supports 3rd party entities via the Litestar plugin system.
    • Documentation: Built-in support for generating static documentation sites using various libraries.
    • Granular Configuration: You can configure OpenAPI settings globally or customize schema generation for specific route handlers using keyword arguments on decorators.
  2. Overview of Litestar Core Features

    main

    Litestar is a high-performance ASGI framework with several key features designed for modern web development:

    • Class-based Controllers: Organize routes using Python OOP.
    • Dependency Injection: A powerful DI system using Provide.
    • Middleware: Support for standard ASGI middleware and built-ins for CORS, CSRF, Rate limiting, and Compression (GZip, Brotli, Zstd).
    • Plugin System: Extend serialization, OpenAPI generation, and more.
    • ORM Support: Built-in SQLAlchemy integration.
    • DTOs: Programmatic creation of Data Transfer Objects via DTOFactory.
    • Lifecycle Hooks: Support for before_request and after_request hooks.
    • OpenAPI 3.1: Automatic schema generation with optional example generation via polyfactory.
  3. Overview of Litestar Stores

    main
    Litestar provides asynchronous, thread-safe, and process-safe key/value stores for simple storage needs like caching response data or managing server-side sessions. These stores are managed via a StoreRegistry, allowing for easy access throughout the application and integration with third-party plugins.
  4. What is a Subscriber and how to consume events

    main

    A Subscriber manages an individual event stream representing the sum of events from all channels the subscriber has subscribed to. It acts as the endpoint for events, while the ChannelsPlugin acts as a router from the backends.

    There are two primary ways to consume the event stream:

    1. Direct Iteration: Use iter_events() which is an asynchronous generator. This is useful if processing events is the only concern, but note that it is effectively an infinite loop.
    2. Background Task: Use the run_in_background() asynchronous context manager. This starts an asyncio.Task that consumes events and invokes a provided callback for each. This is the preferred method for most applications as it allows you to run other code concurrently.

    Important: Events in the stream are always bytes. When using ChannelsPlugin.publish, data is serialized before being sent to the backend.

    WebSocket Caution: When using iter_events() with WebSockets, a WebSocketDisconnect might not be raised immediately if the client disconnects and no further events are received, potentially leaving the coroutine suspended indefinitely.

    # Example of using run_in_background with a callback
    # (Conceptual usage based on documentation)
    async with subscriber.run_in_background(callback=my_callback) as task:
        # Perform other concurrent tasks here
        pass
  5. What is Middleware in Litestar?

    main
    In Litestar, middleware are ASGI applications that sit between the application entrypoint and the route handler function. They allow you to intercept and process requests before they reach your handlers, and responses before they are sent back to the client. Litestar provides several built-in middlewares for common tasks, and also allows you to create custom middleware.
  6. Customize the cache key builder

    main

    Litestar's default cache key is derived from the request's path and sorted query parameters. You can override this behavior by providing a custom key builder function. This can be applied globally via ResponseCacheConfig or specifically to a single route handler using the cache_key_builder parameter.

    from litestar import Litestar, get
    from litestar.types import Request
    
    def custom_key_builder(request: Request) -> str:
        return f"custom-{request.url.path}"
    
    @get(
        path="/custom-key",
        cache=True,
        cache_key_builder=custom_key_builder
    )
    async def handler() -> dict[str, str]:
        return {"message": "custom key"}
    
    app = Litestar(routes=[handler])
  7. Use Layered Parameters in Litestar

    main

    Litestar's layered architecture allows you to declare parameters at multiple levels: the Litestar app, Router, Controller, and the individual route handler.

    • App Level: Parameters declared on the Litestar app (e.g., using CookieParameter) are extracted and validated at the application level. They can exist even if the route handler does not explicitly declare them.
    • Router Level: Parameters declared on a Router (e.g., using HeaderParameter) apply to all routes within that router. If a handler re-declares the parameter using a type like FromHeader[str], it becomes required at the handler level.
    • Controller Level: Parameters declared on a Controller (e.g., using QueryParameter) apply to all handlers in that controller. Handlers can re-declare these parameters to tighten constraints (e.g., changing lt=100 to lt=50).
    • Handler Level: Local parameters like FromQuery, FromHeader, FromCookie, and FromPath are specific to the individual route function.
    from typing import Annotated
    from litestar import Litestar, get, Router, Controller
    from litestar.enums import HTTPMethod
    from litestar.params import CookieParameter, HeaderParameter, QueryParameter, FromHeader, FromQuery, FromPath
    
    # 1. App Level: Cookie parameter 'special-cookie' (optional)
    app = Litestar(
        route=None, 
        parameters=[CookieParameter(name="special-cookie", annotation=str, required=False)]
    )
    
    # 2. Router Level: Header parameter 'MyHeader'
    router = Router(
        path="/router",
        router_param=HeaderParameter(name="MyHeader", required=False),
        route=get("/") # Handler re-declares it as required via FromHeader
    )
    
    # 3. Controller Level: Query parameter 'controller_param' with lt=100
    class MyController(Controller):
        path = "/controller"
        parameters = [QueryParameter(name="controller_param", lt=100)]
    
        @get("/")
        def handler(
            self, 
            # Tightening constraint to lt=50
            controller_param: Annotated[int, QueryParameter(lt=50)],
            # Local parameters
            local_param: FromQuery[str],
            path_param: FromPath[int]
        ) -> None:
            pass
  8. Data Parsing, Type Hints, and Msgspec in Litestar

    main
    Litestar leverages Python type hints for automatic data parsing and validation. It provides high-performance support for msgspec, allowing for extremely fast JSON serialization and deserialization, which is a core part of its data handling capabilities.
  9. Understand WebSocket transport modes: text and binary

    main

    WebSockets in Litestar support two transport modes: text and binary. These modes define how bytes are handled at the protocol level during transfer.

    Key characteristics:

    • Independence: The modes for sending and receiving can be set independently (e.g., a socket can send binary data while receiving text data).
    • text mode: The default mode. It is suitable for most standard string-based communication.
    • binary mode: Typically used when transferring binary blobs that lack a meaningful string representation, such as images or raw byte buffers.

    Note: The transport mode does not strictly map to Python str or bytes types in terms of application logic, as WebSockets can transmit any format; the mode specifically dictates how the underlying bytes are handled during transport.

  10. Handle synchronous callables with sync_to_thread

    main

    Litestar supports both synchronous and asynchronous callables. However, running synchronous functions that perform blocking I/O or intensive computations can block the main event loop and degrade application performance.

    You can control how synchronous functions are executed using the sync_to_thread parameter:

    • Set sync_to_thread=True: Runs the synchronous function in a separate thread pool to prevent blocking the main event loop.
    • Set sync_to_thread=False: Use this if you are certain the synchronous function is non-blocking. This tells Litestar to treat the function as non-blocking.
    • Default behavior: If you provide a synchronous function without explicitly setting sync_to_thread, Litestar will raise a warning.
  11. Use SecretString and SecretBytes for sensitive data

    main

    Litestar provides two specialized data structures for handling sensitive information within your application to prevent accidental exposure (e.g., in logs or tracebacks):

    • SecretString: A container for sensitive text data.
    • SecretBytes: A container for sensitive binary data.

    These structures are designed to wrap sensitive values, making them safer to pass through the framework's request/response lifecycle.