7087ca0
commit 7087ca0
1 file changed
+67 -75
Showing 1 changed file+67-75
▼README.md
+67-75
| @@ -39,36 +39,29 @@ | ||
39 | 39 | |
40 | 40 | --- |
41 | 41 | |
42 | -JustAPI is a modern, **blazing-fast** web framework for building APIs with Python, powered by a **Rust core**. It's designed as a **drop-in replacement for FastAPI** — same decorator syntax, same Pydantic models, same developer experience — but with the entire networking, routing, serialization, and middleware stack written in Rust. | |
42 | +JustAPI is a Rust-powered Python web framework for building APIs. It is designed as a **drop-in replacement for FastAPI** — same decorator syntax, same Pydantic models, same developer experience — but with networking, routing, serialization, and middleware implemented in Rust rather than Python. | |
43 | 43 | |
44 | 44 | **Python writes the logic. Rust does everything else.** |
45 | 45 | |
46 | -The key features are: | |
47 | 46 | |
48 | -* **Fast**: **700,000+ req/s** on a single machine — 20× faster than FastAPI+Uvicorn. The Rust runtime handles networking, TLS, routing, serialization, and middleware at near-native speed. | |
49 | -* **FastAPI-compatible**: Same `@app.get()` decorators, same Pydantic models, same dependency injection. **Migrate existing FastAPI apps with minimal changes.** | |
50 | -* **Type-safe**: Full `.pyi` type stubs for every module. Autocomplete and type checking work out of the box in VS Code, PyCharm, and Neovim. | |
51 | -* **Production-ready**: Built-in JWT auth, rate limiting, circuit breakers, distributed tracing (OpenTelemetry), Prometheus metrics, and health checks — all in Rust, not Python middleware. | |
52 | -* **Standards-based**: Auto-generated **OpenAPI 3.1** docs, **JSON Schema** validation, **gRPC** and **GraphQL** support. | |
53 | -* **Batteries included**: WebSockets, SSE, background tasks, dependency injection, database ORM, file uploads, static files, template rendering, and a plugin system — all from a single `pip install`. | |
54 | 47 | |
55 | 48 | ## Performance |
56 | 49 | |
57 | -<p align="center"> | |
58 | -<em>Hello-world benchmark · 100 concurrent connections · 30 seconds · same hardware</em> | |
59 | -</p> | |
50 | +*Hello-world benchmark · 100 concurrent connections · 30 seconds · same hardware* | |
60 | 51 | |
61 | 52 | | Framework | Requests/sec | p50 Latency | p99 Latency | |
62 | 53 | |---|--:|--:|--:| |
63 | -| **JustAPI** 🦀 | **701,234** | **0.07 ms** | **0.19 ms** | | |
54 | +| **JustAPI (native fast path)** | **701,234** | **0.07 ms** | **0.19 ms** | | |
55 | +| **JustAPI (Python handler)** | **60,297** | **1.03 ms** | **5.21 ms** | | |
56 | +| Robyn 0.88 | 39,103 | 1.78 ms | 11.47 ms | | |
64 | 57 | | Granian | 69,195 | 0.72 ms | 3.87 ms | |
65 | 58 | | FastAPI + Uvicorn | 36,189 | 1.72 ms | 24.63 ms | |
66 | 59 | |
67 | -> **20× faster than FastAPI** and **10× faster than Granian** on the same workload. See [BENCHMARKS.md](BENCHMARKS.md) for full methodology, hardware specs, and JSON/echo benchmarks. | |
60 | +All measurements on the same hardware (i5-13600K, 20 threads), 100 concurrent connections, 30s duration. See [BENCHMARKS.md](BENCHMARKS.md) for full methodology and workload scripts. | |
68 | 61 | |
69 | -### How is this possible? | |
62 | +### Request pipeline | |
70 | 63 | |
71 | -JustAPI moves the entire request pipeline out of Python: | |
64 | +JustAPI runs the entire request path in Rust. Python executes only application logic: | |
72 | 65 | |
73 | 66 | ``` |
74 | 67 | Kernel (epoll/io_uring) |
| @@ -77,45 +70,53 @@ Kernel (epoll/io_uring) | ||
77 | 70 | → HTTP parse (hyper) |
78 | 71 | → Router (matchit) |
79 | 72 | → Middleware chain (Rust: auth, CORS, rate-limit, compression) |
80 | - → Python boundary (zero-copy via PyO3 buffer protocol) | |
81 | - → Your application code (async Python) | |
82 | - → Rust serializer (serde_json / simd-json) | |
73 | + → ┌─────────────────────────────────────────────────────┐ | |
74 | + │ Python handler path (default): │ | |
75 | + │ → Python boundary (zero-copy via PyO3 buffer) │ | |
76 | + │ → Your async Python handler │ | |
77 | + │ → Rust serializer (serde_json / simd-json) │ | |
78 | + ├─────────────────────────────────────────────────────┤ | |
79 | + │ Native fast path (native=True + Schema): │ | |
80 | + │ → Rust validator → Rust response (no Python) │ | |
81 | + └─────────────────────────────────────────────────────┘ | |
83 | 82 | → Response write → Socket |
84 | 83 | ``` |
85 | 84 | |
86 | -Python only executes **your** business logic. Everything else — TLS, parsing, routing, auth, serialization, compression — runs in Rust at native speed with zero GIL contention. | |
85 | +The Python path is used for general routes. For schema-backed routes with `native=True`, the entire handler executes in Rust — eliminating the GIL acquire, Python dispatch, and per-request JSON schema compilation. | |
87 | 86 | |
88 | 87 | ## What makes JustAPI different |
89 | 88 | |
90 | -Two things, stated plainly: | |
89 | +1. **Rust-native request pipeline.** Networking, TLS, routing, serialization, middleware, and auth all execute in Rust — Python runs only your application logic. This yields ~60k rps on the Python handler path and ~724k rps on the native fast path for schema-backed routes, both measured on a single machine. | |
91 | 90 | |
92 | -1. **Throughput.** A Rust networking core (hyper + tokio + rustls) moves TLS, | |
93 | - routing, serialization, and middleware out of Python. The number above | |
94 | - (701k req/s hello-world) is the payoff — ~20× FastAPI+Uvicorn on that | |
95 | - workload. | |
96 | -2. **Agent-native serving.** Beyond REST, JustAPI has a first-class | |
97 | - introspection + tool-serving layer for AI agents: every app can expose its | |
98 | - routes as MCP tools (`python -m justapi.mcp_server`), stream *validated* | |
99 | - structured output as tokens arrive, and carry multi-turn session state — | |
100 | - without bolting a third-party SDK onto generic HTTP routes. This is the part | |
101 | - we invest in most; see [`ROADMAP.md`](ROADMAP.md) for how far it goes. | |
91 | +2. **Agent-native serving.** Beyond REST, JustAPI exposes routes as MCP tools, streams validated structured output per-token, and carries multi-turn session state — without external SDKs. See [`ROADMAP.md`](ROADMAP.md) for the full agent roadmap. | |
102 | 92 | |
103 | 93 | ## Competitors, named honestly |
104 | 94 | |
105 | -We are not the first Rust-backed Python framework, and we don't claim to be: | |
95 | +JustAPI is not the first Rust-backed Python web framework. The following table compares the closest alternatives on raw throughput (Python handler path, same hardware): | |
96 | + | |
97 | +| Workload | JustAPI | Robyn 0.88 | Faster | | |
98 | +|---|---:|---:|---| | |
99 | +| Hello-world (GET) | 60,297 rps | 39,103 rps | JustAPI ×1.54 | | |
100 | +| JSON echo (POST) | 47,415 rps | 36,899 rps | JustAPI ×1.29 | | |
101 | +| Validated JSON (POST) | 40,080 rps | 32,919 rps | JustAPI ×1.22 | | |
102 | + | |
103 | +For routes registered with `native=True` and a schema, JustAPI serves entirely in Rust at **~724k rps** — bypassing the Python handler entirely. | |
104 | + | |
105 | +### Where each competitor fits | |
106 | + | |
107 | +- **Robyn** — Rust runtime with a decorator API, the closest architectural peer. Both frameworks keep the hot path in Rust and dispatch to Python for business logic. JustAPI's edge is: (a) measured throughput advantage on all three standard workloads, (b) a native fast path (`native=True`) that eliminates the Python dispatch entirely for schema-backed routes, (c) an ASGI shim for compatibility with the Starlette middleware ecosystem, and (d) built-in MCP agent serving as a first-class primitive rather than an add-on. | |
108 | + | |
109 | +- **Granian** — Rust ASGI *server*. It drops under existing FastAPI/Starlette apps without changing framework code. If your goal is a faster transport layer without migrating frameworks, Granian is the lower-friction choice. JustAPI wins when you want the full Rust stack — routing, serialization, middleware, auth, and agent serving — all native. | |
106 | 110 | |
107 | -- **Robyn** — Rust runtime, decorator API, commonly cited ~40–60% faster than | |
108 | - FastAPI on simple endpoints. Real project; we benchmark against it. | |
109 | -- **Granian** — Rust *ASGI server* that drops under existing ASGI apps. Different | |
110 | - bet: it replaces the server, not the framework. | |
111 | -- **Litestar** / **BlackSheep** — Python frameworks with first-class ASGI and | |
112 | - rich feature sets; we borrow ergonomics from them. | |
113 | -- **FastAPI** — the compatibility target. JustAPI mirrors its decorator API and | |
114 | - Pydantic models so migration is low-friction. | |
111 | +- **Litestar / BlackSheep** — Python-native frameworks with first-class ASGI support and rich feature sets (DI, validation, OpenAPI). JustAPI shares their design philosophy for ergonomics but implements the critical path in Rust. Migration from these is similar to FastAPI. | |
115 | 112 | |
116 | -Where we deliberately differ from Robyn: JustAPI keeps an **ASGI shim** (so it | |
117 | -runs under Uvicorn/Granian and reuses Starlette-ecosystem middleware) and treats | |
118 | -agent/MCP serving as a built-in primitive rather than an afterthought. | |
113 | +- **FastAPI** — the compatibility target. JustAPI mirrors its decorator API and Pydantic model integration so existing FastAPI applications can migrate with minimal changes — often just the import statement. | |
114 | + | |
115 | +### Honest caveats | |
116 | + | |
117 | +- **Native fast path requires a schema.** Routes without a `Schema` registered fall back to the Python handler path (~60k rps). The 724k rps number only applies to routes with `native=True` + `Schema`. | |
118 | +- **Python handler throughput is GIL-bound.** On CPython, the Python dispatch path is capped at ~100-120k rps on this hardware regardless of framework — that is the GIL, not a framework limitation. Free-threaded Python (3.13t/3.14t) removes this ceiling. | |
119 | +- **Agent-native workloads are the differentiator.** The benchmarks that matter most for JustAPI are structured-LLM streaming, MCP tool dispatch, and durable agent sessions — not hello-world req/s. These workloads are impossible or awkward in every alternative listed above. | |
119 | 120 | |
120 | 121 | ## Non-goals & not-yet-built |
121 | 122 | |
| @@ -190,8 +191,6 @@ def read_item(item_id: int, q: str | None = None): | ||
190 | 191 | |
191 | 192 | ### Run it |
192 | 193 | |
193 | -<div class="termy"> | |
194 | - | |
195 | 194 | ```console |
196 | 195 | $ python main.py |
197 | 196 | |
| @@ -199,8 +198,6 @@ INFO: JustAPI running on http://127.0.0.1:8000 | ||
199 | 198 | INFO: Rust runtime started with 4 worker threads |
200 | 199 | ``` |
201 | 200 | |
202 | -</div> | |
203 | - | |
204 | 201 | ### Check it |
205 | 202 | |
206 | 203 | Open your browser at <a href="http://127.0.0.1:8000/items/5?q=somequery" target="_blank">http://127.0.0.1:8000/items/5?q=somequery</a>. |
| @@ -337,49 +334,44 @@ justapi create jsonrpc_api --db sqlite --api-type jsonrpc | ||
337 | 334 | |
338 | 335 | ## Features |
339 | 336 | |
340 | -### FastAPI-compatible, Rust-accelerated | |
341 | - | |
342 | - | |
343 | -JustAPI gives you the same developer experience as FastAPI, but with a Rust engine underneath. Here's what you get: | |
344 | - | |
345 | 337 | <table> |
346 | 338 | <tr><th>Category</th><th>Feature</th><th>Details</th></tr> |
347 | 339 | |
348 | -<tr><td rowspan="4"><strong>🚀 Performance</strong></td> | |
349 | - <td>HTTP/1.1 & HTTP/2</td><td>700k+ req/s hello-world</td></tr> | |
340 | +<tr><td rowspan="4"><strong>Performance</strong></td> | |
341 | + <td>HTTP/1.1 & HTTP/2</td><td>700k+ req/s (native fast path)</td></tr> | |
350 | 342 | <tr><td>TLS (rustls)</td><td>~10% overhead, no OpenSSL dependency</td></tr> |
351 | 343 | <tr><td>Serialization</td><td>serde_json with optional simd-json</td></tr> |
352 | 344 | <tr><td>Compression</td><td>gzip / deflate / brotli / zstd</td></tr> |
353 | 345 | |
354 | -<tr><td rowspan="5"><strong>🔒 Security</strong></td> | |
346 | +<tr><td rowspan="5"><strong>Security</strong></td> | |
355 | 347 | <td>JWT Authentication</td><td>RS256/ES256, per-route roles & scopes</td></tr> |
356 | 348 | <tr><td>Rate Limiting</td><td>GCRA algorithm, Redis-backed distributed</td></tr> |
357 | 349 | <tr><td>CORS</td><td>Configurable, preflight caching</td></tr> |
358 | 350 | <tr><td>Request Validation</td><td>JSON Schema, Pydantic v2 bridge</td></tr> |
359 | 351 | <tr><td>Security Headers</td><td>HSTS, CSP, X-Frame-Options, etc.</td></tr> |
360 | 352 | |
361 | -<tr><td rowspan="5"><strong>📡 Protocols</strong></td> | |
353 | +<tr><td rowspan="5"><strong>Protocols</strong></td> | |
362 | 354 | <td>REST</td><td>Full HTTP method support with OpenAPI 3.1</td></tr> |
363 | 355 | <tr><td>WebSocket</td><td>Full-duplex with streaming support</td></tr> |
364 | 356 | <tr><td>Server-Sent Events</td><td>Token-generation optimized streaming</td></tr> |
365 | 357 | <tr><td>gRPC</td><td>Native Tonic integration</td></tr> |
366 | 358 | <tr><td>GraphQL</td><td>async-graphql with Apollo Federation</td></tr> |
367 | 359 | |
368 | -<tr><td rowspan="5"><strong>🧩 Application</strong></td> | |
360 | +<tr><td rowspan="5"><strong>Application</strong></td> | |
369 | 361 | <td>Dependency Injection</td><td>Litestar-style tiered DI container</td></tr> |
370 | 362 | <tr><td>Background Tasks</td><td>Thread-safe task scheduling</td></tr> |
371 | 363 | <tr><td>Database ORM</td><td>SQLite / PostgreSQL / MySQL via sqlx</td></tr> |
372 | 364 | <tr><td>Template Engine</td><td>Jinja2 integration</td></tr> |
373 | 365 | <tr><td>File Uploads</td><td>Streaming multipart/form-data</td></tr> |
374 | 366 | |
375 | -<tr><td rowspan="5"><strong>🔧 Operations</strong></td> | |
367 | +<tr><td rowspan="5"><strong>Operations</strong></td> | |
376 | 368 | <td>Observability</td><td>OpenTelemetry tracing, Prometheus metrics</td></tr> |
377 | 369 | <tr><td>Resilience</td><td>Circuit breakers, retry, fallback, bulkhead</td></tr> |
378 | 370 | <tr><td>Health Checks</td><td>Liveness & readiness probe endpoints</td></tr> |
379 | 371 | <tr><td>Plugin System</td><td>Third-party extension API with lifecycle hooks</td></tr> |
380 | 372 | <tr><td>WASM Plugins</td><td>wasmtime-powered WebAssembly middleware</td></tr> |
381 | 373 | |
382 | -<tr><td rowspan="4"><strong>🛡️ Quality</strong></td> | |
374 | +<tr><td rowspan="4"><strong>Quality</strong></td> | |
383 | 375 | <td>Memory Safety</td><td>Miri-verified, 6 fuzz targets</td></tr> |
384 | 376 | <tr><td>Supply Chain Security</td><td>cargo-deny v0.20 — advisories, bans, licenses, sources</td></tr> |
385 | 377 | <tr><td>Type Stubs</td><td>Complete .pyi for all public modules</td></tr> |
| @@ -409,13 +401,13 @@ JustAPI is designed to feel familiar. Here's a side-by-side: | ||
409 | 401 | </tr> |
410 | 402 | <tr> |
411 | 403 | <td><strong>Pydantic</strong></td> |
412 | -<td>✅ Native</td> | |
413 | -<td>✅ Native</td> | |
404 | +<td>Native</td> | |
405 | +<td>Native</td> | |
414 | 406 | </tr> |
415 | 407 | <tr> |
416 | 408 | <td><strong>Depends()</strong></td> |
417 | -<td>✅ Built-in</td> | |
418 | -<td>✅ Built-in</td> | |
409 | +<td>Built-in</td> | |
410 | +<td>Built-in</td> | |
419 | 411 | </tr> |
420 | 412 | <tr> |
421 | 413 | <td><strong>OpenAPI docs</strong></td> |
| @@ -441,19 +433,19 @@ JustAPI is designed to feel familiar. Here's a side-by-side: | ||
441 | 433 | ``` |
442 | 434 | justapi/ |
443 | 435 | ├── crates/ |
444 | -│ ├── justapi-core/ # 🦀 Networking, routing, middleware, serialization | |
445 | -│ ├── justapi-py/ # 🐍 PyO3 bindings, ASGI shim, native Python API | |
446 | -│ ├── justapi-cli/ # ⚡ CLI binary (serve, gen-client, profile) | |
447 | -│ ├── justapi-bench/ # 📊 Internal benchmark harness | |
448 | -│ └── justapi-inference/ # 🧠 ML inference engine (optional) | |
449 | -├── examples/ # 📖 10 progressive tutorial examples | |
450 | -├── tests/ # 🧪 End-to-end integration tests | |
451 | -├── fuzz/ # 🔒 6 cargo-fuzz security targets | |
452 | -├── docs/ # 📚 MkDocs documentation site | |
453 | -├── deploy/ # ☁️ Multi-cloud deployment guides | |
454 | - | |