Skip to main content

AI-API-first async HTTP framework with Cython hot paths

Project description

🔥 Ember

License: MIT Python CI

AI-API-first async HTTP framework for Python — built for LLM workloads with Cython hot paths, multi-process workers, and first-class streaming.

📖 Documentation · 🤝 Contributing


Why Ember

Ember FastAPI Express NestJS
Protocol llhttp + Cython + io_uring ASGI / uvicorn Node.js http Node.js http
Workers Fork + SO_REUSEPORT Single process cluster cluster
SSE streaming Native, zero-copy via starlette manual manual
AI primitives Built-in none none none

Hello-world benchmark (single worker, k6 200 VUs / 20 s)

GET /hello → "Hello, World!", all running on the same Intel i7-14700 box, 0% error rate. Fiber pinned to one core (GOMAXPROCS=1) for fairness.

Framework RPS p50 (ms) p99 (ms) peak RSS
Fiber (Go) 140,993 1.21 3.96 9 MB
Ember 112,177 1.68 4.35 25 MB
Express (Node) 26,357 7.09 13.57 131 MB
NestJS (Node) 23,528 8.08 13.75 158 MB
FastAPI (Python) 17,517 9.45 30.86 49 MB

Ember runs 6.4× FastAPI, 4.3× Express, and 4.8× NestJS on the same hardware — and at 112k RPS / 25 MB RSS / 80% of Go Fiber's throughput, it is the only Python framework in this league.

CRUD benchmark (PostgreSQL, mixed reads + writes)

300-VU ramp, 196k-row table, 70k requests, 0% errors:

Framework avg latency p95 p99
Ember 19.85 ms 44 ms 59 ms
Express 19.20 ms 43 ms 56 ms
FastAPI 153.72 ms 549 ms 794 ms

Ember matches Node on real CRUD — within 3% of Express on average, within 6% on p99 — and has a 13× tighter tail than FastAPI.

Memory: Peak RSS dropped from 48 MB → 25 MB (-48%) in v0.2 — see Performance § Tuning the buffer pool. Idle RSS is ~22 MB, well under FastAPI (47 MB) and 5× lighter than Node frameworks.

Reproducible: see taskbench/hello_bench/ — run ./bench_all.sh.


Features

  • Cython hot paths — headers, router, request, response, protocol all compiled to C
  • Multi-process workers — fork-based with SO_REUSEPORT, kernel load-balancing
  • workers=1 in-process — no supervisor overhead when you don't need it (~22 MB saved)
  • Tunable io_uring buffer poolEmber.run(io_uring_num_bufs=, io_uring_buf_size=) to scale RAM down to 2 MB pool (default) or up to 32 MB for high-concurrency workloads
  • Lazy AI / cache / middleware importsimport ember no longer pulls numpy/redis/memcached for plain HTTP apps
  • AI-first routing@app.ai_route() with streaming, tool calling, conversation context
  • SSE streamingSSEResponse, sse_stream(), TokenStreamResponse for LLM token output
  • Pluggable cachingStaticCache, RedisCache, MemcachedCache via single decorator arg
  • Token rate limitingTokenBucket, GlobalTokenBucket, RateLimitMiddleware
  • Model routingModelRouter with fallback, cost, and latency strategies
  • Semantic cache — vector-search cache for AI responses
  • Built-in middleware — CORS, Bearer auth, API key
  • Blueprints — modular route groups with URL prefixes
  • Cross-platform — Linux/macOS multi-process, Windows single-process fallback

Install

pip install ember-api
# With all performance extras:
pip install "ember-api[fast]"       # uvloop + orjson
pip install "ember-api[cache]"      # Redis + Memcached backends
pip install "ember-api[all]"        # everything

Build Cython extensions from source (optional, for maximum speed):

pip install cython
python setup.py build_ext --inplace

Hello World

from ember import Ember

app = Ember()

@app.get("/")
async def index():
    return {"hello": "world"}

app.run(host="0.0.0.0", port=8000, workers=4)

Full CRUD Example

from ember import Ember, Blueprint, Request, JSONResponse, StaticCache, RedisCache

app = Ember()

tasks: dict = {}

@app.get("/tasks", cache=RedisCache(ttl=30))
async def list_tasks(request: Request) -> JSONResponse:
    page  = int(request.args.get("page", 1))
    limit = int(request.args.get("limit", 10))
    items = list(tasks.values())[(page - 1) * limit : page * limit]
    return JSONResponse({"tasks": items, "total": len(tasks)})

