Xpresso is an ASGI web framework built on top of Starlette, Pydantic and di, with heavy inspiration from FastAPI.
Some of the standout features are:
- ASGI support for high performance (within the context of Python web frameworks)
- OpenAPI documentation generation
- Automatic parsing and validation of request bodies and parameters, with hooks for custom extractors
- Full support for OpenAPI parameter serialization
- Highly typed and tested codebase with great IDE support
- A powerful dependency injection system, backed by di
Requirements
Python 3.7+
Installation
pip install xpresso
You'll also want to install an ASGI server, such as Uvicorn.
pip install uvicorn
Example
Create a file named example.py
:
from pydantic import BaseModel
from xpresso import App, Path, FromPath, FromQuery
class Item(BaseModel):
item_id: int
name: str
async def read_item(item_id: FromPath[int], name: FromQuery[str]) -> Item:
return Item(item_id=item_id, name=name)
app = App(
routes=[
Path(
"/items/{item_id}",
get=read_item,
)
]
)
Run the application:
uvicorn example:app
Navigate to http://127.0.0.1:8000/items/123?name=foobarbaz in your browser. You will get the following JSON response:
{"item_id":123,"name":"foobarbaz"}
Now navigate to http://127.0.0.1:8000/docs to poke around the interactive Swagger UI documentation:
For more examples, tutorials and reference materials, see our documentation.
Inspiration and relationship to other frameworks
Xpresso is mainly inspired by FastAPI. FastAPI pioneered several ideas that are core to Xpresso's approach:
- Leverage Pydantic for JSON parsing, validation and schema generation.
- Leverage Starlette for routing and other low level web framework functionality.
- Provide a simple but powerful dependency injection system.
- Use that dependency injection system to provide extraction of request bodies, forms, query parameters, etc.
Xpresso takes these ideas and refines them by:
- Decoupling the dependency injection system from the request/response cycle, leading to an overall much more flexible and powerful dependency injection system, packaged up as the standalone di library.
- Decoupling the framework from Pydantic by using
Annotated
(PEP 593) instead of default values (param: FromQuery[str]
instead ofparam: str = Query(...)
). - Middleware on Routers so that you can use generic ASGI middleware in a routing-aware manner (for example, installing profiling middleware on only some paths without using regex matching).
- Support for lifespans on any Router or mounted App (this silently fails in FastAPI and Starlette)
- dependency injection into the application lifespan and support for multiple dependency scopes.
- Formalizing the framework for extracting parameters and bodies from requests into the Binder API so that 3rd party extensions can do anything the framework does.
- Support for customizing parameter and form serialization.
- Better performance by implementing dependency resolution in Rust, executing dependencies concurrently and controlling threading of sync dependencies on a per-dependency basis.
Inspiration to FastAPI
When I originally concieved Xpresso I wasn't sure what the goal was. I didn't necessarily want to replace FastAPI, I know how much work open source is and was not and am not willing to commit to something like that. So I always thought of the project more as a testing ground for interesting ideas for ASGI web frameworks in general and FastAPI in particular.
I am happy to report that in this sense it has been a smash hit. In the time since writing the above differences:
- Starlette added support for middleware on routers.
- The ASGI spec, Starlette and FastAPI added support for returning data from lifespans, which I think may be an even better idea than dependency scopes.
- FastAPI added support for PEP593 annotations, taking direct inspiration from Xpresso's approach.
- I've established a strong working relationship with Sebastiรกn, FastAPI's author, and I foresee more ideas from Xpresso leaking into FastAPI in some way or another.
So where does that leave Xpresso? It's going to stay around, but it's less likely to become a stable production ready framework: it can provide more value to the community as an exprimental proving ground for ideas than as yet another "production ready" web framework.