Skip to content

Home

The speed of a velociraptor, the flexibility of Python.

A micro framework built to hunt.

VelociPy logo

PyPI - Version PyPI - Python Version PyPI - License
PePy - Downloads GitLab Pipeline Status GitLab Coverage GitLab Last Commit GitLab Issues
Libraries.io dependency status Python - Formatter Git hooks
RSGI ASGI


VelociPy doesn't lumber through the jungle with bulked-up gear. It stays light, feathered, and alert - reading the terrain, then striking with a sickle claw when the moment is right. When the hunt calls for sharper talons, tougher hide, or a keener nose, it grows them - then sheds them when the job is done.

The result is a micro framework with a tiny core and a set of swappable adapters and optional modules. Start with nothing but the core. Add validation, OpenAPI, security, rate limiting, multipart uploads, Redis storage, and more by importing what you need. Only httpx2 is required at runtime.


Why hunt with VelociPy?

  • Light bones, fast muscles - a radix-tree router, lightweight request/response objects, and precomputed handler plans keep the core tiny.
  • Hunt on any terrain - the same app runs unchanged on ASGI (Uvicorn, Hypercorn) or RSGI (Granian).
  • Swap your claws - pick your JSON encoder, model validator, and protocol independently.
  • Keen senses - typed parameters for query, header, cookie, path, and body injection.
  • Armor and discipline - optional security helpers, rate limiting, and request-size limits.

Quick start

Create main.py:

from velocipy import VelociPy

app = VelociPy()

@app.get("/")
async def hello():
    return {"message": "Hello, VelociPy!"}

Run it under the fastest terrain:

# RSGI - the open plain
granian main:app --interface rsgi --reload

# ASGI - the dense, well-trodden forest
uvicorn main:app --reload

Visit http://localhost:8000/docs for the auto-generated Swagger UI.

RSGI is the fastest strike

For raw throughput, run VelociPy under Granian with RSGI. For compatibility with the broader async ecosystem, use ASGI.

A hunt in one file

This single file shows the essentials: validation, dependencies, rate limiting, headers, and OpenAPI tags.

from typing import Annotated
from pydantic import BaseModel
from velocipy import Depends, Header, Query, VelociPy
from velocipy.limiter import (
    Limiter,
    RateLimitAlgorithm,
    RateLimitRule,
    rate_limit,
)
from velocipy.limiter.storage import MemoryStorage

app = VelociPy()
limiter = Limiter(storage=MemoryStorage())

class Item(BaseModel):
    name: str
    price: float

async def page_params(
    page: Annotated[int, Query(ge=1)] = 1,
    size: Annotated[int, Query(le=100)] = 20,
):
    return {"page": page, "size": size}

rule = RateLimitRule(
    name="items",
    limit=60,
    window=60,
    algorithm=RateLimitAlgorithm.TOKEN_BUCKET,
)

@app.get("/items", response_model=list[Item], tags=["items"])
async def list_items(
    params: Annotated[dict, Depends(page_params)],
    _: None = Depends(rate_limit(limiter, rules=[rule])),
    x_request_id: Annotated[str | None, Header()] = None,
):
    return [{"name": "hoodie", "price": 49.99}]

Test the catch in-process:

from velocipy.testing import TestClient

client = TestClient(app)
assert client.get("/items?page=1").status_code == 200

See examples/basic.py for a runnable version with lifespan events, custom OpenAPI metadata, and authentication dependencies.

The raptor at a glance

Gear What's included
Routing Radix-tree router, static / parametric / typed / catch-all routes, sub-routers, named routes
Validation msgspec.Struct, pydantic.BaseModel, or custom adapters
Parameters Query, header, cookie, path, and body injection via type hints
Dependencies Sub-dependencies, generator yield teardown, async context managers, overrides
Protocols Native ASGI and RSGI support, WebSocket endpoints
Responses JSON, streaming, files, redirects, custom response classes
Middleware CORS, GZip, HTTPS redirect, trusted host, security headers, timing, request ID
Security API-key header / query / cookie, OAuth2 password bearer
Rate limiting Dependency-based, async-only, token / fixed / sliding window, memory + Redis
Request safety Global max_content_length with automatic 413 Payload Too Large
Sessions Signed session cookies via SessionMiddleware (stdlib-only signing)
Form parameters Form(...) field injection and adapter-neutral form models
Typed config Immutable Config container with @Config.register / Config.get
Templating Optional Jinja2 Templates / TemplateResponse
Static files StaticFiles with app.mount()
Uploads UploadFile with multipart streaming
Background tasks Post-response work
Testing Built-in TestClient and AsyncTestClient for ASGI and RSGI
OpenAPI Auto-generated 3.1 docs with reusable schemas and Swagger UI

Choose your terrain

Terrain Best for
RSGI (Granian) Maximum speed, lowest overhead. The open plain.
ASGI (Uvicorn / Hypercorn) Compatibility with the broad async ecosystem. The dense forest.

Example hunts

The examples/ directory has small, runnable demos. Start with the essentials, then move through common patterns and advanced integrations.

Start here

Example What it shows
basic.py Validation, OpenAPI, dependencies, lifespan
routing.py Routes, path params, sub-routers, catch-all routes
query_params.py Query parameter parsing and validation
dependencies.py Dependency injection patterns
responses.py Custom and streaming responses

Common patterns

Example What it shows
security.py API-key and OAuth2 authentication
rate_limit.py Dependency-based rate limiting
middleware.py Function, class, and built-in middleware
testing.py Testing with TestClient and AsyncTestClient
uploads.py UploadFile and multipart streaming
background_tasks.py Post-response background work
sessions.py Signed session cookies
form_parameters.py Form(...) field injection
websocket.py WebSocket echo and path params
headers_cookies.py Header and cookie injection

Advanced and integrations

Example What it shows
json_encoder.py Explicit JSON encoder selection
model_backends.py msgspec / pydantic / custom model backends
templates.py Optional Jinja2 templating
static_files.py Static file serving
config.py Typed Config classes
max_body_size.py Global max_content_length
exception_handlers.py Custom exception handlers
route_extras.py Route decorator metadata
uvicorn_server.py Running a VelociPy app with Uvicorn via ASGI

Next steps