@app.get("/tasks/{task_id:str}")
async def get_task(request: Request, task_id: str) -> JSONResponse:
    task = tasks.get(task_id)
    if not task:
        return JSONResponse({"error": "not found"}, status_code=404)
    return JSONResponse(task)

@app.post("/tasks")
async def create_task(request: Request) -> JSONResponse:
    data = await request.json()
    import uuid
    task_id = str(uuid.uuid4())
    tasks[task_id] = {"id": task_id, **data}
    return JSONResponse(tasks[task_id], status_code=201)

app.run(host="0.0.0.0", port=8000, workers=4)

AI / LLM Routes

from ember import Ember, Request, SSEResponse, ConversationContext, sse_stream
import asyncio

app = Ember()

async def token_stream(prompt: str):
    for word in f"You asked: {prompt}".split():
        await asyncio.sleep(0.05)
        yield word + " "

@app.ai_route("/v1/chat", methods=["POST"], streaming=True)
async def chat(request: Request, context: ConversationContext) -> SSEResponse:
    body = await request.json()
    prompt = body.get("message", "")
    context.add_message("user", prompt)
    return sse_stream(token_stream(prompt))

app.run(host="0.0.0.0", port=8000)

Caching

from ember import Ember, RedisCache, MemcachedCache, StaticCache

app = Ember()

# Static in-memory cache (no TTL, perfect for health checks)
@app.get("/health", cache=StaticCache())
async def health():
    return {"status": "ok"}

# Redis cache — shared across all workers
task_cache = RedisCache(url="redis://localhost:6379", ttl=30)

@app.get("/tasks", cache=task_cache)
async def list_tasks(request):
    ...

# Memcached cache
@app.get("/posts", cache=MemcachedCache(host="localhost", port=11211, ttl=60))
async def list_posts(request):
    ...

Ember auto-connects on server start and auto-disconnects on stop — no lifecycle code needed.


Middleware

from ember import Ember, CORSMiddleware, BearerAuthMiddleware, APIKeyMiddleware

app = Ember()

app.add_middleware(CORSMiddleware(allow_origins=["https://myapp.com"]))
app.add_middleware(BearerAuthMiddleware(verify_fn=lambda token: token == "secret"))
app.add_middleware(APIKeyMiddleware(api_keys=["key-1", "key-2"], header="x-api-key"))

Blueprints

from ember import Ember, Blueprint, JSONResponse

app   = Ember()
admin = Blueprint()

@admin.get("/users")
async def list_users():
    return JSONResponse({"users": []})

@admin.post("/users")
async def create_user(request):
    data = await request.json()
    return JSONResponse(data, status_code=201)

app.add_blueprint(admin, prefixes={"*": "/admin"})
app.run(port=8000)

Limits & Rate Limiting

from ember import Ember, RouteLimits, TokenLimits, ServerLimits

app = Ember(
    server_limits=ServerLimits(keep_alive_timeout=30),
)

@app.post(
    "/upload",
    limits=RouteLimits(max_body_size=50 * 1024 * 1024),  # 50 MB
)
async def upload(request):
    body = await request.body()
    return {"size": len(body)}

@app.ai_route(
    "/v1/chat",
    methods=["POST"],
    token_limits=TokenLimits(tokens_per_minute=10_000, max_prompt_tokens=4_096),
)
async def chat(request, context):
    ...

Project Layout

ember/
  ai/           # ConversationContext, PromptTemplate, ToolRegistry, ModelRouter, SemanticCache
  cache/        # StaticCache, RedisCache, MemcachedCache
  headers/      # Cython headers parser
  middleware/   # CORS, BearerAuth, APIKey
  protocol/     # Cython llhttp HTTP/1.1 protocol
  request/      # Cython Request + Stream
  response/     # Cython Response, JSONResponse, SSEResponse …
  router/       # Cython router with LRU cache, path params, regex
  sessions/     # Session engine (in-memory, extensible)
  workers/      # Fork worker, Reaper, graceful shutdown
  application.py
  server.py
examples/
  basic_api.py
  streaming_chat.py
  tool_calling.py
tests/
setup.py

Running Tests

pip install "ember-api[dev]"
pytest

Contributing

See CONTRIBUTING.md.
Issues: bug reports · feature requests

