django-bolt 0.1.0__cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of django-bolt might be problematic. Click here for more details.
- django_bolt/__init__.py +147 -0
- django_bolt/_core.abi3.so +0 -0
- django_bolt/admin/__init__.py +25 -0
- django_bolt/admin/admin_detection.py +179 -0
- django_bolt/admin/asgi_bridge.py +267 -0
- django_bolt/admin/routes.py +91 -0
- django_bolt/admin/static.py +155 -0
- django_bolt/admin/static_routes.py +111 -0
- django_bolt/api.py +1011 -0
- django_bolt/apps.py +7 -0
- django_bolt/async_collector.py +228 -0
- django_bolt/auth/README.md +464 -0
- django_bolt/auth/REVOCATION_EXAMPLE.md +391 -0
- django_bolt/auth/__init__.py +84 -0
- django_bolt/auth/backends.py +236 -0
- django_bolt/auth/guards.py +224 -0
- django_bolt/auth/jwt_utils.py +212 -0
- django_bolt/auth/revocation.py +286 -0
- django_bolt/auth/token.py +335 -0
- django_bolt/binding.py +363 -0
- django_bolt/bootstrap.py +77 -0
- django_bolt/cli.py +133 -0
- django_bolt/compression.py +104 -0
- django_bolt/decorators.py +159 -0
- django_bolt/dependencies.py +128 -0
- django_bolt/error_handlers.py +305 -0
- django_bolt/exceptions.py +294 -0
- django_bolt/health.py +129 -0
- django_bolt/logging/__init__.py +6 -0
- django_bolt/logging/config.py +357 -0
- django_bolt/logging/middleware.py +296 -0
- django_bolt/management/__init__.py +1 -0
- django_bolt/management/commands/__init__.py +0 -0
- django_bolt/management/commands/runbolt.py +427 -0
- django_bolt/middleware/__init__.py +32 -0
- django_bolt/middleware/compiler.py +131 -0
- django_bolt/middleware/middleware.py +247 -0
- django_bolt/openapi/__init__.py +23 -0
- django_bolt/openapi/config.py +196 -0
- django_bolt/openapi/plugins.py +439 -0
- django_bolt/openapi/routes.py +152 -0
- django_bolt/openapi/schema_generator.py +581 -0
- django_bolt/openapi/spec/__init__.py +68 -0
- django_bolt/openapi/spec/base.py +74 -0
- django_bolt/openapi/spec/callback.py +24 -0
- django_bolt/openapi/spec/components.py +72 -0
- django_bolt/openapi/spec/contact.py +21 -0
- django_bolt/openapi/spec/discriminator.py +25 -0
- django_bolt/openapi/spec/encoding.py +67 -0
- django_bolt/openapi/spec/enums.py +41 -0
- django_bolt/openapi/spec/example.py +36 -0
- django_bolt/openapi/spec/external_documentation.py +21 -0
- django_bolt/openapi/spec/header.py +132 -0
- django_bolt/openapi/spec/info.py +50 -0
- django_bolt/openapi/spec/license.py +28 -0
- django_bolt/openapi/spec/link.py +66 -0
- django_bolt/openapi/spec/media_type.py +51 -0
- django_bolt/openapi/spec/oauth_flow.py +36 -0
- django_bolt/openapi/spec/oauth_flows.py +28 -0
- django_bolt/openapi/spec/open_api.py +87 -0
- django_bolt/openapi/spec/operation.py +105 -0
- django_bolt/openapi/spec/parameter.py +147 -0
- django_bolt/openapi/spec/path_item.py +78 -0
- django_bolt/openapi/spec/paths.py +27 -0
- django_bolt/openapi/spec/reference.py +38 -0
- django_bolt/openapi/spec/request_body.py +38 -0
- django_bolt/openapi/spec/response.py +48 -0
- django_bolt/openapi/spec/responses.py +44 -0
- django_bolt/openapi/spec/schema.py +678 -0
- django_bolt/openapi/spec/security_requirement.py +28 -0
- django_bolt/openapi/spec/security_scheme.py +69 -0
- django_bolt/openapi/spec/server.py +34 -0
- django_bolt/openapi/spec/server_variable.py +32 -0
- django_bolt/openapi/spec/tag.py +32 -0
- django_bolt/openapi/spec/xml.py +44 -0
- django_bolt/pagination.py +669 -0
- django_bolt/param_functions.py +49 -0
- django_bolt/params.py +337 -0
- django_bolt/request_parsing.py +128 -0
- django_bolt/responses.py +214 -0
- django_bolt/router.py +48 -0
- django_bolt/serialization.py +193 -0
- django_bolt/status_codes.py +321 -0
- django_bolt/testing/__init__.py +10 -0
- django_bolt/testing/client.py +274 -0
- django_bolt/testing/helpers.py +93 -0
- django_bolt/tests/__init__.py +0 -0
- django_bolt/tests/admin_tests/__init__.py +1 -0
- django_bolt/tests/admin_tests/conftest.py +6 -0
- django_bolt/tests/admin_tests/test_admin_with_django.py +278 -0
- django_bolt/tests/admin_tests/urls.py +9 -0
- django_bolt/tests/cbv/__init__.py +0 -0
- django_bolt/tests/cbv/test_class_views.py +570 -0
- django_bolt/tests/cbv/test_class_views_django_orm.py +703 -0
- django_bolt/tests/cbv/test_class_views_features.py +1173 -0
- django_bolt/tests/cbv/test_class_views_with_client.py +622 -0
- django_bolt/tests/conftest.py +165 -0
- django_bolt/tests/test_action_decorator.py +399 -0
- django_bolt/tests/test_auth_secret_key.py +83 -0
- django_bolt/tests/test_decorator_syntax.py +159 -0
- django_bolt/tests/test_error_handling.py +481 -0
- django_bolt/tests/test_file_response.py +192 -0
- django_bolt/tests/test_global_cors.py +172 -0
- django_bolt/tests/test_guards_auth.py +441 -0
- django_bolt/tests/test_guards_integration.py +303 -0
- django_bolt/tests/test_health.py +283 -0
- django_bolt/tests/test_integration_validation.py +400 -0
- django_bolt/tests/test_json_validation.py +536 -0
- django_bolt/tests/test_jwt_auth.py +327 -0
- django_bolt/tests/test_jwt_token.py +458 -0
- django_bolt/tests/test_logging.py +837 -0
- django_bolt/tests/test_logging_merge.py +419 -0
- django_bolt/tests/test_middleware.py +492 -0
- django_bolt/tests/test_middleware_server.py +230 -0
- django_bolt/tests/test_model_viewset.py +323 -0
- django_bolt/tests/test_models.py +24 -0
- django_bolt/tests/test_pagination.py +1258 -0
- django_bolt/tests/test_parameter_validation.py +178 -0
- django_bolt/tests/test_syntax.py +626 -0
- django_bolt/tests/test_testing_utilities.py +163 -0
- django_bolt/tests/test_testing_utilities_simple.py +123 -0
- django_bolt/tests/test_viewset_unified.py +346 -0
- django_bolt/typing.py +273 -0
- django_bolt/views.py +1110 -0
- django_bolt-0.1.0.dist-info/METADATA +629 -0
- django_bolt-0.1.0.dist-info/RECORD +128 -0
- django_bolt-0.1.0.dist-info/WHEEL +4 -0
- django_bolt-0.1.0.dist-info/entry_points.txt +2 -0
|
@@ -0,0 +1,629 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: django-bolt
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Classifier: Development Status :: 3 - Alpha
|
|
5
|
+
Classifier: Intended Audience :: Developers
|
|
6
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
7
|
+
Classifier: Programming Language :: Python :: 3
|
|
8
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
9
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
10
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
13
|
+
Classifier: Programming Language :: Python :: Implementation :: CPython
|
|
14
|
+
Classifier: Programming Language :: Python :: Implementation :: PyPy
|
|
15
|
+
Classifier: Programming Language :: Rust
|
|
16
|
+
Classifier: Framework :: Django
|
|
17
|
+
Classifier: Framework :: Django :: 4.2
|
|
18
|
+
Classifier: Framework :: Django :: 5.0
|
|
19
|
+
Classifier: Framework :: Django :: 5.1
|
|
20
|
+
Classifier: Topic :: Internet :: WWW/HTTP
|
|
21
|
+
Classifier: Topic :: Internet :: WWW/HTTP :: HTTP Servers
|
|
22
|
+
Classifier: Topic :: Software Development :: Libraries :: Application Frameworks
|
|
23
|
+
Requires-Dist: django>=4.2
|
|
24
|
+
Requires-Dist: click>=8.1
|
|
25
|
+
Requires-Dist: pydantic>=2
|
|
26
|
+
Requires-Dist: msgspec>=0.18
|
|
27
|
+
Requires-Dist: maturin>=1.9.4
|
|
28
|
+
Requires-Dist: watchfiles>=0.24
|
|
29
|
+
Requires-Dist: pyyaml>=6.0
|
|
30
|
+
Requires-Dist: multipart>=1.3
|
|
31
|
+
Summary: High-performance API framework for Django with Rust-powered endpoints delivering 60k+ RPS
|
|
32
|
+
Keywords: django,api,rust,performance,actix,pyo3,async
|
|
33
|
+
Author-email: Farhan <farhanalirazaazeemi@gmail.com>
|
|
34
|
+
License: MIT
|
|
35
|
+
Requires-Python: >=3.10
|
|
36
|
+
Description-Content-Type: text/markdown; charset=UTF-8; variant=GFM
|
|
37
|
+
Project-URL: Homepage, https://github.com/FarhanAliRaza/django-bolt
|
|
38
|
+
Project-URL: Repository, https://github.com/FarhanAliRaza/django-bolt
|
|
39
|
+
Project-URL: Documentation, https://github.com/FarhanAliRaza/django-bolt#readme
|
|
40
|
+
Project-URL: Bug Tracker, https://github.com/FarhanAliRaza/django-bolt/issues
|
|
41
|
+
|
|
42
|
+
<div align="center">
|
|
43
|
+
<img src="docs/logo.png" alt="Django-Bolt Logo" width="400"/>
|
|
44
|
+
|
|
45
|
+
[](mailto:farhanalirazaazeemi@gmail.com)
|
|
46
|
+
</div>
|
|
47
|
+
|
|
48
|
+
**High-Performance Fully Typed API Framework for Django**
|
|
49
|
+
|
|
50
|
+
Django-Bolt is a high-performance API framework for Django that provides Rust-powered API endpoints capable of **60k+ RPS** performance. Similar to Django REST Framework or Django Ninja, it integrates seamlessly with existing Django projects while leveraging Actix Web for HTTP handling, PyO3 to bridge Python async handlers with Rust's async runtime, msgspec for fast serialization, and supports multi-process scaling with SO_REUSEPORT.
|
|
51
|
+
|
|
52
|
+
**Key Features:**
|
|
53
|
+
|
|
54
|
+
- 🚀 **High Performance** - Rust-powered HTTP server (Actix Web + Tokio + PYO3)
|
|
55
|
+
- 🔐 **Authentication in Rust** - JWT/API Key validation without Python GIL
|
|
56
|
+
- 📦 **msgspec Serialization** - 5-10x faster than standard JSON
|
|
57
|
+
- 🎯 **Django Integration** - Use your existing Django models and other django features you love (django admin, django packages (All django packages will work except that use django middlware for now. I will work on some compatibilty layer to make them work but it is not a priority right now) )
|
|
58
|
+
- 🔄 **Async/Await** - Full async support with Python coroutines
|
|
59
|
+
- 🎛️ **Middleware System** - CORS, rate limiting, compression, custom middleware
|
|
60
|
+
- 🔒 **Guards & Permissions** - DRF and litestar inspired route protection
|
|
61
|
+
|
|
62
|
+
---
|
|
63
|
+
|
|
64
|
+
## 🚀 Quick Start
|
|
65
|
+
|
|
66
|
+
### Installation
|
|
67
|
+
|
|
68
|
+
COMING VERY SOON NEAR YOUR DJANGO PROJECTS
|
|
69
|
+
|
|
70
|
+
For now you can build and use it locally if you want.
|
|
71
|
+
|
|
72
|
+
### Run Your First API
|
|
73
|
+
|
|
74
|
+
```python
|
|
75
|
+
# myproject/api.py
|
|
76
|
+
from django_bolt import BoltAPI
|
|
77
|
+
from django.contrib.auth.models import User
|
|
78
|
+
import msgspec
|
|
79
|
+
|
|
80
|
+
api = BoltAPI()
|
|
81
|
+
|
|
82
|
+
class UserSchema(msgspec.Struct):
|
|
83
|
+
id: str
|
|
84
|
+
username: str
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
@api.get("/users/{user_id}")
|
|
88
|
+
async def get_user(user_id: int) -> UserSchema: # 🎉 Reponse is type validated
|
|
89
|
+
user = await User.objects.aget(id=user_id) # 🤯 Yes and Django orm works without any setup
|
|
90
|
+
return {"id": user.id, "username": user.username} # or you could just return the queryset
|
|
91
|
+
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
```bash
|
|
95
|
+
# Start the server
|
|
96
|
+
python manage.py runbolt --host 0.0.0.0 --port 8000 --processes 4 --workers 1
|
|
97
|
+
# processes are python processes that handle request 1 actix worker
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
---
|
|
101
|
+
|
|
102
|
+
## 📊 Performance Benchmarks
|
|
103
|
+
|
|
104
|
+
> **⚠️ Disclaimer:** Django-Bolt is a **feature-incomplete framework** currently in development. Benchmarks were run on a Ryzen 5600G with 16GB RAM (8 processes × 1 worker, C=100 N=10000) on localhost. Performance will vary significantly based on hardware, OS, configuration, and workload.
|
|
105
|
+
>
|
|
106
|
+
> **📁 Resources:** Example project available at [python/examples/testproject/](python/examples/testproject/). Run benchmarks with `make save-bench` or see [scripts/benchmark.sh](scripts/benchmark.sh).
|
|
107
|
+
|
|
108
|
+
| Endpoint Type | Requests/sec |
|
|
109
|
+
| -------------------------- | --------------- |
|
|
110
|
+
| Root endpoint | **~86,500 RPS** |
|
|
111
|
+
| JSON parsing/validation | **~81,000 RPS** |
|
|
112
|
+
| Path + Query params | **~62,500 RPS** |
|
|
113
|
+
| HTML/Redirect responses | **~88,000 RPS** |
|
|
114
|
+
| Form data handling | **~69,000 RPS** |
|
|
115
|
+
| ORM reads (SQLite, 10 rec) | **~12,000 RPS** |
|
|
116
|
+
|
|
117
|
+
**Why so fast?**
|
|
118
|
+
|
|
119
|
+
- Authentication and guards run in Rust without the Python GIL
|
|
120
|
+
- Request routing uses matchit (zero-copy path matching)
|
|
121
|
+
- No middleware overhead if not required
|
|
122
|
+
- JSON serialization with msgspec
|
|
123
|
+
- Multi-process with SO_REUSEPORT (kernel-level load balancing)
|
|
124
|
+
|
|
125
|
+
---
|
|
126
|
+
|
|
127
|
+
## ✅ What's Complete
|
|
128
|
+
|
|
129
|
+
### Core Framework ✅
|
|
130
|
+
|
|
131
|
+
- ✅ **Rust HTTP Server** - Actix Web with tokio async runtime
|
|
132
|
+
- ✅ **Fast Routing** - matchit-based routing with path parameters (`/items/{id}`)
|
|
133
|
+
- ✅ **Async Handlers** - Full async/await support (enforced async handlers)
|
|
134
|
+
- ✅ **Request/Response** - msgspec-based validation and serialization
|
|
135
|
+
- ✅ **Multiple Response Types**:
|
|
136
|
+
- `JSON` - msgspec-serialized JSON responses
|
|
137
|
+
- `PlainText` - Plain text responses
|
|
138
|
+
- `HTML` - HTML responses
|
|
139
|
+
- `Redirect` - HTTP redirects
|
|
140
|
+
- `File` - File downloads (in-memory)
|
|
141
|
+
- `FileResponse` - Streaming file responses (handled in Rust)
|
|
142
|
+
- `StreamingResponse` - Async streaming for large payloads
|
|
143
|
+
- ✅ **Parameter Injection**:
|
|
144
|
+
- Path parameters (`/items/{id}`)
|
|
145
|
+
- Query parameters (`?page=1&limit=10`)
|
|
146
|
+
- Headers (`Annotated[str, Header("x-api-key")]`)
|
|
147
|
+
- Cookies (`Annotated[str, Cookie("session")]`)
|
|
148
|
+
- Form data (`Annotated[str, Form("username")]`)
|
|
149
|
+
- File uploads (`Annotated[bytes, File("upload")]`)
|
|
150
|
+
- Request body (msgspec.Struct)
|
|
151
|
+
- ✅ **Dependency Injection** - `Depends()` system for reusable dependencies
|
|
152
|
+
- ✅ **Django ORM Integration** - Full access to Django models (async methods)
|
|
153
|
+
- ✅ **Multi-Process Scaling** - SO_REUSEPORT for horizontal scaling
|
|
154
|
+
- ✅ **Auto-Discovery** - Finds `api.py` in project root and all installed apps
|
|
155
|
+
|
|
156
|
+
### Middleware System ✅
|
|
157
|
+
|
|
158
|
+
- ✅ **Global Middleware** - Apply to all routes via `BoltAPI(middleware=[...])`
|
|
159
|
+
- ✅ **Per-Route Middleware** - `@middleware`, `@rate_limit`, `@cors` decorators
|
|
160
|
+
- ✅ **CORS Middleware** - Full CORS support with preflight
|
|
161
|
+
- ✅ **Rate Limiting** - Token bucket algorithm (in Rust, no GIL)
|
|
162
|
+
- ✅ **Compression** - Automatic gzip/brotli/zstd compression (client-negotiated)
|
|
163
|
+
- ✅ **Skip Middleware** - `@skip_middleware("cors", "rate_limit", "compression")`
|
|
164
|
+
- ✅ **Middleware Config** - Dictionary-based configuration
|
|
165
|
+
|
|
166
|
+
### Authentication & Authorization ✅
|
|
167
|
+
|
|
168
|
+
- ✅ **JWT Authentication** - **Complete** (runs in Rust without GIL)
|
|
169
|
+
|
|
170
|
+
- Algorithms: HS256, HS384, HS512, RS256, RS384, RS512, ES256, ES384, ES512
|
|
171
|
+
- Token validation in Rust (zero Python overhead)
|
|
172
|
+
- Expiration validation
|
|
173
|
+
- Custom claims support
|
|
174
|
+
- Django User integration helpers
|
|
175
|
+
- Token revocation support (optional)
|
|
176
|
+
|
|
177
|
+
- ✅ **API Key Authentication** - **Partial** (runs in Rust without GIL)
|
|
178
|
+
|
|
179
|
+
- Header-based API keys
|
|
180
|
+
- Per-key permissions
|
|
181
|
+
- Fast validation in Rust
|
|
182
|
+
|
|
183
|
+
- ✅ **Permission Guards** (all run in Rust):
|
|
184
|
+
|
|
185
|
+
- `AllowAny()` - Public access
|
|
186
|
+
- `IsAuthenticated()` - Requires valid auth
|
|
187
|
+
- `IsAdminUser()` - Requires admin/superuser
|
|
188
|
+
- `IsStaff()` - Requires staff status
|
|
189
|
+
- `HasPermission("perm")` - Single permission check
|
|
190
|
+
- `HasAnyPermission("p1", "p2")` - OR logic
|
|
191
|
+
- `HasAllPermissions("p1", "p2")` - AND logic
|
|
192
|
+
|
|
193
|
+
- ✅ **Auth Context** - Request-level auth context with user info
|
|
194
|
+
- ✅ **Token Utilities**:
|
|
195
|
+
|
|
196
|
+
- `create_jwt_for_user(user)` - Generate JWT for Django User
|
|
197
|
+
|
|
198
|
+
- ✅ **Token Revocation** (optional):
|
|
199
|
+
- `InMemoryRevocation` - In-memory token blacklist
|
|
200
|
+
- `DjangoCacheRevocation` - Cache-based revocation
|
|
201
|
+
- `DjangoORMRevocation` - Database-backed revocation
|
|
202
|
+
|
|
203
|
+
### Developer Tools ✅
|
|
204
|
+
|
|
205
|
+
- ✅ **CLI** - `python -m django_bolt init` for project setup
|
|
206
|
+
- ✅ **Management Command** - `python manage.py runbolt`
|
|
207
|
+
- ✅ **Auto-Discovery** - Finds APIs in all Django apps
|
|
208
|
+
- ⚠️ **Error Messages** - Clear error messages (In Progress)
|
|
209
|
+
- ✅ **Type Hints** - Full type hint support with msgspec
|
|
210
|
+
|
|
211
|
+
---
|
|
212
|
+
|
|
213
|
+
## 📋 TODO / Roadmap
|
|
214
|
+
|
|
215
|
+
### Must Have (Blockers) 🚨
|
|
216
|
+
|
|
217
|
+
- ✅ **Core API functionality** - DONE
|
|
218
|
+
- ✅ **Authentication** - DONE (JWT complete)
|
|
219
|
+
- ✅ **Tests passing** - DONE (142 passed)
|
|
220
|
+
- ✅ **Better error messages** - DONE (Enhanced exception system with structured errors)
|
|
221
|
+
- ✅ **Health check endpoints** - DONE (`/health`, `/ready` with custom checks)
|
|
222
|
+
- ✅ **Request/Response logging** - DONE (Integrates with Django's logging)
|
|
223
|
+
- ❌ **PyPI package** - Missing (currently manual install)
|
|
224
|
+
|
|
225
|
+
### Should Have (Important) 🎯
|
|
226
|
+
|
|
227
|
+
- ✅ **Error handling with Django DEBUG integration** - DONE
|
|
228
|
+
- ✅ **Structured error responses** (FastAPI-compatible) - DONE
|
|
229
|
+
- ✅ **Response compression** - DONE (gzip/brotli/zstd)
|
|
230
|
+
- ✅ **OpenAPI/Swagger docs** - DONE (some parts remaining like grouping)
|
|
231
|
+
- ✅ **Django admin integration** - DONE
|
|
232
|
+
- ⚠️ **API Key auth** - Partial (only in-memory)
|
|
233
|
+
- ⚠️ **Testing utilities** - Partial
|
|
234
|
+
|
|
235
|
+
### Nice to Have (Can defer) 📝
|
|
236
|
+
|
|
237
|
+
- [ ] **Static file serving** - Efficient static file serving from Rust
|
|
238
|
+
- [ ] **Pagination helpers** - Built-in pagination utilities
|
|
239
|
+
- [ ] **OAuth2/OpenID** - OAuth2 and OpenID Connect support
|
|
240
|
+
- [ ] **API Versioning** - URL/header-based versioning
|
|
241
|
+
- [ ] **Content Negotiation** - Accept header-based content negotiation
|
|
242
|
+
- [ ] **ETags & Conditional Requests** - Caching optimization
|
|
243
|
+
- [ ] **Filtering & Sorting** - Query parameter-based filtering
|
|
244
|
+
|
|
245
|
+
---
|
|
246
|
+
|
|
247
|
+
## 🏗️ Architecture
|
|
248
|
+
|
|
249
|
+
### Core Components
|
|
250
|
+
|
|
251
|
+
1. **[src/lib.rs](src/lib.rs)** - Main Rust entry point, exposes PyO3 module
|
|
252
|
+
2. **[src/server.rs](src/server.rs)** - Actix Web server with multi-worker tokio runtime
|
|
253
|
+
3. **[src/router.rs](src/router.rs)** - matchit-based routing
|
|
254
|
+
4. **[src/middleware/](src/middleware/)** - Middleware pipeline
|
|
255
|
+
- `auth.rs` - JWT/API Key authentication (zero GIL overhead)
|
|
256
|
+
- `cors.rs` - CORS handling
|
|
257
|
+
- `rate_limit.rs` - Token bucket rate limiting
|
|
258
|
+
5. **[src/permissions.rs](src/permissions.rs)** - Guard evaluation
|
|
259
|
+
6. **[python/django_bolt/api.py](python/django_bolt/api.py)** - Python decorator-based API
|
|
260
|
+
7. **[python/django_bolt/auth/](python/django_bolt/auth/)** - Authentication system
|
|
261
|
+
- `backends.py` - Auth backend classes (compile to Rust metadata)
|
|
262
|
+
- `guards.py` - Permission guard classes
|
|
263
|
+
- `jwt_utils.py` - JWT utilities for Django User integration
|
|
264
|
+
- `middleware.py` - Middleware decorators
|
|
265
|
+
- `token.py` - Token handling
|
|
266
|
+
- `revocation.py` - Token revocation stores
|
|
267
|
+
|
|
268
|
+
### Request Flow
|
|
269
|
+
|
|
270
|
+
```
|
|
271
|
+
HTTP Request → Actix Web (Rust)
|
|
272
|
+
↓
|
|
273
|
+
Route Matching (matchit)
|
|
274
|
+
↓
|
|
275
|
+
Middleware Pipeline (Rust - no GIL)
|
|
276
|
+
- CORS
|
|
277
|
+
- Rate Limiting
|
|
278
|
+
↓
|
|
279
|
+
Authentication (Rust - no GIL for most part may require in future)
|
|
280
|
+
- JWT validation
|
|
281
|
+
- API Key validation
|
|
282
|
+
↓
|
|
283
|
+
Guards/Permissions (Rust - no GIL)
|
|
284
|
+
- IsAuthenticated
|
|
285
|
+
- IsAdminUser
|
|
286
|
+
- HasPermission
|
|
287
|
+
↓
|
|
288
|
+
Python Handler (PyO3 bridge)
|
|
289
|
+
↓
|
|
290
|
+
Parameter Extraction & Validation (msgspec)
|
|
291
|
+
↓
|
|
292
|
+
Handler Execution (async Python)
|
|
293
|
+
- Django ORM access
|
|
294
|
+
- Business logic
|
|
295
|
+
↓
|
|
296
|
+
Response Serialization (msgspec)
|
|
297
|
+
↓
|
|
298
|
+
HTTP Response
|
|
299
|
+
```
|
|
300
|
+
|
|
301
|
+
---
|
|
302
|
+
|
|
303
|
+
## 📖 Usage Examples
|
|
304
|
+
|
|
305
|
+
### Basic Routes
|
|
306
|
+
|
|
307
|
+
```python
|
|
308
|
+
from django_bolt import BoltAPI
|
|
309
|
+
import msgspec
|
|
310
|
+
from typing import Optional
|
|
311
|
+
|
|
312
|
+
api = BoltAPI()
|
|
313
|
+
|
|
314
|
+
# Simple GET
|
|
315
|
+
@api.get("/hello")
|
|
316
|
+
async def hello():
|
|
317
|
+
return {"message": "Hello, World!"}
|
|
318
|
+
|
|
319
|
+
# Path parameters
|
|
320
|
+
@api.get("/users/{user_id}")
|
|
321
|
+
async def get_user(user_id: int):
|
|
322
|
+
return {"user_id": user_id}
|
|
323
|
+
|
|
324
|
+
# Query parameters
|
|
325
|
+
@api.get("/search")
|
|
326
|
+
async def search(q: str, limit: int = 10):
|
|
327
|
+
return {"query": q, "limit": limit}
|
|
328
|
+
|
|
329
|
+
# Request body with validation
|
|
330
|
+
class CreateUserRequest(msgspec.Struct):
|
|
331
|
+
username: str
|
|
332
|
+
email: str
|
|
333
|
+
age: int
|
|
334
|
+
|
|
335
|
+
@api.post("/users", response_model=CreateUserRequest)
|
|
336
|
+
async def create_user(user: CreateUserRequest):
|
|
337
|
+
# Validated automatically
|
|
338
|
+
return user
|
|
339
|
+
```
|
|
340
|
+
|
|
341
|
+
### Authentication & Guards
|
|
342
|
+
|
|
343
|
+
```python
|
|
344
|
+
from django_bolt import BoltAPI
|
|
345
|
+
from django_bolt.auth import (
|
|
346
|
+
JWTAuthentication,
|
|
347
|
+
IsAuthenticated,
|
|
348
|
+
IsAdminUser,
|
|
349
|
+
HasPermission,
|
|
350
|
+
)
|
|
351
|
+
|
|
352
|
+
api = BoltAPI()
|
|
353
|
+
|
|
354
|
+
# Require JWT authentication
|
|
355
|
+
@api.get(
|
|
356
|
+
"/protected",
|
|
357
|
+
auth=[JWTAuthentication()],
|
|
358
|
+
guards=[IsAuthenticated()]
|
|
359
|
+
)
|
|
360
|
+
async def protected_route(request):
|
|
361
|
+
auth_context = request.get("auth", {})
|
|
362
|
+
user_id = auth_context.get("user_id")
|
|
363
|
+
return {"message": f"Hello, user {user_id}"}
|
|
364
|
+
|
|
365
|
+
# Require admin access
|
|
366
|
+
@api.get(
|
|
367
|
+
"/admin",
|
|
368
|
+
auth=[JWTAuthentication()],
|
|
369
|
+
guards=[IsAdminUser()]
|
|
370
|
+
)
|
|
371
|
+
async def admin_only(request):
|
|
372
|
+
return {"message": "Admin access"}
|
|
373
|
+
|
|
374
|
+
# Permission-based access
|
|
375
|
+
@api.post(
|
|
376
|
+
"/articles",
|
|
377
|
+
auth=[JWTAuthentication()],
|
|
378
|
+
guards=[HasPermission("articles.create")]
|
|
379
|
+
)
|
|
380
|
+
async def create_article(request):
|
|
381
|
+
return {"message": "Article created"}
|
|
382
|
+
|
|
383
|
+
# Create JWT token for Django user
|
|
384
|
+
from django_bolt.auth import create_jwt_for_user
|
|
385
|
+
from django.contrib.auth.models import User
|
|
386
|
+
|
|
387
|
+
@api.post("/login")
|
|
388
|
+
async def login(username: str, password: str):
|
|
389
|
+
user = await User.objects.aget(username=username)
|
|
390
|
+
# Verify password...
|
|
391
|
+
token = create_jwt_for_user(user, exp_hours=24)
|
|
392
|
+
return {"access_token": token, "token_type": "bearer"}
|
|
393
|
+
```
|
|
394
|
+
|
|
395
|
+
### Middleware
|
|
396
|
+
|
|
397
|
+
```python
|
|
398
|
+
from django_bolt import BoltAPI
|
|
399
|
+
from django_bolt.auth import cors, rate_limit, skip_middleware
|
|
400
|
+
|
|
401
|
+
# Global middleware
|
|
402
|
+
api = BoltAPI(
|
|
403
|
+
middleware_config={
|
|
404
|
+
"cors": {
|
|
405
|
+
"origins": ["http://localhost:3000"],
|
|
406
|
+
"methods": ["GET", "POST", "PUT", "DELETE"],
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
)
|
|
410
|
+
|
|
411
|
+
# Per-route rate limiting
|
|
412
|
+
@api.get("/limited")
|
|
413
|
+
@rate_limit(rps=10, burst=20)
|
|
414
|
+
async def limited_endpoint():
|
|
415
|
+
return {"message": "Rate limited to 10 req/s"}
|
|
416
|
+
|
|
417
|
+
# Custom CORS for specific route
|
|
418
|
+
@api.get("/public")
|
|
419
|
+
@cors(origins=["*"])
|
|
420
|
+
async def public_endpoint():
|
|
421
|
+
return {"message": "Public endpoint with CORS"}
|
|
422
|
+
|
|
423
|
+
# Skip global middleware
|
|
424
|
+
@api.get("/no-cors")
|
|
425
|
+
@skip_middleware("cors")
|
|
426
|
+
async def no_cors():
|
|
427
|
+
return {"message": "CORS disabled for this route"}
|
|
428
|
+
```
|
|
429
|
+
|
|
430
|
+
### Django ORM Integration
|
|
431
|
+
|
|
432
|
+
```python
|
|
433
|
+
from django_bolt import BoltAPI
|
|
434
|
+
from django.contrib.auth.models import User
|
|
435
|
+
from myapp.models import Article
|
|
436
|
+
|
|
437
|
+
api = BoltAPI()
|
|
438
|
+
|
|
439
|
+
@api.get("/users/{user_id}")
|
|
440
|
+
async def get_user(user_id: int):
|
|
441
|
+
# Use Django's async ORM methods
|
|
442
|
+
user = await User.objects.aget(id=user_id)
|
|
443
|
+
return {
|
|
444
|
+
"id": user.id,
|
|
445
|
+
"username": user.username,
|
|
446
|
+
"email": user.email,
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
@api.get("/articles")
|
|
450
|
+
async def list_articles(limit: int = 10):
|
|
451
|
+
# Async query with select_related
|
|
452
|
+
articles = await Article.objects.select_related("author").all()[:limit]
|
|
453
|
+
return [
|
|
454
|
+
{
|
|
455
|
+
"id": a.id,
|
|
456
|
+
"title": a.title,
|
|
457
|
+
"author": a.author.username,
|
|
458
|
+
}
|
|
459
|
+
async for a in articles
|
|
460
|
+
]
|
|
461
|
+
```
|
|
462
|
+
|
|
463
|
+
### Response Types
|
|
464
|
+
|
|
465
|
+
```python
|
|
466
|
+
from django_bolt import BoltAPI
|
|
467
|
+
from django_bolt.responses import PlainText, HTML, Redirect, FileResponse
|
|
468
|
+
|
|
469
|
+
api = BoltAPI()
|
|
470
|
+
|
|
471
|
+
@api.get("/text")
|
|
472
|
+
async def text_response():
|
|
473
|
+
return PlainText("Hello, World!")
|
|
474
|
+
|
|
475
|
+
@api.get("/html")
|
|
476
|
+
async def html_response():
|
|
477
|
+
return HTML("<h1>Hello</h1>")
|
|
478
|
+
|
|
479
|
+
@api.get("/redirect")
|
|
480
|
+
async def redirect_response():
|
|
481
|
+
return Redirect("/new-location")
|
|
482
|
+
|
|
483
|
+
@api.get("/download")
|
|
484
|
+
async def download_file():
|
|
485
|
+
# Streams file from Rust (zero-copy)
|
|
486
|
+
return FileResponse("/path/to/file.pdf", filename="document.pdf")
|
|
487
|
+
```
|
|
488
|
+
|
|
489
|
+
### Streaming Responses
|
|
490
|
+
|
|
491
|
+
```python
|
|
492
|
+
from django_bolt import BoltAPI
|
|
493
|
+
from django_bolt.responses import StreamingResponse
|
|
494
|
+
import asyncio
|
|
495
|
+
|
|
496
|
+
api = BoltAPI()
|
|
497
|
+
|
|
498
|
+
@api.get("/stream")
|
|
499
|
+
async def stream_data():
|
|
500
|
+
async def generate():
|
|
501
|
+
for i in range(100):
|
|
502
|
+
yield f"data: {i}\n\n"
|
|
503
|
+
await asyncio.sleep(0.1)
|
|
504
|
+
|
|
505
|
+
return StreamingResponse(
|
|
506
|
+
generate(),
|
|
507
|
+
media_type="text/event-stream"
|
|
508
|
+
)
|
|
509
|
+
```
|
|
510
|
+
|
|
511
|
+
---
|
|
512
|
+
|
|
513
|
+
## 🔧 Development
|
|
514
|
+
|
|
515
|
+
### Setup
|
|
516
|
+
|
|
517
|
+
```bash
|
|
518
|
+
# Clone repository
|
|
519
|
+
git clone https://github.com/yourusername/django-bolt.git
|
|
520
|
+
cd django-bolt
|
|
521
|
+
|
|
522
|
+
# Install dependencies
|
|
523
|
+
pip install -r requirements-dev.txt
|
|
524
|
+
|
|
525
|
+
# Build Rust extension
|
|
526
|
+
make build # or: maturin develop --release
|
|
527
|
+
|
|
528
|
+
# Run tests
|
|
529
|
+
make test-py
|
|
530
|
+
```
|
|
531
|
+
|
|
532
|
+
### Commands
|
|
533
|
+
|
|
534
|
+
```bash
|
|
535
|
+
# Build
|
|
536
|
+
make build # Build Rust extension
|
|
537
|
+
make rebuild # Clean and rebuild
|
|
538
|
+
|
|
539
|
+
# Testing
|
|
540
|
+
make test-py # Run Python tests
|
|
541
|
+
make smoke # Quick smoke tests
|
|
542
|
+
make orm-smoke # ORM-specific tests
|
|
543
|
+
|
|
544
|
+
# Benchmarking
|
|
545
|
+
make bench # Run benchmarks
|
|
546
|
+
make save-bench # Run and save results
|
|
547
|
+
make bench C=100 N=50000 # Custom benchmark
|
|
548
|
+
|
|
549
|
+
# Server
|
|
550
|
+
make run-bg HOST=127.0.0.1 PORT=8000 P=2 WORKERS=2
|
|
551
|
+
```
|
|
552
|
+
|
|
553
|
+
---
|
|
554
|
+
|
|
555
|
+
## 📁 Project Structure
|
|
556
|
+
|
|
557
|
+
```
|
|
558
|
+
django-bolt/
|
|
559
|
+
├── src/ # Rust server code
|
|
560
|
+
│ ├── lib.rs # PyO3 module entry point
|
|
561
|
+
│ ├── server.rs # Actix Web server
|
|
562
|
+
│ ├── router.rs # matchit routing
|
|
563
|
+
│ ├── middleware/
|
|
564
|
+
│ │ ├── mod.rs
|
|
565
|
+
│ │ ├── auth.rs # JWT/API Key auth (no GIL)
|
|
566
|
+
│ │ ├── cors.rs # CORS handling
|
|
567
|
+
│ │ └── rate_limit.rs # Token bucket rate limiting
|
|
568
|
+
│ ├── permissions.rs # Guard evaluation
|
|
569
|
+
│ └── streaming.rs # Streaming response handling
|
|
570
|
+
├── python/django_bolt/ # Python framework
|
|
571
|
+
│ ├── api.py # BoltAPI class, decorators
|
|
572
|
+
│ ├── responses.py # Response types
|
|
573
|
+
│ ├── exceptions.py # HTTP exceptions
|
|
574
|
+
│ ├── params.py # Parameter markers
|
|
575
|
+
│ ├── auth/ # Authentication system
|
|
576
|
+
│ │ ├── __init__.py
|
|
577
|
+
│ │ ├── backends.py # Auth backends
|
|
578
|
+
│ │ ├── guards.py # Permission guards
|
|
579
|
+
│ │ ├── middleware.py # Middleware decorators
|
|
580
|
+
│ │ ├── jwt_utils.py # JWT utilities
|
|
581
|
+
│ │ ├── token.py # Token handling
|
|
582
|
+
│ │ └── revocation.py # Token revocation
|
|
583
|
+
│ ├── management/commands/
|
|
584
|
+
│ │ └── runbolt.py # Django management command
|
|
585
|
+
│ ├── cli.py # django-bolt CLI
|
|
586
|
+
│ ├── tests/ # Test suite
|
|
587
|
+
│ │ ├── test_auth_secret_key.py
|
|
588
|
+
│ │ ├── test_guards_auth.py
|
|
589
|
+
│ │ ├── test_guards_integration.py
|
|
590
|
+
│ │ ├── test_jwt_auth.py
|
|
591
|
+
│ │ ├── test_jwt_token.py
|
|
592
|
+
│ │ ├── test_middleware.py
|
|
593
|
+
│ │ └── test_syntax.py
|
|
594
|
+
│ └── bootstrap.py # Django setup helper
|
|
595
|
+
└── python/examples/testproject/ # Example Django project
|
|
596
|
+
├── manage.py
|
|
597
|
+
├── testproject/
|
|
598
|
+
│ ├── settings.py
|
|
599
|
+
│ └── api.py # Example routes
|
|
600
|
+
└── users/ # Example app
|
|
601
|
+
├── models.py
|
|
602
|
+
└── api.py
|
|
603
|
+
```
|
|
604
|
+
|
|
605
|
+
---
|
|
606
|
+
|
|
607
|
+
## 🤝 Contributing
|
|
608
|
+
|
|
609
|
+
Contributions welcome! Here's how:
|
|
610
|
+
|
|
611
|
+
1. Fork the repository
|
|
612
|
+
2. Create a feature branch (`git checkout -b feature/amazing-feature`)
|
|
613
|
+
3. Make your changes
|
|
614
|
+
4. Run tests (`make test-py`)
|
|
615
|
+
5. Commit (`git commit -m 'Add amazing feature'`)
|
|
616
|
+
6. Push (`git push origin feature/amazing-feature`)
|
|
617
|
+
7. Open a Pull Request
|
|
618
|
+
|
|
619
|
+
### Areas That Need Help
|
|
620
|
+
|
|
621
|
+
- Authentication
|
|
622
|
+
- OpenAPI/Swagger generation
|
|
623
|
+
- More comprehensive tests and test utilities
|
|
624
|
+
- Documentation improvements
|
|
625
|
+
|
|
626
|
+
---
|
|
627
|
+
|
|
628
|
+
**Built with ⚡ by developers who need speed without sacrificing Python's elegance**
|
|
629
|
+
|