swadhinbiswas

[email protected]
2026-07-25 17:52:05 +0600 committed NaN years ago
54132cc
commit 54132cc
23 files changed
+1529 -0
▼docs_site/src/content/docs/advanced/additional-responses.md
+71-0
1
+---
2
+title: Additional Responses in OpenAPI
3
+description: Document additional error responses and custom status codes in OpenAPI for JustAPI.
4
+keywords: [JustAPI, OpenAPI, additional responses, error responses, documentation]
5
+---
6
+
7
+## Declaring Error Responses
8
+
9
+Document additional responses that your handler might return:
10
+
11
+```python
12
+from justapi import JustAPIApp, HTTPException
13
+from pydantic import BaseModel
14
+
15
+class ErrorResponse(BaseModel):
16
+ detail: str
17
+
18
+app = JustAPIApp()
19
+
20
+@app.get(
21
+ "/items/{item_id}",
22
+ responses={
23
+ 404: {"model": ErrorResponse, "description": "Item not found"},
24
+ 500: {"description": "Internal server error"},
25
+ },
26
+)
27
+def get_item(item_id: int):
28
+ if item_id == 0:
29
+ raise HTTPException(status_code=404, detail="Item not found")
30
+ return {"item_id": item_id}
31
+```
32
+
33
+## Multiple Response Models
34
+
35
+```python
36
+@app.get(
37
+ "/users/{user_id}",
38
+ response_model=UserOut,
39
+ responses={
40
+ 200: {"description": "User found"},
41
+ 404: {"model": ErrorResponse, "description": "User not found"},
42
+ 403: {"description": "Access denied"},
43
+ },
44
+)
45
+def get_user(user_id: int):
46
+ return {"user_id": user_id}
47
+```
48
+
49
+## Per-Media-Type Responses
50
+
51
+```python
52
+@app.get(
53
+ "/data",
54
+ responses={
55
+ 200: {
56
+ "content": {
57
+ "application/json": {"schema": {"type": "object"}},
58
+ "text/plain": {"schema": {"type": "string"}},
59
+ }
60
+ }
61
+ },
62
+)
63
+def get_data():
64
+ return {"data": "value"}
65
+```
66
+
67
+## See Also
68
+
69
+- [OpenAPI Callbacks & Webhooks](/advanced/openapi-callbacks/) — advanced OpenAPI features
70
+- [Metadata & Docs URLs](/tutorials/metadata/) — app-level metadata
71
+- [API Reference](/api-reference/) — full reference
0
72
▼docs_site/src/content/docs/advanced/advanced-dependencies.md
+67-0
1
+---
2
+title: Advanced Dependencies
3
+description: Parameterized dependencies, async generator dependencies, and dependency overrides in JustAPI.
4
+keywords: [JustAPI, advanced dependencies, parameterized, overrides, async generator]
5
+---
6
+
7
+## Parameterized Dependencies
8
+
9
+Create dependencies that accept arguments:
10
+
11
+```python
12
+from justapi import JustAPIApp, Depends
13
+
14
+def get_query_filter(field: str, value: str):
15
+ def dependency():
16
+ return {field: value}
17
+ return dependency
18
+
19
+app = JustAPIApp()
20
+
21
+@app.get("/items/")
22
+def list_items(fresh: str = Depends(get_query_filter("status", "active"))):
23
+ return {"filter": fresh}
24
+```
25
+
26
+## Dependency Overrides
27
+
28
+Override dependencies for testing:
29
+
30
+```python
31
+def get_db():
32
+ return ProductionDB()
33
+
34
+app = JustAPIApp(dependencies=[Depends(get_db)])
35
+
36
+# In tests
37
+def override_get_db():
38
+ return TestDB()
39
+
40
+app.dependency_overrides[get_db] = override_get_db
41
+
42
+def test_handler():
43
+ response = client.get("/items/")
44
+ assert response.status == 200
45
+```
46
+
47
+## Async Generator Dependencies
48
+
49
+```python
50
+async def get_async_db():
51
+ db = await create_async_connection()
52
+ try:
53
+ yield db
54
+ finally:
55
+ await db.close()
56
+
57
+@app.get("/items/")
58
+async def list_items(db = Depends(get_async_db)):
59
+ items = await db.fetch_all("SELECT * FROM items")
60
+ return {"items": items}
61
+```
62
+
63
+## See Also
64
+
65
+- [Dependencies with yield](/tutorials/dependencies/dependencies-with-yield/) — cleanup patterns
66
+- [Testing with Overrides](/advanced/async-tests/) — testing dependencies
67
+- [Classes as Dependencies](/tutorials/dependencies/classes-as-dependencies/) — class-based deps
0
68
▼docs_site/src/content/docs/advanced/advanced-middleware.md
+63-0
1
+---
2
+title: Advanced Middleware
3
+description: Add ASGI middleware, HTTPS redirect, trusted hosts, and GZip compression in JustAPI.
4
+keywords: [JustAPI, middleware, ASGI, HTTPS redirect, trusted host, GZip]
5
+---
6
+
7
+## Adding ASGI Middleware
8
+
9
+JustAPI supports any ASGI middleware:
10
+
11
+```python
12
+from justapi import JustAPIApp
13
+from starlette.middleware.httpsredirect import HTTPSRedirectMiddleware
14
+from starlette.middleware.trustedhost import TrustedHostMiddleware
15
+
16
+app = JustAPIApp()
17
+
18
+app.add_middleware(HTTPSRedirectMiddleware)
19
+```
20
+
21
+## Trusted Host Middleware
22
+
23
+Guard against HTTP host header attacks:
24
+
25
+```python
26
+app.add_middleware(
27
+ TrustedHostMiddleware,
28
+ allowed_hosts=["example.com", "*.example.com"],
29
+)
30
+```
31
+
32
+## GZip Compression
33
+
34
+```python
35
+from starlette.middleware.gzip import GZipMiddleware
36
+
37
+app.add_middleware(GZipMiddleware, minimum_size=500, compresslevel=9)
38
+```
39
+
40
+## Custom ASGI Middleware
41
+
42
+Write your own middleware class:
43
+
44
+```python
45
+import time
46
+from starlette.middleware.base import BaseHTTPMiddleware
47
+
48
+class TimingMiddleware(BaseHTTPMiddleware):
49
+ async def dispatch(self, request, call_next):
50
+ start = time.time()
51
+ response = await call_next(request)
52
+ duration = time.time() - start
53
+ response.headers["X-Process-Time"] = str(round(duration, 4))
54
+ return response
55
+
56
+app.add_middleware(TimingMiddleware)
57
+```
58
+
59
+## See Also
60
+
61
+- [Middleware](/tutorials/middleware/) — basic middleware usage
62
+- [Behind a Proxy](/advanced/behind-a-proxy/) — reverse proxy configuration
63
+- [Sub Applications](/advanced/sub-applications/) — mounting sub-apps
0
64
▼docs_site/src/content/docs/advanced/advanced-security.md
+76-0
1
+---
2
+title: Advanced Security
3
+description: OAuth2 scopes, HTTP Basic Auth, and API key authentication in JustAPI.
4
+keywords: [JustAPI, OAuth2 scopes, HTTP Basic Auth, API keys, advanced security]
5
+---
6
+
7
+## OAuth2 Scopes
8
+
9
+Control access with fine-grained permissions:
10
+
11
+```python
12
+from justapi import JustAPIApp, Security
13
+from fastapi.security import OAuth2PasswordBearer
14
+
15
+oauth2_scheme = OAuth2PasswordBearer(
16
+ tokenUrl="token",
17
+ scopes={"read": "Read access", "write": "Write access", "admin": "Admin access"},
18
+)
19
+
20
+@app.get("/items/")
21
+def list_items(token: str = Security(oauth2_scheme, scopes=["read"])):
22
+ return []
23
+
24
+@app.post("/items/")
25
+def create_item(token: str = Security(oauth2_scheme, scopes=["write"])):
26
+ return {}
27
+
28
+@app.delete("/items/{item_id}")
29
+def delete_item(item_id: int, token: str = Security(oauth2_scheme, scopes=["admin"])):
30
+ return {"deleted": item_id}
31
+```
32
+
33
+## HTTP Basic Auth
34
+
35
+```python
36
+from fastapi import Depends, HTTPException, status
37
+from fastapi.security import HTTPBasic, HTTPBasicCredentials
38
+import secrets
39
+
40
+security = HTTPBasic()
41
+
42
+def verify_credentials(credentials: HTTPBasicCredentials = Depends(security)):
43
+ correct_username = secrets.compare_digest(credentials.username, "admin")
44
+ correct_password = secrets.compare_digest(credentials.password, "secret")
45
+ if not (correct_username and correct_password):
46
+ raise HTTPException(status_code=401, detail="Invalid credentials")
47
+ return credentials.username
48
+
49
+@app.get("/admin")
50
+def admin_panel(username: str = Depends(verify_credentials)):
51
+ return {"message": f"Welcome {username}"}
52
+```
53
+
54
+## API Key Authentication
55
+
56
+```python
57
+from fastapi import Security
58
+from fastapi.security import APIKeyHeader
59
+
60
+api_key_header = APIKeyHeader(name="X-API-Key")
61
+
62
+def verify_api_key(api_key: str = Security(api_key_header)):
63
+ if api_key != "my-secret-key":
64
+ raise HTTPException(status_code=403, detail="Invalid API key")
65
+ return api_key
66
+
67
+@app.get("/data")
68
+def get_data(key: str = Security(verify_api_key)):
69
+ return {"data": "sensitive"}
70
+```
71
+
72
+## See Also
73
+
74
+- [Security — First Steps](/tutorials/security/first-steps/) — basic security
75
+- [OAuth2 + JWT](/tutorials/security/oauth2-jwt/) — JWT implementation
76
+- [Secure Configuration](/security/secure-configuration/) — production security
0
77
▼docs_site/src/content/docs/advanced/async-tests.md
+63-0
1
+---
2
+title: Async Tests
3
+description: Write async test functions with httpx.AsyncClient for JustAPI applications.
4
+keywords: [JustAPI, async tests, httpx, AsyncClient, pytest-asyncio]
5
+---
6
+
7
+## Async Test Client
8
+
9
+Use `httpx.AsyncClient` for async testing:
10
+
11
+```python
12
+import pytest
13
+import httpx
14
+from justapi import JustAPIApp
15
+
16
+app = JustAPIApp()
17
+
18
+@app.get("/hello")
19
+async def hello():
20
+ return {"message": "Hello!"}
21
+
22
+@pytest.mark.anyio
23
+async def test_hello():
24
+ async with httpx.AsyncClient(transport=httpx.ASGITransport(app=app), base_url="http://test") as client:
25
+ response = await client.get("/hello")
26
+ assert response.status_code == 200
27
+ assert response.json() == {"message": "Hello!"}
28
+```
29
+
30
+## Testing with Dependencies
31
+
32
+```python
33
+def override_get_db():
34
+ return TestDB()
35
+
36
+app.dependency_overrides[get_db] = override_get_db
37
+
38
+@pytest.mark.anyio
39
+async def test_with_override():
40
+ async with httpx.AsyncClient(transport=httpx.ASGITransport(app=app), base_url="http://test") as client:
41
+ response = await client.get("/items/")
42
+ assert response.status_code == 200
43
+```
44
+
45
+## Setup and Teardown
46
+
47
+```python
48
+@pytest.fixture
49
+async def client():
50
+ async with httpx.AsyncClient(transport=httpx.ASGITransport(app=app), base_url="http://test") as c:
51
+ yield c
52
+
53
+@pytest.mark.anyio
54
+async def test_example(client):
55
+ response = await client.get("/hello")
56
+ assert response.status_code == 200
57
+```
58
+
59
+## See Also
60
+
61
+- [Testing](/tutorials/testing/) — sync testing with JustAPITestClient
62
+- [Testing with Overrides](/advanced/async-tests/) — dependency overrides
63
+- [Debugging](/tutorials/debugging/) — debugging techniques
0
64
▼docs_site/src/content/docs/advanced/behind-a-proxy.md
+50-0
1
+---
2
+title: Behind a Proxy
3
+description: Configure JustAPI to run behind a reverse proxy (Nginx, Traefik, HAProxy, Cloudflare).
4
+keywords: [JustAPI, reverse proxy, Nginx, Traefik, root_path, X-Forwarded]
5
+---
6
+
7
+## root_path
8
+
9
+When running behind a proxy, set `root_path` so JustAPI knows the external path:
10
+
11
+```python
12
+app = JustAPIApp(root_path="/api/v1")
13
+```
14
+
15
+## Nginx Configuration
16
+
17
+```nginx
18
+location /api/ {
19
+ proxy_pass http://localhost:8000/;
20
+ proxy_set_header Host $host;
21
+ proxy_set_header X-Real-IP $remote_addr;
22
+ proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
23
+ proxy_set_header X-Forwarded-Proto $scheme;
24
+}
25
+```
26
+
27
+## Cloudflare
28
+
29
+Cloudflare automatically adds the right headers. JustAPI detects them:
30
+
31
+```python
32
+app = JustAPIApp(root_path="/")
33
+```
34
+
35
+## Trusted Hosts with Proxy
36
+
37
+```python
38
+from starlette.middleware.trustedhost import TrustedHostMiddleware
39
+
40
+app.add_middleware(
41
+ TrustedHostMiddleware,
42
+ allowed_hosts=["example.com", "*.example.com"],
43
+)
44
+```
45
+
46
+## See Also
47
+
48
+- [Docker](/deployment/docker/) — containerized deployment
49
+- [Kubernetes / Helm](/deployment/kubernetes-helm/) — K8s deployment
50
+- [Production Checklist](/deployment/production-checklist/) — production setup
0
51
▼docs_site/src/content/docs/advanced/custom-response.md
+74-0
1
+---
2
+title: Custom Response Classes
3
+description: Use HTML, streaming, file, and other custom response types in JustAPI.
4
+keywords: [JustAPI, custom response, HTML, streaming, file response, redirect]
5
+---
6
+
7
+## HTML Response
8
+
9
+```python
10
+from starlette.responses import HTMLResponse
11
+from justapi import JustAPIApp
12
+
13
+app = JustAPIApp()
14
+
15
+@app.get("/html")
16
+def html_page():
17
+ return HTMLResponse(content="<h1>Hello</h1><p>This is HTML</p>")
18
+```
19
+
20
+## Streaming Response
21
+
22
+```python
23
+from starlette.responses import StreamingResponse
24
+import asyncio
25
+
26
+async def generate_tokens():
27
+ for i in range(10):
28
+ yield f"data: token_{i}\n\n"
29
+ await asyncio.sleep(0.1)
30
+
31
+@app.get("/stream")
32
+def stream():
33
+ return StreamingResponse(generate_tokens(), media_type="text/event-stream")
34
+```
35
+
36
+## File Response
37
+
38
+```python
39
+from starlette.responses import FileResponse
40
+
41
+@app.get("/download")
42
+def download():
43
+ return FileResponse("report.pdf", filename="report.pdf")
44
+```
45
+
46
+## Plain Text Response
47
+
48
+```python
49
+from starlette.responses import PlainTextResponse
50
+
51
+@app.get("/text")
52
+def text():
53
+ return PlainTextResponse("Hello, plain text!")
54
+```
55
+
56
+## Default Response Class
57
+
58
+Set a default response class for all routes:
59
+
60
+```python
61
+from starlette.responses import ORJSONResponse
62
+
63
+app = JustAPIApp(default_response_class=ORJSONResponse)
64
+```
65
+
66
+:::tip
67
+`ORJSONResponse` is faster than `JSONResponse` for large payloads. Install with `pip install orjson`.
68
+:::
69
+
70
+## See Also
71
+
72
+- [Return a Response Directly](/advanced/response-directly/) — basic response object usage
73
+- [Streaming Output](/advanced/streaming-output/) — JustAPI-native streaming
74
+- [Static Files](/tutorials/static-files/) — serving files
0
75
▼docs_site/src/content/docs/advanced/dataclasses.md
+47-0
1
+---
2
+title: Using Dataclasses
3
+description: Use Python dataclasses as request models and response models in JustAPI.
4
+keywords: [JustAPI, dataclasses, request model, Python dataclass]
5
+---
6
+
7
+## Dataclasses as Request Models
8
+
9
+JustAPI supports Python `dataclasses` as an alternative to Pydantic:
10
+
11
+```python
12
+from dataclasses import dataclass
13
+from typing import Optional
14
+from justapi import JustAPIApp
15
+
16
+@dataclass
17
+class Item:
18
+ name: str
19
+ price: float
20
+ description: Optional[str] = None
21
+
22
+app = JustAPIApp()
23
+
24
+@app.post("/items")
25
+def create_item(item: Item):
26
+ return {"name": item.name, "price": item.price}
27
+```
28
+
29
+## Dataclasses as Response Models
30
+
31
+```python
32
+@dataclass
33
+class ItemResponse:
34
+ id: int
35
+ name: str
36
+ price: float
37
+
38
+@app.get("/items/{item_id}", response_model=ItemResponse)
39
+def get_item(item_id: int):
40
+ return ItemResponse(id=item_id, name="Widget", price=9.99)
41
+```
42
+
43
+## See Also
44
+
45
+- [Request Body](/tutorials/request-body/) — Pydantic model usage
46
+- [Using the Request Directly](/advanced/using-request-directly/) — raw request access
47
+- [Response Model](/tutorials/response-model/) — filtering output
0
48
▼docs_site/src/content/docs/advanced/generate-clients.md
+64-0
1
+---
2
+title: Generating SDKs
3
+description: Generate client SDKs from your JustAPI OpenAPI schema for multiple languages.
4
+keywords: [JustAPI, SDK generation, OpenAPI, client generation, code generation]
5
+---
6
+
7
+## Automatic OpenAPI Schema
8
+
9
+JustAPI generates an OpenAPI 3.1 schema at `/openapi.json`:
10
+
11
+```bash
12
+curl http://localhost:8000/openapi.json
13
+```
14
+
15
+## Generate Python Client
16
+
17
+```bash
18
+pip install openapi-generator-cli
19
+
20
+openapi-generator-cli generate \
21
+ -i http://localhost:8000/openapi.json \
22
+ -g python \
23
+ -o ./clients/python
24
+```
25
+
26
+## Generate TypeScript Client
27
+
28
+```bash
29
+openapi-generator-cli generate \
30
+ -i http://localhost:8000/openapi.json \
31
+ -g typescript-axios \
32
+ -o ./clients/typescript
33
+```
34
+
35
+## Available Languages
36
+
37
+| Language | Generator |
38
+|----------|-----------|
39
+| Python | `python` |
40
+| TypeScript | `typescript-axios` |
41
+| Go | `go` |
42
+| Java | `java` |
43
+| Ruby | `ruby` |
44
+| C# | `csharp` |
45
+| Swift | `swift5` |
46
+
47
+## Custom ID Function
48
+
49
+Customize operation IDs for better SDK generation:
50
+
51
+```python
52
+from justapi import JustAPIApp
53
+
54
+def custom_id(operation):
55
+ return f"{operation.tags[0]}_{operation.name}" if operation.tags else operation.name
56
+
57
+app = JustAPIApp(generate_unique_id_function=custom_id)
58
+```
59
+
60
+## See Also
61
+
62
+- [OpenAPI Callbacks & Webhooks](/advanced/openapi-callbacks/) — outbound schemas
63
+- [Additional Responses in OpenAPI](/advanced/additional-responses/) — error docs
64
+- [Metadata & Docs URLs](/tutorials/metadata/) — app metadata
0
65
▼docs_site/src/content/docs/advanced/lifespan-events.md
+60-0
1
+---
2
+title: Lifespan Events
3
+description: Run startup and shutdown code in JustAPI using the lifespan context manager.
4
+keywords: [JustAPI, lifespan, startup, shutdown, events, lifecycle]
5
+---
6
+
7
+## Lifespan Context Manager
8
+
9
+Use `@asynccontextmanager` for startup/shutdown:
10
+
11
+```python
12
+from contextlib import asynccontextmanager
13
+from justapi import JustAPIApp
14
+
15
+@asynccontextmanager
16
+async def lifespan(app):
17
+ # Startup: run before the server starts
18
+ print("Starting up...")
19
+ db = await create_connection()
20
+ app.state.db = db
21
+ yield
22
+ # Shutdown: run after the server stops
23
+ print("Shutting down...")
24
+ await db.close()
25
+
26
+app = JustAPIApp(lifespan=lifespan)
27
+```
28
+
29
+## Accessing State
30
+
31
+```python
32
+@app.get("/health")
33
+def health(request):
34
+ db = request.app.state.db
35
+ return {"status": "ok" if db else "error"}
36
+```
37
+
38
+## Multiple Resources
39
+
40
+```python
41
+@asynccontextmanager
42
+async def lifespan(app):
43
+ # Start all resources
44
+ app.state.db = await create_db()
45
+ app.state.cache = await create_cache()
46
+ app.state.queue = await create_queue()
47
+ yield
48
+ # Stop all resources
49
+ await app.state.queue.close()
50
+ await app.state.cache.close()
51
+ await app.state.db.close()
52
+
53
+app = JustAPIApp(lifespan=lifespan)
54
+```
55
+
56
+## See Also
57
+
58
+- [Settings & Environment Variables](/advanced/settings/) — configuration
59
+- [Health Checks](/observability/health-checks/) — monitoring
60
+- [SQL Databases](/tutorials/database-integration/) — database lifecycle
0
61
▼docs_site/src/content/docs/advanced/openapi-callbacks.md
+57-0
1
+---
2
+title: OpenAPI Callbacks and Webhooks
3
+description: Define OpenAPI callbacks and webhooks for outbound request schemas in JustAPI.
4
+keywords: [JustAPI, OpenAPI, callbacks, webhooks, outbound requests]
5
+---
6
+
7
+## OpenAPI Callbacks
8
+
9
+Callbacks define the schema for outbound requests your API makes:
10
+
11
+```python
12
+from justapi import JustAPIApp
13
+from pydantic import BaseModel
14
+
15
+class Order(BaseModel):
16
+ id: int
17
+ status: str
18
+
19
+app = JustAPIApp()
20
+
21
+@app.post("/orders", callbacks={
22
+ "on_order_complete": {
23
+ "http://localhost:8000/webhook": {
24
+ "post": {
25
+ "requestBody": {
26
+ "content": {
27
+ "application/json": {
28
+ "schema": Order.model_jsonschema()
29
+ }
30
+ }
31
+ }
32
+ }
33
+ }
34
+ }
35
+})
36
+def create_order(order: Order):
37
+ return {"id": 1, "status": "pending"}
38
+```
39
+
40
+## OpenAPI Webhooks
41
+
42
+Define outbound webhook schemas:
43
+
44
+```python
45
+@app.webhooks.post("new-order")
46
+def new_order_webhook(order: Order):
47
+ """
48
+ This webhook is triggered when a new order is created.
49
+ """
50
+ pass
51
+```
52
+
53
+## See Also
54
+
55
+- [Additional Responses in OpenAPI](/advanced/additional-responses/) — error responses
56
+- [Metadata & Docs URLs](/tutorials/metadata/) — app metadata
57
+- [OpenAPI Callbacks Reference](/advanced/openapi-callbacks/) — full reference
0
58
▼docs_site/src/content/docs/advanced/response-cookies-headers.md
+57-0
1
+---
2
+title: Response Cookies and Headers
3
+description: Set cookies and custom headers on responses in JustAPI.
4
+keywords: [JustAPI, response cookies, response headers, Set-Cookie, custom headers]
5
+---
6
+
7
+## Setting Cookies
8
+
9
+```python
10
+from starlette.responses import JSONResponse
11
+from justapi import JustAPIApp
12
+
13
+app = JustAPIApp()
14
+
15
+@app.get("/set-cookie")
16
+def set_cookie():
17
+ response = JSONResponse(content={"message": "cookie set"})
18
+ response.set_cookie("session_id", "abc123", httponly=True, secure=True)
19
+ return response
20
+```
21
+
22
+## Deleting Cookies
23
+
24
+```python
25
+@app.get("/clear-cookie")
26
+def clear_cookie():
27
+ response = JSONResponse(content={"message": "cookie cleared"})
28
+ response.delete_cookie("session_id")
29
+ return response
30
+```
31
+
32
+## Cookie Options
33
+
34
+| Option | Description |
35
+|--------|-------------|
36
+| `max_age` | Expiration in seconds |
37
+| `httponly` | Prevent JavaScript access |
38
+| `secure` | Only send over HTTPS |
39
+| `samesite` | CSRF protection (`"lax"`, `"strict"`, `"none"`) |
40
+| `path` | Cookie scope path |
41
+
42
+## Custom Response Headers
43
+
44
+```python
45
+@app.get("/with-headers")
46
+def with_headers():
47
+ response = JSONResponse(content={"data": "value"})
48
+ response.headers["X-Request-Id"] = "req-123"
49
+ response.headers["X-Response-Time"] = "42ms"
50
+ return response
51
+```
52
+
53
+## See Also
54
+
55
+- [Return a Response Directly](/advanced/response-directly/) — full response control
56
+- [Security — First Steps](/tutorials/security/first-steps/) — auth with cookies
57
+- [Cookie Parameters](/tutorials/cookie-params/) — reading cookies
0
58
▼docs_site/src/content/docs/advanced/response-directly.md
+68-0
1
+---
2
+title: Return a Response Directly
3
+description: Return a Response object directly from a JustAPI handler for full control over headers, status, and body.
4
+keywords: [JustAPI, response, direct response, headers, status code]
5
+---
6
+
7
+## Returning a Response Object
8
+
9
+For full control over the response, return a `Response` object:
10
+
11
+```python
12
+from starlette.responses import JSONResponse
13
+from justapi import JustAPIApp
14
+
15
+app = JustAPIApp()
16
+
17
+@app.get("/custom")
18
+def custom_response():
19
+ return JSONResponse(
20
+ content={"message": "custom response"},
21
+ status_code=202,
22
+ headers={"X-Custom-Header": "value"},
23
+ )
24
+```
25
+
26
+## Response Classes
27
+
28
+| Class | Use Case |
29
+|-------|----------|
30
+| `JSONResponse` | JSON response with custom headers |
31
+| `HTMLResponse` | HTML content |
32
+| `PlainTextResponse` | Plain text |
33
+| `RedirectResponse` | Redirect to another URL |
34
+| `StreamingResponse` | Streaming data |
35
+| `FileResponse` | Serve a file |
36
+
37
+## Headers
38
+
39
+Set custom headers on any response:
40
+
41
+```python
42
+@app.get("/with-headers")
43
+def with_headers():
44
+ return JSONResponse(
45
+ content={"data": "value"},
46
+ headers={"X-Request-Id": "abc-123", "Cache-Control": "no-cache"},
47
+ )
48
+```
49
+
50
+## Redirect
51
+
52
+```python
53
+from starlette.responses import RedirectResponse
54
+
55
+@app.get("/old-path")
56
+def old_path():
57
+ return RedirectResponse(url="/new-path")
58
+
59
+@app.get("/new-path")
60
+def new_path():
61
+ return {"message": "you are here"}
62
+```
63
+
64
+## See Also
65
+
66
+- [Custom Response Classes](/advanced/custom-response/) — HTML, stream, file responses
67
+- [Response Status Code](/tutorials/response-status-code/) — status codes
68
+- [Response Cookies & Headers](/advanced/response-cookies-headers/) — cookies and headers
0
69
▼docs_site/src/content/docs/advanced/settings.md
+67-0
1
+---
2
+title: Settings and Environment Variables
3
+description: Manage configuration with environment variables and Pydantic Settings in JustAPI.
4
+keywords: [JustAPI, settings, environment variables, configuration, Pydantic Settings]
5
+---
6
+
7
+## Basic Settings with Pydantic
8
+
9
+```python
10
+from pydantic_settings import BaseSettings
11
+
12
+class Settings(BaseSettings):
13
+ database_url: str = "sqlite:///app.db"
14
+ secret_key: str = "change-me"
15
+ debug: bool = False
16
+ api_prefix: str = "/api/v1"
17
+
18
+ class Config:
19
+ env_file = ".env"
20
+
21
+settings = Settings()
22
+```
23
+
24
+## Using Settings in Your App
25
+
26
+```python
27
+from justapi import JustAPIApp
28
+
29
+app = JustAPIApp(title="My App", debug=settings.debug)
30
+
31
+@app.get("/config")
32
+def get_config():
33
+ return {
34
+ "debug": settings.debug,
35
+ "api_prefix": settings.api_prefix,
36
+ }
37
+```
38
+
39
+## .env File
40
+
41
+```env
42
+# .env
43
+DATABASE_URL=postgresql://user:pass@localhost/db
44
+SECRET_KEY=my-production-secret
45
+DEBUG=false
46
+API_PREFIX=/api/v1
47
+```
48
+
49
+:::warning
50
+Never commit `.env` files to version control. Add it to `.gitignore`.
51
+:::
52
+
53
+## Accessing Environment Variables
54
+
55
+```python
56
+import os
57
+
58
+# Standard library approach
59
+debug = os.getenv("DEBUG", "false").lower() == "true"
60
+database_url = os.getenv("DATABASE_URL", "sqlite:///app.db")
61
+```
62
+
63
+## See Also
64
+
65
+- [Lifespan Events](/advanced/lifespan-events/) — startup/shutdown
66
+- [Configuration Reference](/reference/configuration/) — all config options
67
+- [Deployment — Docker](/deployment/docker/) — environment in containers
0
68
▼docs_site/src/content/docs/advanced/sub-applications.md
+60-0
1
+---
2
+title: Sub Applications — Mounts
3
+description: Mount sub-applications and routers in JustAPI for modular application architecture.
4
+keywords: [JustAPI, sub-applications, mounts, routers, modular, APIRouter]
5
+---
6
+
7
+## Using APIRouter
8
+
9
+Split your application into multiple files:
10
+
11
+```python
12
+# routers/users.py
13
+from justapi import APIRouter
14
+
15
+router = APIRouter(prefix="/users", tags=["users"])
16
+
17
+@router.get("/")
18
+def list_users():
19
+ return []
20
+
21
+@router.get("/{user_id}")
22
+def get_user(user_id: int):
23
+ return {"user_id": user_id}
24
+```
25
+
26
+```python
27
+# main.py
28
+from justapi import JustAPIApp
29
+from routers.users import router as users_router
30
+
31
+app = JustAPIApp()
32
+app.include_router(users_router)
33
+```
34
+
35
+## Prefix and Tags
36
+
37
+```python
38
+app.include_router(users_router, prefix="/api/v1", tags=["users"])
39
+```
40
+
41
+All routes in `users_router` now start with `/api/v1/users/`.
42
+
43
+## Mounting Sub-Applications
44
+
45
+Mount an entire ASGI app at a sub-path:
46
+
47
+```python
48
+from justapi import JustAPIApp
49
+from starlette.applications import Starlette
50
+
51
+app = JustAPIApp()
52
+sub_app = Starlette()
53
+app.mount("/api/v2", sub_app)
54
+```
55
+
56
+## See Also
57
+
58
+- [Routing & Sub-routers](/tutorials/routing-subrouters/) — router basics
59
+- [Bigger Applications](/tutorials/routing-subrouters/) — multi-file structure
60
+- [Behind a Proxy](/advanced/behind-a-proxy/) — reverse proxy setup
0
61
▼docs_site/src/content/docs/advanced/templates.md
+70-0
1
+---
2
+title: Templates (Jinja2)
3
+description: Render Jinja2 templates for server-side HTML in JustAPI.
4
+keywords: [JustAPI, templates, Jinja2, HTML, server-side rendering]
5
+---
6
+
7
+## Basic Template Rendering
8
+
9
+Install dependencies:
10
+
11
+```bash
12
+pip install jinja2
13
+```
14
+
15
+Create a template directory:
16
+
17
+```
18
+templates/
19
+ index.html
20
+ items.html
21
+```
22
+
23
+Set up templates in your app:
24
+
25
+```python
26
+from justapi import JustAPIApp
27
+from starlette.templating import Jinja2Templates
28
+
29
+app = JustAPIApp()
30
+templates = Jinja2Templates(directory="templates")
31
+
32
+@app.get("/")
33
+def index(request):
34
+ return templates.TemplateResponse("index.html", {"request": request, "title": "Home"})
35
+```
36
+
37
+## Template Example
38
+
39
+```html
40
+<!-- templates/index.html -->
41
+<!DOCTYPE html>
42
+<html>
43
+<head>
44
+ <title>{{ title }}</title>
45
+</head>
46
+<body>
47
+ <h1>{{ title }}</h1>
48
+ <p>Welcome to JustAPI</p>
49
+</body>
50
+</html>
51
+```
52
+
53
+## Passing Data
54
+
55
+```python
56
+@app.get("/items")
57
+def list_items(request):
58
+ items = [{"id": 1, "name": "Widget"}, {"id": 2, "name": "Gadget"}]
59
+ return templates.TemplateResponse("items.html", {
60
+ "request": request,
61
+ "items": items,
62
+ "title": "Items",
63
+ })
64
+```
65
+
66
+## See Also
67
+
68
+- [Frontend](/tutorials/) — frontend integration
69
+- [Static Files](/tutorials/static-files/) — serving CSS/JS
70
+- [Custom Response Classes](/advanced/custom-response/) — HTML responses
0
71
▼docs_site/src/content/docs/advanced/using-request-directly.md
+63-0
1
+---
2
+title: Using the Request Directly
3
+description: Access the raw Starlette Request object for headers, body, and client info in JustAPI.
4
+keywords: [JustAPI, request object, raw request, headers, body, client]
5
+---
6
+
7
+## Accessing the Request
8
+
9
+Any handler can receive the raw `Request` object as a parameter:
10
+
11
+```python
12
+from starlette.requests import Request
13
+from justapi import JustAPIApp
14
+
15
+app = JustAPIApp()
16
+
17
+@app.get("/info")
18
+def get_info(request: Request):
19
+ return {
20
+ "method": request.method,
21
+ "url": str(request.url),
22
+ "client": request.client.host if request.client else None,
23
+ }
24
+```
25
+
26
+## Reading Headers
27
+
28
+```python
29
+@app.get("/headers")
30
+def get_headers(request: Request):
31
+ return {
32
+ "user_agent": request.headers.get("user-agent"),
33
+ "accept": request.headers.get("accept"),
34
+ "authorization": request.headers.get("authorization", "none"),
35
+ }
36
+```
37
+
38
+## Reading Body
39
+
40
+```python
41
+@app.post("/raw-body")
42
+async def raw_body(request: Request):
43
+ body = await request.body()
44
+ return {"size": len(body), "content": body.decode()}
45
+```
46
+
47
+## Path and Query Info
48
+
49
+```python
50
+@app.get("/request-info")
51
+def request_info(request: Request):
52
+ return {
53
+ "path": request.url.path,
54
+ "query": str(request.query_params),
55
+ "path_params": dict(request.path_params),
56
+ }
57
+```
58
+
59
+## See Also
60
+
61
+- [Path Parameters](/tutorials/path-params/) — extracting path params
62
+- [Header Parameters](/tutorials/header-params/) — typed header access
63
+- [Cookie Parameters](/tutorials/cookie-params/) — typed cookie access
0
64
▼docs_site/src/content/docs/advanced/websockets-advanced.md
+68-0
1
+---
2
+title: WebSockets Advanced
3
+description: Advanced WebSocket patterns — connection management, broadcasting, and testing in JustAPI.
4
+keywords: [JustAPI, WebSocket, advanced, broadcasting, connection management]
5
+---
6
+
7
+## WebSocket with Connection Manager
8
+
9
+```python
10
+from justapi import JustAPIApp
11
+from starlette.websockets import WebSocket, WebSocketDisconnect
12
+
13
+app = JustAPIApp()
14
+
15
+class ConnectionManager:
16
+ def __init__(self):
17
+ self.connections: list[WebSocket] = []
18
+
19
+ async def connect(self, websocket: WebSocket):
20
+ await websocket.accept()
21
+ self.connections.append(websocket)
22
+
23
+ def disconnect(self, websocket: WebSocket):
24
+ self.connections.remove(websocket)
25
+
26
+ async def broadcast(self, message: str):
27
+ for conn in self.connections:
28
+ await conn.send_text(message)
29
+
30
+manager = ConnectionManager()
31
+
32
+@app.websocket("/ws")
33
+async def websocket_endpoint(websocket: WebSocket):
34
+ await manager.connect(websocket)
35
+ try:
36
+ while True:
37
+ data = await websocket.receive_text()
38
+ await manager.broadcast(f"Echo: {data}")
39
+ except WebSocketDisconnect:
40
+ manager.disconnect(websocket)
41
+```
42
+
43
+## Private WebSocket Rooms
44
+
45
+```python
46
+from collections import defaultdict
47
+
48
+rooms: dict[str, list[WebSocket]] = defaultdict(list)
49
+
50
+@app.websocket("/ws/{room}")
51
+async def room_websocket(websocket: WebSocket, room: str):
52
+ await websocket.accept()
53
+ rooms[room].append(websocket)
54
+ try:
55
+ while True:
56
+ data = await websocket.receive_text()
57
+ for conn in rooms[room]:
58
+ if conn != websocket:
59
+ await conn.send_text(data)
60
+ except WebSocketDisconnect:
61
+ rooms[room].remove(websocket)
62
+```
63
+
64
+## See Also
65
+
66
+- [WebSockets & SSE](/tutorials/websockets-sse/) — basic WebSocket usage
67
+- [Streaming Output](/advanced/streaming-output/) — SSE streaming
68
+- [Resilience Patterns](/advanced/resilience-patterns/) — connection management
0
69
▼docs_site/src/content/docs/how-to/background-task-patterns.md
+79-0
1
+---
2
+title: Background Task Patterns
3
+description: Implement prioritized tasks, progress tracking, and error handling with JustAPI background tasks.
4
+keywords: [JustAPI, background tasks, patterns, priority, progress, error handling]
5
+---
6
+
7
+## Basic Background Tasks
8
+
9
+```python
10
+from justapi import JustAPIApp, BackgroundTasks
11
+
12
+app = JustAPIApp()
13
+
14
+def process_data(task_id: str, data: dict):
15
+ # Long-running processing
16
+ import time
17
+ time.sleep(5)
18
+ # Save results
19
+ print(f"Task {task_id} completed")
20
+
21
+@app.post("/process")
22
+def start_processing(data: dict, background_tasks: BackgroundTasks):
23
+ task_id = "task-123"
24
+ background_tasks.add_task(process_data, task_id, data)
25
+ return {"task_id": task_id, "status": "started"}
26
+```
27
+
28
+## Progress Tracking
29
+
30
+```python
31
+import asyncio
32
+
33
+task_progress = {}
34
+
35
+def update_progress(task_id: str, progress: int, status: str = "running"):
36
+ task_progress[task_id] = {"progress": progress, "status": status}
37
+
38
+def long_task(task_id: str):
39
+ for i in range(100):
40
+ time.sleep(0.1)
41
+ update_progress(task_id, i + 1)
42
+ update_progress(task_id, 100, "completed")
43
+
44
+@app.post("/tasks")
45
+def create_task(background_tasks: BackgroundTasks):
46
+ import uuid
47
+ task_id = str(uuid.uuid4())
48
+ update_progress(task_id, 0, "pending")
49
+ background_tasks.add_task(long_task, task_id)
50
+ return {"task_id": task_id}
51
+
52
+@app.get("/tasks/{task_id}")
53
+def get_task_progress(task_id: str):
54
+ return task_progress.get(task_id, {"error": "task not found"})
55
+```
56
+
57
+## Error Handling in Tasks
58
+
59
+```python
60
+def safe_task(task_id: str):
61
+ try:
62
+ # Risky operation
63
+ risky_operation()
64
+ update_progress(task_id, 100, "completed")
65
+ except Exception as e:
66
+ update_progress(task_id, 0, f"failed: {str(e)}")
67
+
68
+@app.post("/safe-tasks")
69
+def create_safe_task(background_tasks: BackgroundTasks):
70
+ task_id = "safe-task-1"
71
+ background_tasks.add_task(safe_task, task_id)
72
+ return {"task_id": task_id}
73
+```
74
+
75
+## See Also
76
+
77
+- [Background Tasks](/tutorials/background-tasks/) — basic background tasks
78
+- [Lifespan Events](/advanced/lifespan-events/) — startup/shutdown
79
+- [Settings & Environment Variables](/advanced/settings/) — configuration
0
80
▼docs_site/src/content/docs/how-to/circuit-breaker-recipes.md
+118-0
1
+---
2
+title: Circuit Breaker Recipes
3
+description: Configure circuit breakers, retry policies, and bulkheads for real-world scenarios in JustAPI.
4
+keywords: [JustAPI, circuit breaker, retry, bulkhead, resilience, patterns]
5
+---
6
+
7
+## Basic Circuit Breaker
8
+
9
+```python
10
+import time
11
+from justapi import JustAPIApp
12
+
13
+class CircuitBreaker:
14
+ def __init__(self, failure_threshold=3, recovery_timeout=60):
15
+ self.failure_count = 0
16
+ self.failure_threshold = failure_threshold
17
+ self.recovery_timeout = recovery_timeout
18
+ self.state = "closed"
19
+ self.last_failure_time = None
20
+
21
+ def call(self, func, *args, **kwargs):
22
+ if self.state == "open":
23
+ if time.time() - self.last_failure_time > self.recovery_timeout:
24
+ self.state = "half-open"
25
+ else:
26
+ raise Exception("Circuit breaker is open")
27
+
28
+ try:
29
+ result = func(*args, **kwargs)
30
+ self.failure_count = 0
31
+ self.state = "closed"
32
+ return result
33
+ except Exception as e:
34
+ self.failure_count += 1
35
+ self.last_failure_time = time.time()
36
+ if self.failure_count >= self.failure_threshold:
37
+ self.state = "open"
38
+ raise
39
+
40
+breaker = CircuitBreaker(failure_threshold=3, recovery_timeout=60)
41
+
42
+def unreliable_service():
43
+ # Simulate a failing service
44
+ import random
45
+ if random.random() < 0.5:
46
+ raise Exception("Service unavailable")
47
+ return {"status": "ok"}
48
+
49
+@app.get("/data")
50
+def get_data():
51
+ return breaker.call(unreliable_service)
52
+```
53
+
54
+## Retry with Backoff
55
+
56
+```python
57
+import asyncio
58
+from justapi import JustAPIApp
59
+
60
+async def retry_with_backoff(func, max_retries=3, base_delay=1):
61
+ for attempt in range(max_retries):
62
+ try:
63
+ return await func()
64
+ except Exception as e:
65
+ if attempt == max_retries - 1:
66
+ raise
67
+ await asyncio.sleep(base_delay * (2 ** attempt))
68
+
69
+@app.get("/retry")
70
+async def retry_example():
71
+ async def call_external():
72
+ # Simulate external call
73
+ import random
74
+ if random.random() < 0.7:
75
+ raise Exception("Temporary failure")
76
+ return {"data": "success"}
77
+
78
+ return await retry_with_backoff(call_external)
79
+```
80
+
81
+## Rate Limiting
82
+
83
+```python
84
+import time
85
+from collections import defaultdict
86
+
87
+class RateLimiter:
88
+ def __init__(self, max_requests=100, window=60):
89
+ self.max_requests = max_requests
90
+ self.window = window
91
+ self.requests = defaultdict(list)
92
+
93
+ def is_allowed(self, client_id):
94
+ now = time.time()
95
+ self.requests[client_id] = [
96
+ t for t in self.requests[client_id] if now - t < self.window
97
+ ]
98
+ if len(self.requests[client_id]) >= self.max_requests:
99
+ return False
100
+ self.requests[client_id].append(now)
101
+ return True
102
+
103
+limiter = RateLimiter(max_requests=100, window=60)
104
+
105
+@app.get("/api/data")
106
+def rate_limited_data(request):
107
+ client_id = request.client.host
108
+ if not limiter.is_allowed(client_id):
109
+ from starlette.responses import JSONResponse
110
+ return JSONResponse(content={"error": "Rate limit exceeded"}, status_code=429)
111
+ return {"data": "ok"}
112
+```
113
+
114
+## See Also
115
+
116
+- [Resilience Patterns](/advanced/resilience-patterns/) — full resilience guide
117
+- [Rate Limiting](/tutorials/middleware/) — built-in rate limiting
118
+- [Error Handling](/tutorials/error-handling/) — exception handling
0
119
▼docs_site/src/content/docs/how-to/configure-swagger-ui.md
+50-0
1
+---
2
+title: Configure Swagger UI
3
+description: Customize the Swagger UI appearance and behavior in JustAPI.
4
+keywords: [JustAPI, Swagger UI, documentation, OpenAPI, customization]
5
+---
6
+
7
+## Basic Configuration
8
+
9
+```python
10
+from justapi import JustAPIApp
11
+
12
+app = JustAPIApp(
13
+ docs_url="/docs",
14
+ redoc_url="/redoc",
15
+ swagger_ui_parameters={
16
+ "docExpansion": "none",
17
+ "filter": True,
18
+ "tagsSorter": "alpha",
19
+ "operationsSorter": "alpha",
20
+ },
21
+)
22
+```
23
+
24
+## Common Options
25
+
26
+| Parameter | Type | Description |
27
+|-----------|------|-------------|
28
+| `docExpansion` | `str` | `"none"`, `"list"`, `"full"` |
29
+| `filter` | `bool` or `str` | Enable search filter |
30
+| `tagsSorter` | `str` | `"alpha"` for alphabetical |
31
+| `operationsSorter` | `str` | `"alpha"` for alphabetical |
32
+| `defaultModelsExpandDepth` | `int` | Model expansion depth |
33
+| `defaultModelExpandDepth` | `int` | Individual model depth |
34
+
35
+## Disable Docs in Production
36
+
37
+```python
38
+import os
39
+
40
+app = JustAPIApp(
41
+ docs_url="/docs" if os.getenv("ENVIRONMENT") == "development" else None,
42
+ redoc_url="/redoc" if os.getenv("ENVIRONMENT") == "development" else None,
43
+)
44
+```
45
+
46
+## See Also
47
+
48
+- [Additional Responses in OpenAPI](/advanced/additional-responses/) — error docs
49
+- [Metadata & Docs URLs](/tutorials/metadata/) — app metadata
50
+- [OpenAPI Callbacks & Webhooks](/advanced/openapi-callbacks/) — outbound schemas
0
51
▼docs_site/src/content/docs/how-to/custom-request-route.md
+57-0
1
+---
2
+title: Custom Request and Route Classes
3
+description: Extend the Request and APIRoute classes in JustAPI for custom behavior.
4
+keywords: [JustAPI, custom request, custom route, APIRoute, extend]
5
+---
6
+
7
+## Custom Route Class
8
+
9
+Override the default `APIRoute` to add custom behavior:
10
+
11
+```python
12
+from starlette.routing import APIRoute
13
+from justapi import JustAPIApp, Request
14
+
15
+class TimingRoute(APIRoute):
16
+ def get_route_handler(self):
17
+ original_handler = super().get_route_handler()
18
+
19
+ async def custom_handler(request: Request):
20
+ import time
21
+ start = time.time()
22
+ response = await original_handler(request)
23
+ duration = time.time() - start
24
+ response.headers["X-Process-Time"] = str(round(duration, 4))
25
+ return response
26
+
27
+ return custom_handler
28
+
29
+app = JustAPIApp(route_class=TimingRoute)
30
+
31
+@app.get("/items/")
32
+def list_items():
33
+ return {"items": []}
34
+```
35
+
36
+## Custom Request Class
37
+
38
+```python
39
+from starlette.requests import Request
40
+
41
+class CustomRequest(Request):
42
+ async def json(self):
43
+ body = await super().json()
44
+ # Transform the body before validation
45
+ return body
46
+
47
+@app.post("/items")
48
+async def create_item(request: CustomRequest):
49
+ data = await request.json()
50
+ return data
51
+```
52
+
53
+## See Also
54
+
55
+- [Using the Request Directly](/advanced/using-request-directly/) — raw request access
56
+- [Advanced Middleware](/advanced/advanced-middleware/) — custom middleware
57
+- [Advanced Dependencies](/advanced/advanced-dependencies/) — custom deps
0
58
▼docs_site/src/content/docs/how-to/testing-database.md
+80-0
1
+---
2
+title: Testing a Database
3
+description: Use in-memory SQLite and transaction rollback for fast database tests in JustAPI.
4
+keywords: [JustAPI, testing, database, SQLite, in-memory, transactions]
5
+---
6
+
7
+## In-Memory SQLite
8
+
9
+Use in-memory SQLite for fast, isolated tests:
10
+
11
+```python
12
+import sqlite3
13
+from justapi import JustAPIApp, JustAPITestClient
14
+
15
+def get_test_db():
16
+ conn = sqlite3.connect(":memory:")
17
+ conn.execute("CREATE TABLE items (id INTEGER PRIMARY KEY, name TEXT)")
18
+ return conn
19
+
20
+app = JustAPIApp()
21
+
22
+@app.get("/items")
23
+def list_items():
24
+ db = get_test_db()
25
+ cursor = db.execute("SELECT * FROM items")
26
+ return {"items": cursor.fetchall()}
27
+
28
+def test_list_items_empty():
29
+ client = JustAPITestClient(app)
30
+ response = client.get("/items")
31
+ assert response.status_code == 200
32
+ assert response.json() == {"items": []}
33
+```
34
+
35
+## Transaction Rollback
36
+
37
+Wrap each test in a transaction and rollback:
38
+
39
+```python
40
+import pytest
41
+
42
+@pytest.fixture
43
+def db():
44
+ conn = sqlite3.connect(":memory:")
45
+ conn.execute("CREATE TABLE items (id INTEGER PRIMARY KEY, name TEXT)")
46
+ yield conn
47
+ conn.rollback() # undo all changes
48
+ conn.close()
49
+
50
+def test_create_item(db):
51
+ db.execute("INSERT INTO items (name) VALUES (?)", ("Widget",))
52
+ cursor = db.execute("SELECT * FROM items")
53
+ assert cursor.fetchone() is not None
54
+```
55
+
56
+## Dependency Override for Testing
57
+
58
+```python
59
+from justapi import Depends
60
+
61
+def get_db():
62
+ return production_db
63
+
64
+def override_get_db():
65
+ return sqlite3.connect(":memory:")
66
+
67
+app = JustAPIApp()
68
+app.dependency_overrides[get_db] = override_get_db
69
+
70
+def test_handler():
71
+ client = JustAPITestClient(app)
72
+ response = client.get("/items/")
73
+ assert response.status_code == 200
74
+```
75
+
76
+## See Also
77
+
78
+- [Testing](/tutorials/testing/) — basic testing
79
+- [SQL Databases](/tutorials/database-integration/) — database setup
80
+- [Advanced Dependencies](/advanced/advanced-dependencies/) — dependency overrides
0
81