Architecture¶
How Xitzin is structured internally.
Module Overview¶
xitzin/
├── application.py # Main Xitzin class
├── routing.py # Route and Router
├── requests.py # Request wrapper
├── responses.py # Response types
├── exceptions.py # Exception hierarchy
├── middleware.py # Middleware system
├── auth.py # Certificate authentication
├── templating.py # Jinja2 templates
└── testing.py # Test client
Core Components¶
Xitzin (application.py)¶
The central class that ties everything together:
class Xitzin:
def __init__(self, title, version, templates_dir):
self._router = Router()
self._middleware = []
self._startup_handlers = []
self._shutdown_handlers = []
self.state = AppState()
Key responsibilities:
- Route registration via decorators
- Middleware management
- Lifecycle events
- Template rendering
- Server lifecycle
Router and Route (routing.py)¶
Route represents a single registered endpoint:
- Path pattern with parameter extraction
- Handler function
- Optional input configuration
Router manages route matching:
- Stores routes in registration order
- Matches paths against patterns
- Returns matched route and extracted parameters
Request (requests.py)¶
Wraps the raw Gemini request from Nauyaca:
class Request:
def __init__(self, raw_request, app):
self._raw = raw_request
self.app = app
self.state = RequestState()
Provides convenient properties:
path,query,urlclient_cert,client_cert_fingerprintstatefor middleware data
Response Types (responses.py)¶
Three main response classes:
- Response: Success with body
- Input: Request user input
- Redirect: Redirect to URL
All implement to_gemini_response() for conversion.
Exceptions (exceptions.py)¶
Exception hierarchy mapping to Gemini status codes:
GeminiException (50)
├── InputRequired (10)
├── SensitiveInputRequired (11)
├── TemporaryFailure (40)
│ ├── ServerUnavailable (41)
│ ├── CGIError (42)
│ ├── ProxyError (43)
│ └── SlowDown (44)
├── PermanentFailure (50)
│ ├── NotFound (51)
│ ├── Gone (52)
│ ├── ProxyRequestRefused (53)
│ └── BadRequest (59)
└── CertificateRequired (60)
├── CertificateNotAuthorized (61)
└── CertificateNotValid (62)
Middleware (middleware.py)¶
Two patterns supported:
Function-based:
Class-based:
class MyMiddleware(BaseMiddleware):
async def before_request(self, request): ...
async def after_response(self, request, response): ...
Authentication (auth.py)¶
Decorators and helpers for certificate auth:
@require_certificate- Enforce authentication@require_fingerprint()- Whitelist specific certs@optional_certificate- Optional personalizationget_identity()- Access certificate info
Templating (templating.py)¶
Jinja2 integration for Gemtext:
TemplateEngine- Main rendering interfaceGemtextEnvironment- Custom Jinja2 environment- Filters:
link,heading,list,quote,preformat
Testing (testing.py)¶
In-memory testing utilities:
TestClient- Make requests without serverTestResponse- Response wrapper with helperstest_app()- Context manager for lifecycle
Design Patterns¶
Decorator-Based Registration¶
Routes are registered via decorators:
The decorator stores the handler in the router and returns it unchanged.
Async/Sync Handler Support¶
Both sync and async handlers are supported:
# Sync handler - wrapped in executor
@app.gemini("/sync")
def sync_handler(request: Request):
return "sync"
# Async handler - used directly
@app.gemini("/async")
async def async_handler(request: Request):
return "async"
Sync handlers are automatically wrapped to run in a thread pool executor.
Response Conversion¶
Handlers can return various types:
# String → Response with text/gemini
return "# Hello"
# Response object
return Response(body="data", mime_type="text/plain")
# Tuple for control
return ("body", 20, "text/gemini")
The convert_response() function handles all conversions.
State Storage¶
Two levels of state:
- App state (
app.state): Shared across all requests - Request state (
request.state): Per-request, middleware data
# App startup
app.state.db = connect_database()
# Middleware stores data
request.state.user = get_user(request)
# Handler accesses it
user = request.state.user
Dependencies¶
Xitzin builds on:
- Nauyaca: Gemini protocol implementation
- Jinja2: Template engine