License

MIT — see LICENSE.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

ember_api-0.1.0.tar.gz (1.1 MB view details)

Uploaded Source

Built Distributions

If you're not sure about the file name format, learn more about wheel file names.

ember_api-0.1.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl (1.8 MB view details)

Uploaded CPython 3.13manylinux: glibc 2.17+ x86-64manylinux: glibc 2.28+ x86-64

ember_api-0.1.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl (1.7 MB view details)

Uploaded CPython 3.13manylinux: glibc 2.17+ ARM64manylinux: glibc 2.28+ ARM64

ember_api-0.1.0-cp313-cp313-macosx_11_0_x86_64.whl (1.4 MB view details)

Uploaded CPython 3.13macOS 11.0+ x86-64

ember_api-0.1.0-cp313-cp313-macosx_11_0_arm64.whl (1.4 MB view details)

Uploaded CPython 3.13macOS 11.0+ ARM64

ember_api-0.1.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl (1.8 MB view details)

Uploaded CPython 3.12manylinux: glibc 2.17+ x86-64manylinux: glibc 2.28+ x86-64

ember_api-0.1.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl (1.7 MB view details)

Uploaded CPython 3.12manylinux: glibc 2.17+ ARM64manylinux: glibc 2.28+ ARM64

ember_api-0.1.0-cp312-cp312-macosx_11_0_x86_64.whl (1.4 MB view details)

Uploaded CPython 3.12macOS 11.0+ x86-64

ember_api-0.1.0-cp312-cp312-macosx_11_0_arm64.whl (1.3 MB view details)

Uploaded CPython 3.12macOS 11.0+ ARM64

File details

Details for the file ember_api-0.1.0.tar.gz.

