p3n-q: add Plugins, Testing Client, UploadFile, Database API reference pages

swadhinbiswas committed 3 months ago
2e97a02
1 parent 6138bab
commit 2e97a02
4 files changed
+325 -0
▼docs_site/src/content/docs/api-reference/database.md
+95-0
1
+---
2
+title: Database API
3
+description: Reference for the Rust-native database connection pool and query interface.
4
+---
5
+
6
+## `app.set_database()`
7
+
8
+Configure the database connection pool:
9
+
10
+```python
11
+app.set_database(
12
+ url="postgres://user:pass@localhost:5432/mydb",
13
+ init_sql="CREATE TABLE IF NOT EXISTS ...",
14
+ max_connections=10,
15
+ request_acquire_timeout=3.0,
16
+ wal=False,
17
+ pragmas=None,
18
+)
19
+```
20
+
21
+### Parameters
22
+
23
+| Parameter | Type | Default | Description |
24
+|---|---|---|---|
25
+| `url` | `str` | required | Database connection URL |
26
+| `init_sql` | `str` | `None` | SQL to run on startup (for schema creation) |
27
+| `max_connections` | `int` | `10` | Maximum pool connections |
28
+| `request_acquire_timeout` | `float` | `3.0` | Seconds before pool saturation returns 503 |
29
+| `wal` | `bool` | `False` | Enable SQLite WAL mode |
30
+| `pragmas` | `list[str]` | `None` | Additional SQLite pragmas |
31
+
32
+## `app.db` Object
33
+
34
+### Methods
35
+
36
+| Method | Returns | Description |
37
+|---|---|---|
38
+| `app.db.query(sql, params)` | `list[dict]` | Execute SELECT and return rows |
39
+| `app.db.execute(sql, params)` | `int` | Execute INSERT/UPDATE/DELETE, return affected rows |
40
+
41
+#### `query()`
42
+
43
+```python
44
+rows = app.db.query(
45
+ "SELECT id, name, price FROM products WHERE price > $1 ORDER BY id",
46
+ [100.0],
47
+)
48
+# Returns: [{"id": 1, "name": "Widget", "price": 150.0}, ...]
49
+```
50
+
51
+| Parameter | Type | Default | Description |
52
+|---|---|---|---|
53
+| `sql` | `str` | required | SQL query with `$1`, `$2`, ... placeholders |
54
+| `params` | `list` | `[]` | Query parameters |
55
+
56
+#### `execute()`
57
+
58
+```python
59
+affected = app.db.execute(
60
+ "INSERT INTO products (name, price) VALUES ($1, $2)",
61
+ ["Widget", 150.0],
62
+)
63
+# Returns: 1
64
+```
65
+
66
+| Parameter | Type | Default | Description |
67
+|---|---|---|---|
68
+| `sql` | `str` | required | SQL with `$1`, `$2`, ... placeholders |
69
+| `params` | `list` | `[]` | Query parameters |
70
+
71
+## Connection URLs
72
+
73
+| Database | URL Format | Example |
74
+|---|---|---|
75
+| PostgreSQL | `postgres://user:pass@host:port/db` | `postgres://postgres@localhost/mydb` |
76
+| MySQL | `mysql://user:pass@host:port/db` | `mysql://root@localhost/mydb` |
77
+| SQLite | `sqlite:///path/to/db.db` | `sqlite:///app.db` |
78
+| SQLite (memory) | `sqlite://:memory:` | `sqlite://:memory:` |
79
+
80
+## Pool Saturation
81
+
82
+When all connections are in use, new requests wait up to `request_acquire_timeout` seconds, then receive **503 Service Unavailable** with a `Retry-After: 1` header.
83
+
84
+## SQLite Defaults
85
+
86
+For SQLite connections, JustAPI automatically enables:
87
+- `PRAGMA busy_timeout=5000` — Wait up to 5 seconds for busy connections
88
+- `PRAGMA journal_mode=WAL` — Write-Ahead Logging for concurrent access
89
+- `PRAGMA synchronous=NORMAL` — Balanced durability/performance
90
+
91
+## See Also
92
+
93
+- [Database Integration Tutorial](/tutorials/database-integration/) — Usage guide
94
+- [JustAPIApp](/api-reference/justapiapp/) — `set_database()` method
95
+- [Performance Tuning](/advanced/performance-tuning/) — Database optimization
0
96
▼docs_site/src/content/docs/api-reference/plugins.md
+105-0
1
+---
2
+title: Plugin System API
3
+description: Reference for extending JustAPI with Python and Rust plugins.
4
+---
5
+
6
+JustAPI's plugin system supports Python plugins (for flexibility) and Rust plugins (for maximum performance).
7
+
8
+## Python Plugin Interface
9
+
10
+A Python plugin is any class implementing one or more lifecycle hooks:
11
+
12
+```python
13
+class MyPlugin:
14
+ def build(self, app):
15
+ """Called when plugin is registered with app.use()."""
16
+ pass
17
+
18
+ async def on_startup(self):
19
+ """Called before server starts accepting requests."""
20
+ pass
21
+
22
+ async def on_shutdown(self):
23
+ """Called during server shutdown."""
24
+ pass
25
+```
26
+
27
+### Hook Details
28
+
29
+| Method | Timing | Purpose |
30
+|---|---|---|
31
+| `build(self, app)` | On `app.use()` | Add routes, middleware, modify config |
32
+| `on_startup(self)` | Before server starts | Connect to services, warm caches |
33
+| `on_shutdown(self)` | During graceful shutdown | Close connections, save state |
34
+
35
+### Registration
36
+
37
+```python
38
+from justapi import JustAPIApp
39
+
40
+class MyPlugin:
41
+ def build(self, app: JustAPIApp):
42
+ print("Plugin registered!")
43
+
44
+ async def on_startup(self):
45
+ print("Server starting...")
46
+
47
+ async def on_shutdown(self):
48
+ print("Server stopping...")
49
+
50
+app = JustAPIApp()
51
+app.use(MyPlugin())
52
+```
53
+
54
+## Rust Plugin Interface
55
+
56
+For performance-critical extensions, Rust plugins implement the `Plugin` trait:
57
+
58
+```rust
59
+use justapi_core::plugin::Plugin;
60
+use async_trait::async_trait;
61
+
62
+pub struct MyRustPlugin;
63
+
64
+#[async_trait]
65
+impl Plugin for MyRustPlugin {
66
+ fn name(&self) -> &'static str {
67
+ "MyRustPlugin"
68
+ }
69
+
70
+ async fn on_startup(&self) -> anyhow::Result<()> {
71
+ println!("Rust plugin started");
72
+ Ok(())
73
+ }
74
+
75
+ async fn on_shutdown(&self) -> anyhow::Result<()> {
76
+ println!("Rust plugin stopped");
77
+ Ok(())
78
+ }
79
+}
80
+```
81
+
82
+### Registration
83
+
84
+```rust
85
+use justapi_core::plugin::PluginRegistration;
86
+use std::sync::Arc;
87
+
88
+inventory::submit! {
89
+ PluginRegistration::new(|| Arc::new(MyRustPlugin))
90
+}
91
+```
92
+
93
+## Plugin Marketplace
94
+
95
+To publish a JustAPI Python plugin to the community:
96
+
97
+1. Publish to PyPI with the `justapi-plugin` keyword
98
+2. Users install via `pip install justapi-plugin-yourname`
99
+3. Usage: `from justapi_plugin_yourname import YourPlugin; app.use(YourPlugin())`
100
+
101
+## See Also
102
+
103
+- [Plugins Guide](/docs/plugins.md) — Detailed plugin development guide
104
+- [JustAPIApp](/api-reference/justapiapp/) — `app.use()` method
105
+- [Rust Core Deep Dive](/advanced/rust-core-deep-dive/) — Plugin trait internals
0
106
▼docs_site/src/content/docs/api-reference/testing-client.md
+54-0
1
+---
2
+title: Testing Client API
3
+description: Reference for the in-process HTTP test client.
4
+---
5
+
6
+## `JustAPITestClient`
7
+
8
+The test client sends HTTP requests to your application without starting a real server, using `tokio` duplex streams.
9
+
10
+```python
11
+from justapi import JustAPITestClient
12
+
13
+client = JustAPITestClient(app)
14
+```
15
+
16
+### Methods
17
+
18
+```python
19
+response = client.get("/items/42")
20
+response = client.post("/items/", body={"name": "Item"})
21
+response = client.put("/items/42", body={"name": "Updated"})
22
+response = client.patch("/items/42", body={"name": "Patched"})
23
+response = client.delete("/items/42")
24
+```
25
+
26
+### Response Object
27
+
28
+| Attribute | Type | Description |
29
+|---|---|---|
30
+| `status` | `int` | HTTP status code |
31
+| `body` | `bytes` | Raw response body |
32
+| `json()` | `dict` | Parsed JSON body |
33
+
34
+### Example Test
35
+
36
+```python
37
+from justapi import JustAPIApp, JustAPITestClient
38
+
39
+app = JustAPIApp()
40
+
41
+@app.get("/ping")
42
+def ping(request):
43
+ return {"status": "ok"}
44
+
45
+client = JustAPITestClient(app)
46
+response = client.get("/ping")
47
+assert response.status == 200
48
+assert response.json() == {"status": "ok"}
49
+```
50
+
51
+## See Also
52
+
53
+- [Testing Guide](/contributing/testing-guide/) — Writing tests for JustAPI
54
+- [JustAPIApp](/api-reference/justapiapp/) — App configuration
0
55
▼docs_site/src/content/docs/api-reference/uploadfile.md
+71-0
1
+---
2
+title: UploadFile API
3
+description: Reference for uploaded file representation.
4
+---
5
+
6
+## `UploadFile` Object
7
+
8
+Represents a file uploaded via `multipart/form-data`. Files are streamed to temporary files by the Rust `multer` parser.
9
+
10
+```python
11
+from justapi import UploadFile, File
12
+```
13
+
14
+### Properties
15
+
16
+| Attribute | Type | Description |
17
+|---|---|---|
18
+| `filename` | `str` | Original filename from the client |
19
+| `content_type` | `str` | MIME type (e.g., `image/png`) |
20
+| `file` | `str` | Path to the temporary file on disk |
21
+| `size` | `int` | File size in bytes |
22
+
23
+### Methods
24
+
25
+| Method | Returns | Description |
26
+|---|---|---|
27
+| `.read()` | `bytes` | Read file contents into memory |
28
+| `.write(data)` | `int` | Write bytes to the temp file |
29
+| `.seek(pos)` | `None` | Seek to position in the temp file |
30
+| `.close()` | `None` | Close and clean up the temp file |
31
+
32
+### Usage
33
+
34
+```python
35
+@app.post("/upload")
36
+async def upload(request, file: UploadFile = File(...)):
37
+ content = await file.read()
38
+ return {
39
+ "name": file.filename,
40
+ "type": file.content_type,
41
+ "size": file.size,
42
+ "content": content.decode(),
43
+ }
44
+```
45
+
46
+## `File()`
47
+
48
+Declare a file parameter:
49
+
50
+```python
51
+File(
52
+ default=..., # Use ... for required
53
+ description=None, # OpenAPI description
54
+)
55
+```
56
+
57
+## `Form()`
58
+
59
+Declare a form field parameter:
60
+
61
+```python
62
+Form(
63
+ default=...,
64
+ description=None,
65
+)
66
+```
67
+
68
+## See Also
69
+
70
+- [File Uploads Tutorial](/tutorials/file-uploads/) — Usage guide
71
+- [Dependency Injection API](/api-reference/dependency-injection/) — File and Form extractors
0
72