### Install Dependencies with uv Source: https://github.com/alanbato/xitzin/blob/main/examples/guestbook/README.md Installs project dependencies using the 'uv' package manager. This is a prerequisite for running the guestbook application. ```bash cd examples/guestbook uv sync ``` -------------------------------- ### Create Basic Gemini App with Xitzin Source: https://github.com/alanbato/xitzin/blob/main/docs/getting-started/quickstart.md This Python code snippet demonstrates how to create a simple Gemini application using the Xitzin framework. It defines a single route '/' that returns a welcome message. Ensure the 'xitzin' library is installed. ```python from xitzin import Xitzin, Request app = Xitzin() @app.gemini("/") def home(request: Request): return "# Welcome to my capsule!" if __name__ == "__main__": app.run() ``` -------------------------------- ### Install Xitzin from Source Source: https://github.com/alanbato/xitzin/blob/main/docs/getting-started/installation.md Installs Xitzin from its GitHub repository for development or to access the latest changes. This involves cloning the repository, navigating into the directory, and syncing dependencies with uv. ```bash git clone https://github.com/alanbato/xitzin.git cd xitzin uv sync ``` -------------------------------- ### User Input Handling Source: https://github.com/alanbato/xitzin/blob/main/docs/getting-started/quickstart.md Shows how to use the `@app.input` decorator to prompt users for input and process their responses. ```APIDOC ## INPUT /search ### Description Prompts the user for a search query and displays the results. ### Method INPUT ### Endpoint /search ### Parameters #### Query Parameter - **query** (string) - Required - The search term entered by the user. ### Response #### Success Response (200) - **gemini_content** (string) - Gemtext content displaying the search results. ### Response Example ``` # Search Results You searched for: example query * Result 1 * Result 2 * Result 3 ``` ``` -------------------------------- ### Path Parameters Source: https://github.com/alanbato/xitzin/blob/main/docs/getting-started/quickstart.md Illustrates how to define routes with dynamic path parameters and how they are automatically converted to the correct types. ```APIDOC ## GET /user/{username} ### Description Retrieves a user's profile based on their username. ### Method GET ### Endpoint /user/{username} ### Parameters #### Path Parameters - **username** (string) - Required - The username of the profile to retrieve. ### Response #### Success Response (200) - **gemini_content** (string) - Gemtext content displaying the user's profile. ### Response Example ``` # johndoe's Profile Welcome to the profile of johndoe! ``` ``` ```APIDOC ## GET /post/{post_id} ### Description Retrieves a specific post based on its ID. ### Method GET ### Endpoint /post/{post_id} ### Parameters #### Path Parameters - **post_id** (integer) - Required - The ID of the post to retrieve. ### Response #### Success Response (200) - **gemini_content** (string) - Gemtext content displaying the post details. ### Response Example ``` # Post #123 ``` ``` -------------------------------- ### Multiple Routes Source: https://github.com/alanbato/xitzin/blob/main/docs/getting-started/quickstart.md Demonstrates how to define multiple routes for different paths, including a root path with navigation links. ```APIDOC ## GET / ### Description Provides a welcome message and navigation links to other sections of the capsule. ### Method GET ### Endpoint / ### Response #### Success Response (200) - **gemini_content** (string) - Gemtext content including welcome message and links. ### Response Example ``` # Welcome to my capsule! => /about About me => /projects My projects ``` ``` ```APIDOC ## GET /about ### Description Displays information about the capsule creator. ### Method GET ### Endpoint /about ### Response #### Success Response (200) - **gemini_content** (string) - Gemtext content with about information and a link back home. ### Response Example ``` # About Me I'm building cool things with Xitzin! => / Back home ``` ``` ```APIDOC ## GET /projects ### Description Lists the projects associated with the capsule. ### Method GET ### Endpoint /projects ### Response #### Success Response (200) - **gemini_content** (string) - Gemtext content listing projects and a link back home. ### Response Example ``` # My Projects * Project Alpha * Project Beta * Project Gamma => / Back home ``` ``` -------------------------------- ### Basic Route Definition Source: https://github.com/alanbato/xitzin/blob/main/docs/getting-started/quickstart.md Defines a simple route for the root path '/' and runs the Xitzin application. ```APIDOC ## POST /api/users ### Description This endpoint allows for the creation of new users. ### Method POST ### Endpoint /api/users ### Parameters #### Request Body - **username** (string) - Required - The desired username for the new user. - **email** (string) - Required - The email address for the new user. - **password** (string) - Required - The password for the new user. ### Request Example ```json { "username": "johndoe", "email": "john.doe@example.com", "password": "securepassword123" } ``` ### Response #### Success Response (201) - **id** (string) - The unique identifier for the newly created user. - **username** (string) - The username of the created user. - **email** (string) - The email address of the created user. #### Response Example ```json { "id": "user-12345", "username": "johndoe", "email": "john.doe@example.com" } ``` ``` -------------------------------- ### Project Setup and Initialization with Uvicorn Source: https://github.com/alanbato/xitzin/blob/main/docs/tutorials/building-a-guestbook.md This snippet demonstrates the command-line steps to set up a new project directory, initialize it with uvicorn, and add the 'xitzin' dependency. It's the foundational setup for the guestbook application. ```bash mkdir guestbook cd guestbook mkdir templates uv init uv add xitzin ``` -------------------------------- ### Run Guestbook Application with uv Source: https://github.com/alanbato/xitzin/blob/main/examples/guestbook/README.md Starts the Xitzin guestbook application using 'uv run'. The application will be accessible via a self-signed certificate at gemini://localhost:1965/. ```bash uv run python app.py ``` -------------------------------- ### Verify Xitzin Installation Source: https://github.com/alanbato/xitzin/blob/main/docs/getting-started/installation.md Confirms that Xitzin has been successfully installed by importing it in a Python interpreter and checking its version. This is a crucial step after installation. ```python import xitzin print(xitzin.__version__) ``` -------------------------------- ### Serve Documentation with uv and MkDocs Source: https://github.com/alanbato/xitzin/blob/main/docs/contributing.md Starts a local development server to preview the documentation with hot reloading. Built using MkDocs and the Material theme. ```bash uv run mkdocs serve ``` -------------------------------- ### Python RateLimitMiddleware Setup Source: https://github.com/alanbato/xitzin/blob/main/docs/how-to/middleware.md Provides an example of configuring `RateLimitMiddleware` for basic rate limiting. It allows setting the maximum number of requests within a specified time window and the duration for retrying after being rate-limited. ```python from xitzin.middleware import RateLimitMiddleware app.add_middleware(RateLimitMiddleware( max_requests=10, # Max requests per window window_seconds=60.0, # Time window retry_after=30 # Seconds to wait when rate limited )) ``` -------------------------------- ### Run Tests with pytest Source: https://github.com/alanbato/xitzin/blob/main/examples/guestbook/README.md Executes the test suite for the guestbook example using 'pytest'. This verifies the functionality of the application. ```bash uv run pytest tests/test_example_app.py -v ``` -------------------------------- ### Complete Test Example with Pytest and xitzin Source: https://github.com/alanbato/xitzin/blob/main/docs/how-to/testing.md Presents a comprehensive example of a test suite using pytest fixtures and xitzin's testing utilities. It demonstrates testing different aspects of an application, including public pages, authentication, and input flows, within a structured class-based test setup. ```python import pytest from xitzin.testing import TestClient, test_app from myapp import app, users @pytest.fixture def client(): users.clear() # Reset state return TestClient(app) @pytest.fixture def auth_client(client): return client.with_certificate("test-user") class TestPublicPages: def test_home(self, client): response = client.get("/") assert response.is_success assert "Welcome" in response.body def test_about(self, client): response = client.get("/about") assert response.is_success class TestAuthentication: def test_private_requires_cert(self, client): response = client.get("/private") assert response.status == 60 def test_private_with_cert(self, auth_client): response = auth_client.get("/private") assert response.is_success class TestRegistration: def test_registration_flow(self, auth_client): # Enter name response = auth_client.get_input("/register", "Alice") assert response.is_success assert "Welcome, Alice" in response.body ``` -------------------------------- ### Implement User Input Prompts in Gemini Source: https://github.com/alanbato/xitzin/blob/main/docs/getting-started/quickstart.md This Python code uses the `@app.input` decorator in Xitzin to create Gemini routes that prompt the user for input. The provided `prompt` string is displayed to the user, and their response is passed as an argument (e.g., `query`) to the decorated function. Requires the 'xitzin' library. ```python @app.input("/search", prompt="Enter your search query:") def search(request: Request, query: str): return f"# Search Results\n\nYou searched for: {query}\n\n* Result 1\n* Result 2\n* Result 3\n" ``` -------------------------------- ### Manage Xitzin Systemd Service (Bash) Source: https://github.com/alanbato/xitzin/blob/main/docs/how-to/deployment.md Provides bash commands to reload the systemd daemon, enable the Xitzin service to start on boot, and start the service immediately. ```bash sudo systemctl daemon-reload sudo systemctl enable my-capsule sudo systemctl start my-capsule ``` -------------------------------- ### Create a Basic Xitzin Gemini Capsule Source: https://github.com/alanbato/xitzin/blob/main/README.md A minimal example of a Xitzin application that defines a single root route and starts the server. This serves as a starting point for building a Gemini capsule with Xitzin. ```python from xitzin import Xitzin, Request app = Xitzin() @app.gemini("/") def home(request: Request): return "# Hello, Geminispace!" if __name__ == "__main__": app.run() ``` -------------------------------- ### Install Xitzin with pip Source: https://github.com/alanbato/xitzin/blob/main/docs/getting-started/installation.md Installs the Xitzin package and its core dependencies using the pip package manager. Ensure Python 3.10 or higher is installed. ```bash pip install xitzin ``` -------------------------------- ### Complete Request Flow Example Output Source: https://github.com/alanbato/xitzin/blob/main/docs/explanation/request-lifecycle.md Provides a concrete example of a successful request flow through Xitzin, starting from the initial Gemini request URL. It details each step: route matching, middleware execution (before and after), handler invocation, response conversion, and the final sent response, including status and body. ```text # 1. Request: gemini://example.com/user/alice # 2. Route matched: /user/{username} # params = {"username": "alice"} # 3. No input_prompt, skip input flow # 4. Middleware before: # - LoggingMiddleware: logs "Request: /user/alice" # - TimingMiddleware: sets start_time # 5. Handler called: @app.gemini("/user/{username}") def profile(request, username): return f"# {username}'s Profile" # returns: "# alice's Profile" # 6. Response converted: # GeminiResponse(status=20, meta="text/gemini", body="# alice's Profile") # 7. Middleware after: # - TimingMiddleware: calculates elapsed_time # - LoggingMiddleware: logs "Response: 20" # 8. No exceptions, response sent: # 20 text/gemini\r\n # # alice's Profile ``` -------------------------------- ### Initialize Project with uv Source: https://github.com/alanbato/xitzin/blob/main/docs/tutorials/your-first-capsule.md Sets up a new project directory and installs the 'xitzin' library using the 'uv' package manager. This is the initial step for creating a new Xitzin application. ```bash mkdir my-capsule cd my-capsule uv init uv add xitzin ``` -------------------------------- ### Install Dependencies with uv Source: https://github.com/alanbato/xitzin/blob/main/docs/contributing.md Installs project dependencies, including development and documentation tools, using the uv package manager. Ensures all necessary libraries are available for development and testing. ```bash uv sync --group dev --group docs ``` -------------------------------- ### Install Xitzin with uv Source: https://github.com/alanbato/xitzin/blob/main/docs/getting-started/installation.md Installs the Xitzin package using the uv package manager, which is recommended for Python projects. This command adds xitzin to your project's dependencies. ```bash uv add xitzin ``` -------------------------------- ### After Response Middleware Example in Python Source: https://github.com/alanbato/xitzin/blob/main/docs/explanation/request-lifecycle.md Provides an example of middleware that executes after the response has been generated, specifically demonstrating how to measure request processing time. The `TimingMiddleware` logs the start time before the request and calculates the elapsed time after the response, storing it in `request.state`. ```python class TimingMiddleware(BaseMiddleware): async def before_request(self, request): request.state.start_time = time.perf_counter() return None async def after_response(self, request, response): elapsed = time.perf_counter() - request.state.start_time request.state.elapsed_time = elapsed return response ``` -------------------------------- ### Render Xitzin Template Source: https://github.com/alanbato/xitzin/blob/main/examples/guestbook/README.md Demonstrates how to render a Gemini template using the 'app.template()' function in Xitzin. It shows passing parameters to the template for dynamic content generation. ```python return app.template( "base.gmi", title="Page Title", content="Page content here", show_sign=True, ) ``` -------------------------------- ### Add Multiple Routes to Gemini App Source: https://github.com/alanbato/xitzin/blob/main/docs/getting-started/quickstart.md This Python code extends a basic Xitzin Gemini application by adding multiple routes (`/about`, `/projects`) and defining their respective Gemtext responses. It demonstrates how to structure responses with links using Gemtext syntax. Requires the 'xitzin' library. ```python from xitzin import Xitzin, Request app = Xitzin() @app.gemini("/") def home(request: Request): return "# Welcome to my capsule!\n\n=> /about About me\n=> /projects My projects\n" @app.gemini("/about") def about(request: Request): return "# About Me\n\nI'm building cool things with Xitzin!\n\n=> / Back home\n" @app.gemini("/projects") def projects(request: Request): return "# My Projects\n\n* Project Alpha\n* Project Beta\n* Project Gamma\n\n=> / Back home\n" if __name__ == "__main__": app.run() ``` -------------------------------- ### Setup Templates Directory (Python) Source: https://github.com/alanbato/xitzin/blob/main/docs/how-to/templates.md Configures the directory for template files when initializing a Xitzin application. It uses `pathlib.Path` to construct the path relative to the current file's directory. ```python from pathlib import Path app = Xitzin( templates_dir=Path(__file__).parent / "templates" ) ``` -------------------------------- ### Docker Build Configuration for Xitzin Source: https://github.com/alanbato/xitzin/blob/main/docs/how-to/deployment.md A Dockerfile for building a production-ready Xitzin image. It uses a slim Python base image, installs dependencies with `uv`, copies project files, and sets the command to run the application. ```dockerfile FROM python:3.12-slim WORKDIR /app # Install uv RUN pip install uv # Copy project files COPY pyproject.toml uv.lock ./ RUN uv sync --frozen COPY . . # Expose Gemini port EXPOSE 1965 CMD ["uv", "run", "python", "app.py"] ``` -------------------------------- ### Test Application Lifecycle Events with test_app Source: https://github.com/alanbato/xitzin/blob/main/docs/how-to/testing.md Demonstrates how to test application startup and shutdown handlers using the `test_app` context manager. This ensures that setup and cleanup code runs correctly during tests. ```python from xitzin.testing import test_app def test_with_lifecycle(): with test_app(app) as client: # Startup handlers have run response = client.get("/") assert response.is_success # Shutdown handlers have run ``` -------------------------------- ### Create a Template File (Jinja) Source: https://github.com/alanbato/xitzin/blob/main/docs/how-to/templates.md Demonstrates the structure of a basic Jinja template file (`.gmi`) which can include variables, loops, and links. This serves as a fundamental example for creating dynamic content. ```jinja {# templates/page.gmi #} # {{ title }} {{ description }} {% for item in items %} * {{ item }} {% endfor %} => / Home ``` -------------------------------- ### Make GET Requests and Assert Responses Source: https://github.com/alanbato/xitzin/blob/main/docs/how-to/testing.md Demonstrates how to make a GET request to a specific path and assert conditions on the response. It checks for successful status and verifies the presence of expected text in the response body. This is a fundamental pattern for testing endpoint functionality. ```python def test_home(): client = TestClient(app) response = client.get("/") assert response.is_success assert "Welcome" in response.body ``` -------------------------------- ### CGI Script Output Examples (Python) Source: https://github.com/alanbato/xitzin/blob/main/docs/how-to/cgi-scripts.md Illustrates various output formats for CGI scripts in Python, demonstrating how to generate different Gemini response types using status codes and meta fields. Includes examples for success, input prompts, redirects, and errors. ```python # Success with content print("20 text/gemini") print() print("# Page Title") # Request input print("10 Enter search query:") # Redirect print("30 gemini://example.com/new-location") # Error print("51 Page not found") ``` -------------------------------- ### Configure Xitzin with Environment Variables (Python) Source: https://github.com/alanbato/xitzin/blob/main/docs/how-to/deployment.md Loads Xitzin configuration settings such as host, port, certificate file, and key file from environment variables, with default fallbacks. It then runs the application using these configured values. ```python import os HOST = os.environ.get("GEMINI_HOST", "localhost") PORT = int(os.environ.get("GEMINI_PORT", "1965")) CERT_FILE = os.environ.get("GEMINI_CERT", "cert.pem") KEY_FILE = os.environ.get("GEMINI_KEY", "key.pem") if __name__ == "__main__": app.run( host=HOST, port=PORT, certfile=CERT_FILE, keyfile=KEY_FILE ) ``` -------------------------------- ### Template Inheritance Example (Jinja) Source: https://github.com/alanbato/xitzin/blob/main/docs/how-to/templates.md Shows how to implement template inheritance using Jinja's `{% extends %}` and `{% block %}` tags. A base template defines the overall structure, which child templates can override. ```jinja {# templates/base.gmi #} # {{ title }} {% block content %}{% endblock %} --- {{ "/" | link("Home") }} {# templates/about.gmi #} {% extends "base.gmi" %} {% block content %} Welcome to the about page! This is my personal capsule. {% endblock %} ``` -------------------------------- ### Python Short-Circuit Response Example Source: https://github.com/alanbato/xitzin/blob/main/docs/how-to/middleware.md Demonstrates how a middleware can return a `GeminiResponse` directly from its `before_request` method to bypass the main request handler. This is useful for implementing features like maintenance mode. ```python from xitzin.middleware import BaseMiddleware, Request from nauyaca import GeminiResponse, StatusCode class MaintenanceMiddleware(BaseMiddleware): def __init__(self, maintenance_mode: bool = False): self.maintenance_mode = maintenance_mode async def before_request(self, request: Request): if self.maintenance_mode: return GeminiResponse( status=StatusCode.TEMPORARY_FAILURE, meta="Under maintenance" ) return None ``` -------------------------------- ### Python Example: Serving JSON data with Gemini Source: https://github.com/alanbato/xitzin/blob/main/docs/explanation/gemtext-format.md A Python code snippet demonstrating how to serve JSON data using the Xitzin framework, specifying the MIME type as 'application/json'. ```python from xitzin import Request, Response @app.gemini("/data.json") def json_data(request: Request): return Response('{"key": "value"}', mime_type="application/json") ``` -------------------------------- ### Run Xitzin Gemini Capsule Source: https://github.com/alanbato/xitzin/blob/main/docs/tutorials/your-first-capsule.md Starts the Xitzin Gemini application server. This command executes the Python script containing the capsule's routes and handlers, making it accessible via a Gemini client. ```bash python capsule.py ``` -------------------------------- ### Run Gemini Application (Python) Source: https://github.com/alanbato/xitzin/blob/main/docs/tutorials/your-first-capsule.md This is the standard Python entry point to run the Gemini application. It checks if the script is being executed directly and, if so, calls the `app.run()` method to start the server. ```python ```python if __name__ == "__main__": app.run() ``` ``` -------------------------------- ### Python Middleware Order Demonstration Source: https://github.com/alanbato/xitzin/blob/main/docs/how-to/middleware.md Illustrates how the order of middleware registration affects execution flow. The example shows two function-based middleware, `first` and `second`, and the expected sequence of their before and after execution blocks relative to the handler. ```python @app.middleware async def first(request, call_next): print("1. First - before") response = await call_next(request) print("4. First - after") return response @app.middleware async def second(request, call_next): print("2. Second - before") response = await call_next(request) print("3. Second - after") return response # The output sequence would be: # 1. First - before # 2. Second - before # [handler runs] # 3. Second - after # 4. First - after ``` -------------------------------- ### HTTP Request Format Example for Comparison Source: https://github.com/alanbato/xitzin/blob/main/docs/explanation/gemini-protocol.md Illustrates a typical HTTP request, showcasing the presence of various headers like Host, User-Agent, Accept, and Cookie, which are absent in Gemini requests. ```http GET /path/to/page HTTP/1.1\nHost: example.com\nUser-Agent: ...\nAccept: ...\nCookie: ...\n[many more headers] ``` -------------------------------- ### Test Path Parameters with GET Requests Source: https://github.com/alanbato/xitzin/blob/main/docs/how-to/testing.md Illustrates testing routes that accept path parameters. The `client.get()` method is used with a dynamic path, and the response is checked for success and content related to the provided parameter. ```python def test_user_profile(): client = TestClient(app) response = client.get("/user/alice") assert response.is_success assert "alice" in response.body ``` -------------------------------- ### Run Xitzin with Custom Certificates (Python) Source: https://github.com/alanbato/xitzin/blob/main/docs/how-to/deployment.md Runs the Xitzin application using specified certificate and key files. This Python snippet demonstrates how to configure the application to use custom SSL certificates for secure communication. ```python if __name__ == "__main__": app.run( host="0.0.0.0", port=1965, certfile="cert.pem", keyfile="key.pem" ) ``` -------------------------------- ### Build User System with Registration and Profile Pages Source: https://github.com/alanbato/xitzin/blob/main/docs/how-to/authentication.md This example demonstrates how to build a user system using Xitzin's authentication decorators. It includes routes for user registration (requiring a certificate), setting a username via input, and viewing a user's profile. A simple dictionary `users` is used for in-memory storage. ```python # Simple user store users = {} @app.gemini("/register") @require_certificate def register(request: Request): identity = get_identity(request) if identity.fingerprint in users: return f"# Already registered as {users[identity.fingerprint]['name']}" return "=> /register/name Choose a username" @app.input("/register/name", prompt="Choose a username:") @require_certificate def register_name(request: Request, query: str): identity = get_identity(request) users[identity.fingerprint] = { "name": query, "registered": datetime.now(), } return f"# Welcome, {query}!" @app.gemini("/profile") @require_certificate def profile(request: Request): identity = get_identity(request) user = users.get(identity.fingerprint) if not user: return "=> /register Please register first" return f"# {user['name']}'s Profile Registered: {user['registered']} Certificate: {identity.short_id} " ``` -------------------------------- ### Creating and Running a Gemini Application Source: https://context7.com/alanbato/xitzin/llms.txt Demonstrates how to create a basic Xitzin application, define routes with path parameters, and run the application with or without custom TLS certificates. ```APIDOC ## POST / HTTP/1.1 ### Description Defines the root route for the Gemini application. ### Method GET ### Endpoint / ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Request Example None ### Response #### Success Response (200) - **string** - The Gemtext content to be displayed. #### Response Example ``` # Welcome to Geminispace! ``` ## POST /user/{username} HTTP/1.1 ### Description Defines a route that accepts a username as a path parameter. ### Method GET ### Endpoint /user/{username} ### Parameters #### Path Parameters - **username** (string) - Required - The username to be displayed. #### Query Parameters None #### Request Body None ### Request Example None ### Response #### Success Response (200) - **string** - The Gemtext content including the username. #### Response Example ``` # Alice's Profile Welcome to Alice's page. ``` ## POST /post/{post_id} HTTP/1.1 ### Description Defines a route that accepts a post ID as a path parameter, automatically converting it to an integer. ### Method GET ### Endpoint /post/{post_id} ### Parameters #### Path Parameters - **post_id** (integer) - Required - The ID of the post to be displayed. #### Query Parameters None #### Request Body None ### Request Example None ### Response #### Success Response (200) - **string** - The Gemtext content including the post ID. #### Response Example ``` # Post 123 Showing post number 123. ``` ## POST / HTTP/1.1 ### Description Runs the Xitzin application, either with auto-generated self-signed certificates or with provided TLS certificates. ### Method RUN ### Endpoint N/A ### Parameters #### Path Parameters None #### Query Parameters - **host** (string) - Required - The host address to bind to. - **port** (integer) - Required - The port number to listen on. - **certfile** (string) - Optional - Path to the TLS certificate file. - **keyfile** (string) - Optional - Path to the TLS private key file. #### Request Body None ### Request Example ```python app.run(host="localhost", port=1965) app.run(host="0.0.0.0", port=1965, certfile="cert.pem", keyfile="key.pem") ``` ### Response None #### Response Example None ``` -------------------------------- ### Create and Run a Gemini Application with Xitzin Source: https://context7.com/alanbato/xitzin/llms.txt Demonstrates how to initialize a Xitzin application, define routes using decorators, and run the server. Supports automatic or custom TLS certificate handling. Path parameters are automatically type-converted. ```python from xitzin import Xitzin, Request app = Xitzin(title="My Capsule", version="1.0.0") @app.gemini("/") def home(request: Request): return "# Welcome to Geminispace!" @app.gemini("/user/{username}") def profile(request: Request, username: str): return f"# {username}'s Profile\n\nWelcome to {username}'s page." @app.gemini("/post/{post_id}") def get_post(request: Request, post_id: int): # Path parameters are automatically type-converted return f"# Post {post_id}\n\nShowing post number {post_id}." if __name__ == "__main__": # Run with auto-generated self-signed certificate app.run(host="localhost", port=1965) # Or provide your own TLS certificates # app.run(host="0.0.0.0", port=1965, # certfile="cert.pem", keyfile="key.pem") ``` -------------------------------- ### Xitzin Quick Example: Routing and Input Handling Source: https://github.com/alanbato/xitzin/blob/main/docs/index.md Demonstrates basic Xitzin usage, including defining routes with decorators, handling path parameters, and setting up input prompts for user interaction. This snippet showcases the core routing mechanisms and how to integrate user input into Gemini capsules. ```python from xitzin import Xitzin, Request app = Xitzin() @app.gemini("/") def home(request: Request): return "# Welcome to my capsule!" @app.gemini("/user/{username}") def profile(request: Request, username: str): return f"# {username}'s Profile" @app.input("/search", prompt="Enter search query:") def search(request: Request, query: str): return f"# Results for: {query}" if __name__ == "__main__": app.run() ``` -------------------------------- ### Build Documentation with uv and MkDocs Source: https://github.com/alanbato/xitzin/blob/main/docs/contributing.md Builds the documentation for production using MkDocs. The output will be static HTML files ready for deployment. ```bash uv run mkdocs build ``` -------------------------------- ### Docker Health Check Configuration Source: https://github.com/alanbato/xitzin/blob/main/docs/how-to/deployment.md Configures a health check for a service within a Docker Compose setup. It specifies a test command to run, interval, timeout, and retry count to ensure the container is healthy. ```yaml healthcheck: test: ["CMD", "curl", "-f", "gemini://localhost:1965/health"] interval: 30s timeout: 10s retries: 3 ``` -------------------------------- ### Validating User Input with Type Conversion and Range Checks in Python Source: https://github.com/alanbato/xitzin/blob/main/docs/how-to/input-handling.md Provides an example of how to validate user input by attempting to convert it to an integer and checking if it falls within an acceptable range (0-150). It handles potential `ValueError` exceptions for non-numeric input and guides the user back if validation fails. ```python from xitzin import Request @app.input("/age", prompt="Enter your age:") def get_age(request: Request, query: str): try: age = int(query) if age < 0 or age > 150: return "# Invalid age. Please try again.\n\n=> /age Try Again" return f"# You are {age} years old" except ValueError: return "# Please enter a number.\n\n=> /age Try Again" ``` -------------------------------- ### Run Gemini Application (Python) Source: https://github.com/alanbato/xitzin/blob/main/docs/tutorials/building-a-guestbook.md Executes the Gemini application using the `uv` command-line tool. This snippet shows the standard Python entry point for running the application server. ```python if __name__ == "__main__": app.run() ``` -------------------------------- ### CGI Script Using TLS Certificate Info (Python) Source: https://github.com/alanbato/xitzin/blob/main/docs/how-to/cgi-scripts.md An example Python CGI script that accesses TLS client certificate information passed via environment variables (TLS_CLIENT_HASH, TLS_CLIENT_AUTHORISED). It demonstrates how to check for client certificate presence and display its hash. Requires a TLS-enabled server setup. ```python #!/usr/bin/env python3 import os cert_hash = os.environ.get("TLS_CLIENT_HASH", "") authorised = os.environ.get("TLS_CLIENT_AUTHORISED", "0") print("20 text/gemini") print() print("# Identity Info") print() if authorised == "1": print(f"Your certificate: {cert_hash[:16]}...") else: print("You are not using a client certificate.") ``` -------------------------------- ### Chaining Multiple Inputs for Signup Flow in Python Source: https://github.com/alanbato/xitzin/blob/main/docs/how-to/input-handling.md Demonstrates how to chain multiple input prompts to create a multi-step user registration process. It uses redirects (`=> /path`) to move the user from one input prompt to the next, storing intermediate data in a session. Requires careful state management in production. ```python # Store data between requests (use a proper session store in production) sessions = {} @app.input("/signup", prompt="Enter username:") @require_certificate def signup_username(request: Request, query: str): identity = get_identity(request) sessions[identity.fingerprint] = {"username": query} return "=> /signup/email Continue" @app.input("/signup/email", prompt="Enter email:") @require_certificate def signup_email(request: Request, query: str): identity = get_identity(request) data = sessions.get(identity.fingerprint, {}) data["email"] = query return f"# Registration Complete\n\nUsername: {data.get('username')}\nEmail: {data.get('email')}" ``` -------------------------------- ### Handle Path Parameters in Gemini Routes Source: https://github.com/alanbato/xitzin/blob/main/docs/getting-started/quickstart.md This Python snippet shows how to define Gemini routes in Xitzin that capture dynamic values from the URL path, such as usernames or post IDs. The captured values are passed as arguments to the route handler function and can be automatically type-casted (e.g., to `int`). Requires the 'xitzin' library. ```python @app.gemini("/user/{username}") def profile(request: Request, username: str): return f"# {username}'s Profile\n\nWelcome to the profile of {username}!\n" @app.gemini("/post/{post_id}") def post(request: Request, post_id: int): # post_id is automatically converted to int return f"# Post #{post_id}" ``` -------------------------------- ### Response Conversion Examples (Python) Source: https://github.com/alanbato/xitzin/blob/main/docs/explanation/architecture.md Provides examples of different return types from handler functions that Xitzin can automatically convert into Gemini responses, including strings, Response objects, and tuples. ```python # String → Response with text/gemini return "# Hello" ``` ```python # Response object return Response(body="data", mime_type="text/plain") ``` ```python # Tuple for control return ("body", 20, "text/gemini") ``` -------------------------------- ### Xitzin Application Lifecycle and State Management Source: https://context7.com/alanbato/xitzin/llms.txt Demonstrates how to manage application state in Xitzin using startup and shutdown event handlers. It shows initializing resources like database connections and caches during startup and cleaning them up during shutdown. Application state is accessed via `app.state` and request state via `request.state`. Supports asynchronous handlers and multiple handlers per event. ```python from xitzin import Xitzin, Request import asyncio app = Xitzin() # Application state storage @app.on_startup async def startup(): # Initialize resources app.state.db = await create_database_connection() # Assuming create_database_connection exists app.state.cache = {} app.state.api_key = "secret-key" print("Application started") @app.on_shutdown async def shutdown(): # Clean up resources await app.state.db.close() # Assuming db object has a close method print("Application stopped") # Multiple startup/shutdown handlers are supported @app.on_startup async def load_config(): app.state.config = load_configuration() # Assuming load_configuration exists # Access state in handlers @app.gemini("/data") async def get_data(request: Request): # Access application state db = request.app.state.db result = await db.query("SELECT * FROM items") # Assuming db object has query method # Access request state (per-request storage) request.state.processed = True return f"# Data\n\n{len(result)} items found" # Async handlers are fully supported @app.gemini("/async-example") async def async_handler(request: Request): await asyncio.sleep(0.1) data = await fetch_data_async() # Assuming fetch_data_async exists return f"# Async Result\n\n{data}" if __name__ == "__main__": # Startup handlers run automatically app.run() # Shutdown handlers run on exit ``` -------------------------------- ### Gemtext MIME Type Example Source: https://github.com/alanbato/xitzin/blob/main/docs/explanation/gemtext-format.md Shows the standard MIME type for Gemtext, `text/gemini`, as it might appear in a Gemini client response header. Also includes a simple text/gemini response example. ```gemtext 20 text/gemini # Hello, World! ``` -------------------------------- ### CGI Script Support Configuration (Python) Source: https://context7.com/alanbato/xitzin/llms.txt This code demonstrates three methods for integrating CGI scripts with the Xitzin framework: mounting an entire directory of scripts, mounting with a custom configuration for fine-grained control over execution, and mounting a single specific script. It also lists environment variables passed to CGI scripts. ```Python from xitzin import Xitzin from xitzin.cgi import CGIHandler, CGIConfig, CGIScript app = Xitzin() # Method 1: Mount a CGI directory app.cgi( "/cgi-bin", script_dir="/srv/gemini/cgi-bin", timeout=30.0, app_state_keys=["db_path", "api_key"] ) # Method 2: Mount with custom configuration config = CGIConfig( timeout=60.0, max_header_size=8192, check_execute_permission=True, inherit_environment=True, app_state_keys=["database_url"] ) handler = CGIHandler("/srv/cgi-bin", config=config) app.mount("/cgi-bin", handler) # Method 3: Mount a single script app.mount("/calculator", CGIScript("/srv/scripts/calc.py", timeout=10)) # CGI scripts receive environment variables: # - GATEWAY_INTERFACE=CGI/1.1 # - SERVER_PROTOCOL=GEMINI # - GEMINI_URL=gemini://example.com/path?query # - QUERY_STRING=user+input # - TLS_CLIENT_HASH=certificate_fingerprint # - XITZIN_DATABASE_URL=value (from app.state.database_url) ``` -------------------------------- ### Define Gemini Routes and Input Handlers with Xitzin Source: https://github.com/alanbato/xitzin/blob/main/README.md Demonstrates how to set up a Xitzin application using decorators for routing Gemini requests and handling user input. It shows examples of basic route definition, path parameter extraction, and prompt-based input collection. This snippet requires the 'xitzin' library. ```python from xitzin import Xitzin, Request app = Xitzin() @app.gemini("/") def home(request: Request): return "# Welcome to my capsule!" @app.gemini("/user/{username}") def profile(request: Request, username: str): return f"# {username}'s Profile" @app.input("/search", prompt="Enter query:") def search(request: Request, query: str): return f"# Results for: {query}" if __name__ == "__main__": app.run() ``` -------------------------------- ### Create Basic Xitzin Application Source: https://github.com/alanbato/xitzin/blob/main/docs/tutorials/your-first-capsule.md Defines a simple Xitzin application with a root route ('/'). This Python code sets up the application instance and registers a handler that returns Gemtext content for the homepage. It includes instructions on how to run the application. ```python from xitzin import Xitzin, Request app = Xitzin(title="My Personal Capsule") @app.gemini("/") def home(request: Request): return """# Welcome to My Capsule Hello, Geminispace! This is my personal corner of the smolnet. ## Navigation => /about About Me => /projects My Projects => /links Cool Links """ if __name__ == "__main__": app.run() ``` -------------------------------- ### GET /user/{username} Source: https://github.com/alanbato/xitzin/blob/main/docs/explanation/request-lifecycle.md Retrieves the profile information for a specific user. If the user is not found, a NotFound exception is raised and translated into a GeminiResponse. ```APIDOC ## GET /user/{username} ### Description Retrieves the profile information for a specific user. If the user is not found, a NotFound exception is raised and translated into a GeminiResponse. ### Method GET ### Endpoint /user/{username} ### Parameters #### Path Parameters - **username** (string) - Required - The username of the user whose profile to retrieve. ### Request Example ```json { "example": "No request body for GET request" } ``` ### Response #### Success Response (200) - **name** (string) - The name of the user. #### Response Example ```json { "example": "# John Doe's Profile" } ``` #### Error Response (51) - **status** (integer) - The status code, 51 indicates resource not found. - **meta** (string) - A message indicating the user was not found. #### Error Response Example ```json { "example": "51 User unknown not found" } ``` ``` -------------------------------- ### Article Search and Browsing API Source: https://github.com/alanbato/xitzin/blob/main/docs/tutorials/handling-user-input.md A comprehensive example of a Xitzin application that allows users to search for articles, browse by category, and view individual articles. ```APIDOC ## GET / ### Description Provides the home page with links to search, browse, and view all articles. ### Method GET ### Endpoint / ### Response #### Success Response (200) - **string** - Markdown content for the home page. #### Response Example ```markdown # Article Search => /search Search Articles => /browse Browse by Category => /articles All Articles ``` ``` ```APIDOC ## POST /search ### Description Processes a user's search query and returns a list of matching articles. ### Method POST ### Endpoint /search ### Parameters #### Request Body - **query** (string) - Required - The search term entered by the user. ### Request Example ```json { "query": "Gemini" } ``` ### Response #### Success Response (200) - **string** - Markdown content listing the search results or indicating no results were found. #### Response Example ```markdown # Results for 'Gemini' => /article/1 Getting Started with Gemini ``` ``` ```APIDOC ## GET /browse ### Description Displays a list of available article categories for browsing. ### Method GET ### Endpoint /browse ### Response #### Success Response (200) - **string** - Markdown content listing the categories. #### Response Example ```markdown # Browse by Category => /category/tutorial Tutorial => /category/python Python => /category/security Security => / Home ``` ``` ```APIDOC ## GET /category/{category} ### Description Retrieves and displays articles belonging to a specific category. ### Method GET ### Endpoint /category/{category} ### Parameters #### Path Parameters - **category** (string) - Required - The category name to filter articles by. ### Response #### Success Response (200) - **string** - Markdown content listing articles within the specified category. #### Response Example ```markdown # Tutorial Articles => /article/1 Getting Started with Gemini => /article/3 Building a Capsule => /browse Back to Categories => / Home ``` ``` ```APIDOC ## GET /article/{article_id} ### Description Retrieves and displays the content of a specific article based on its ID. ### Method GET ### Endpoint /article/{article_id} ### Parameters #### Path Parameters - **article_id** (integer) - Required - The unique identifier of the article. ### Response #### Success Response (200) - **string** - Markdown content of the requested article. #### Response Example ```markdown # Getting Started with Gemini Category: tutorial [Article content would go here...] => /category/tutorial More Tutorial Articles => / Home ``` #### Not Found Response (404) - **string** - Markdown content indicating the article was not found. #### Not Found Response Example ```markdown # Article Not Found => / Home ``` ``` ```APIDOC ## GET /articles ### Description Displays a list of all available articles in the application. ### Method GET ### Endpoint /articles ### Response #### Success Response (200) - **string** - Markdown content listing all articles. #### Response Example ```markdown # All Articles => /article/1 Getting Started with Gemini => /article/2 Python Tips and Tricks => /article/3 Building a Capsule => /article/4 Gemtext Formatting => /article/5 Certificate Authentication => /article/6 Advanced Python Patterns => / Home ``` ``` -------------------------------- ### Xitzin Testing Utilities with TestClient Source: https://context7.com/alanbato/xitzin/llms.txt Shows how to test Xitzin applications using the `TestClient` and `test_app` utilities. It covers testing various route types including simple GET, path parameters, input flows, and authentication requirements like certificate checks. Demonstrates both basic route testing and testing with lifecycle events. ```python from xitzin import Xitzin, Request from xitzin.testing import TestClient, test_app from xitzin.auth import require_certificate app = Xitzin() @app.gemini("/") def home(request: Request): return "# Welcome" @app.gemini("/user/{username}") def profile(request: Request, username: str): return f"# {username}" @app.input("/search", prompt="Enter query:") def search(request: Request, query: str): return f"# Results: {query}" @app.gemini("/members") @require_certificate def members(request: Request): return "# Members Area" # Basic testing def test_routes(): client = TestClient(app) # Test simple route response = client.get("/") assert response.is_success assert response.status == 20 assert "Welcome" in response.body # Test path parameters response = client.get("/user/alice") assert response.is_success assert "alice" in response.body # Test input flow response = client.get("/search") assert response.is_input_required assert response.input_prompt == "Enter query:" # Provide input response = client.get_input("/search", "python") assert response.is_success assert "python" in response.body # Test certificate authentication response = client.get("/members") assert response.is_certificate_required assert response.status == 60 # With certificate auth_client = client.with_certificate("abc123...") response = auth_client.get("/members") assert response.is_success # Testing with lifecycle events @app.on_startup async def init(): app.state.db = "connected" def test_with_lifecycle(): with test_app(app) as client: # Startup has run, app.state.db is available response = client.get("/") assert response.is_success # Shutdown has run automatically ``` -------------------------------- ### Serve Individual Gemini Project Detail Page (Python) Source: https://github.com/alanbato/xitzin/blob/main/docs/tutorials/your-first-capsule.md This Python function handles requests for individual project detail pages. It takes a `project_id` from the URL, retrieves project data (assuming a `PROJECTS` dictionary), and returns a page displaying the project's name, description, and status. It includes error handling for non-existent projects. ```python ```python @app.gemini("/projects/{project_id}") def project_detail(request: Request, project_id: str): project = PROJECTS.get(project_id) if not project: return """# Project Not Found Sorry, that project doesn't exist. => /projects Back to Projects """ return f"""# {project['name']} {project['description']} Status: {project['status']} => /projects Back to Projects => / Back to Home """ ``` ``` -------------------------------- ### Loops in Templates (Jinja) Source: https://github.com/alanbato/xitzin/blob/main/docs/how-to/templates.md Shows how to iterate over a list or collection using Jinja's `{% for %}` loop. It also includes an example of checking if a collection is empty using `{% if not %}`. ```jinja ## Articles {% for article in articles %} {{ article.url | link(article.title) }} {% endfor %} {% if not articles %} No articles yet. {% endif %} ``` -------------------------------- ### Apply Middleware to CGI Requests Source: https://github.com/alanbato/xitzin/blob/main/docs/how-to/cgi-scripts.md Demonstrates how middleware can be applied to requests handled by CGI scripts. This example logs incoming requests and outgoing response statuses. ```python @app.middleware async def log_requests(request, call_next): print(f"Request: {request.path}") response = await call_next(request) print(f"Response: {response.status}") return response app.mount("/cgi-bin", CGIHandler("/srv/cgi-bin")) ```