File metadata

  • Download URL: ember_api-0.1.0.tar.gz
  • Upload date:
  • Size: 1.1 MB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.11.8 {"installer":{"name":"uv","version":"0.11.8","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for ember_api-0.1.0.tar.gz
Algorithm Hash digest
SHA256 42374b266b657394049eb2b8ef3ff1768674cc46c13574a36f031e65528545b1
MD5 11bb9e4bbc1983e0e3447ffb508408b7
BLAKE2b-256 8976f7e3c3e31f9bcf4e51a7f1a3b6b5f0a4a50a938794b7b4dc4598c24498a0

See more details on using hashes here.

File details

Details for the file ember_api-0.1.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl.

File metadata

  • Download URL: ember_api-0.1.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl
  • Upload date:
  • Size: 1.8 MB
  • Tags: CPython 3.13, manylinux: glibc 2.17+ x86-64, manylinux: glibc 2.28+ x86-64
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.11.8 {"installer":{"name":"uv","version":"0.11.8","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for ember_api-0.1.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 41d72edbbccd3dc14d6a01560d56c2381749ce55ca035d29af1fc2c114553c8a
MD5 8cce5a7c72f96848a2c57e1f53d404fe
BLAKE2b-256 f704cef35c30e4dc838882f652e1e852173e8b64d6d11aef0be9cb95d5ae3df1

See more details on using hashes here.

File details

Details for the file ember_api-0.1.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl.

File metadata

  • Download URL: ember_api-0.1.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl
  • Upload date:
  • Size: 1.7 MB
  • Tags: CPython 3.13, manylinux: glibc 2.17+ ARM64, manylinux: glibc 2.28+ ARM64
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.11.8 {"installer":{"name":"uv","version":"0.11.8","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for ember_api-0.1.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl
Algorithm Hash digest
SHA256 6634565493839fd29c26dc820e1c451f05cfd4281fe94a8a2499ae64e5c3eb59
MD5 2447c26168c83afac17d61a109186989
BLAKE2b-256 51a03b81c154b43645864e5eb9cea1e1405d63808c3385daceffaa2c612eea87

See more details on using hashes here.

File details

Details for the file ember_api-0.1.0-cp313-cp313-macosx_11_0_x86_64.whl.

File metadata

  • Download URL: ember_api-0.1.0-cp313-cp313-macosx_11_0_x86_64.whl
  • Upload date:
  • Size: 1.4 MB
  • Tags: CPython 3.13, macOS 11.0+ x86-64
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.11.8 {"installer":{"name":"uv","version":"0.11.8","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for ember_api-0.1.0-cp313-cp313-macosx_11_0_x86_64.whl
Algorithm Hash digest
SHA256 15c8c136c8f098d9978fd3af6415b035fe0756fa3fd7b5fec3b64cd1993f71ae
MD5 0d00e9c281c42e334416b827ec689620
BLAKE2b-256 2265aa77a73c5145506b9ef619e1f7878d42a3ca8b7afc7e2c84bf63ca30ad45

See more details on using hashes here.

File details

Details for the file ember_api-0.1.0-cp313-cp313-macosx_11_0_arm64.whl.

File metadata

  • Download URL: ember_api-0.1.0-cp313-cp313-macosx_11_0_arm64.whl
  • Upload date:
  • Size: 1.4 MB
  • Tags: CPython 3.13, macOS 11.0+ ARM64
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.11.8 {"installer":{"name":"uv","version":"0.11.8","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for ember_api-0.1.0-cp313-cp313-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 2a1e60e5d6106246f319026c90c0766625ec6842565ea69b7be40ee1412be49e
MD5 7bede9896e06aacfa4eddb201276b0cb
BLAKE2b-256 8e5482f151c659c8014fd8341259b80971168ece22f098a3ca11a19d9b4896c5

See more details on using hashes here.

File details

Details for the file ember_api-0.1.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl.

File metadata

  • Download URL: ember_api-0.1.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl
  • Upload date:
  • Size: 1.8 MB
  • Tags: CPython 3.12, manylinux: glibc 2.17+ x86-64, manylinux: glibc 2.28+ x86-64
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.11.8 {"installer":{"name":"uv","version":"0.11.8","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for ember_api-0.1.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 6a4bae46ced0f34b34d3feb0a6fddf007e4ff600e6b20a01aaef2384c1b2afca
MD5 d2e156949848dce10be1ba2625118f30
BLAKE2b-256 d34a2468ad2dcdd5263435f104e30145e57a75a845756d854de090fd0d0e4d2b

See more details on using hashes here.

File details

Details for the file ember_api-0.1.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl.

File metadata

  • Download URL: ember_api-0.1.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl
  • Upload date:
  • Size: 1.7 MB
  • Tags: CPython 3.12, manylinux: glibc 2.17+ ARM64, manylinux: glibc 2.28+ ARM64
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.11.8 {"installer":{"name":"uv","version":"0.11.8","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for ember_api-0.1.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl
Algorithm Hash digest
SHA256 5f8925a9966211b6d4c60495d92579f84525496f1d48001f8932550cd18316af
MD5 6ef0fbcc02a03cf98478ece0e815bcc3
BLAKE2b-256 67ffe4f8f5c75177b32eddffc66d65e6437435228f667c1d46b53bfddf479410

See more details on using hashes here.

File details

Details for the file ember_api-0.1.0-cp312-cp312-macosx_11_0_x86_64.whl.

File metadata

  • Download URL: ember_api-0.1.0-cp312-cp312-macosx_11_0_x86_64.whl
  • Upload date:
  • Size: 1.4 MB
  • Tags: CPython 3.12, macOS 11.0+ x86-64
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.11.8 {"installer":{"name":"uv","version":"0.11.8","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for ember_api-0.1.0-cp312-cp312-macosx_11_0_x86_64.whl
Algorithm Hash digest
SHA256 fe095fb3f122e1f0f80460885b35780f6662ce407b9053048ef6c387afe79be0
MD5 6241361b08ec22f10c601dd51b6e4659
BLAKE2b-256 c95e74d90784311efe399d079f6e7ff5928408f3e0f25c8e4f9df00bc528ea14

See more details on using hashes here.

File details

Details for the file ember_api-0.1.0-cp312-cp312-macosx_11_0_arm64.whl.

File metadata

  • Download URL: ember_api-0.1.0-cp312-cp312-macosx_11_0_arm64.whl
  • Upload date:
  • Size: 1.3 MB
  • Tags: CPython 3.12, macOS 11.0+ ARM64
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.11.8 {"installer":{"name":"uv","version":"0.11.8","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for ember_api-0.1.0-cp312-cp312-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 a2ec777627cc07956f98ae276b015c3e039bb0253b5b885d36cc36273dcbb94c
MD5 245d7aaba0c2937d6dce1d047f3d153d
BLAKE2b-256 781c68e1eab4fb7e45573e13dfb1a813ec5ec189c2cfa324846b1e56f524fa7e

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page