# Getting Started This guide walks you through setting up EDRI from scratch and creating your first event-driven application. --- ## Quickstart The shortest possible EDRI application — copy this file, install, and run: Create `main.py`: ```python from datetime import datetime from edri import EDRI from edri.api.dataclass.api_event import api, ApiType from edri.dataclass.event import Event from edri.dataclass.response import Response, response from edri.abstract import ManagerBase, request from http import HTTPMethod @response class GreetingResponse(Response): message: str timestamp: str @api(url="/hello/{name}", method=HTTPMethod.GET, exclude={ApiType.HTML, ApiType.WS}) class Greeting(Event): name: str response: GreetingResponse class GreetingManager(ManagerBase): @request def greet(self, event: Greeting) -> None: event.response.message = f"Hello, {event.name}!" event.response.timestamp = datetime.now().isoformat() if __name__ == "__main__": edri = EDRI() edri.add_component(GreetingManager(edri.router_queue)) edri.start_api() edri.run() ``` Install **{{ VERSION }}** and run: ```bash pip install "edri[uvicorn]==" && python main.py ``` In another terminal: ```bash curl -H "Accept: application/json" http://localhost:8080/hello/World ``` Expected response: ```json {"data": {"message": "Hello, World!", "timestamp": "2025-06-04T12:00:00"}, "status": "OK"} ``` --- ## Installation ### Prerequisites * Python **3.12+** (3.12, 3.13, 3.14, and pre-release versions are tested in CI) * POSIX-compatible OS (Linux; macOS is experimental — never tested in CI) ### Install from PyPI Install the documented version (**{{ VERSION }}**) with the recommended ASGI server: ```bash python -m pip install "edri[uvicorn]==" ``` For the latest stable release, omit the version pin: ```bash python -m pip install "edri[uvicorn]" ``` Other supported ASGI servers: | Server | Install command | Feature | |---------------|--------------------------------------------|----------------------| | uvicorn | `python -m pip install "edri[uvicorn]"` | Recommended, fastest | | hypercorn | `python -m pip install "edri[hypercorn]"` | HTTP/3 support | | daphne | `python -m pip install "edri[daphne]"` | Twisted-based | Each of these pulls in `edri[api]`, the HTTP/WebSocket layer itself (jinja2, markdown, multipart). Plain `pip install edri` installs only the core -- Router, Managers, Workers, Switch, Scheduler and Store -- and importing anything under `edri.api` then raises an `ImportError` naming `edri[api]`. The `edri` command is installed with the optional `cli` extra, `edri[cli]`; see [Create a project](#create-a-project). To install with development tools (Sphinx, coverage, twine): ```bash python -m pip install "edri[dev]" ``` ### Check installed version ```bash python -c "from importlib.metadata import version; print(version('edri'))" ``` > The documented version is **{{ VERSION }}**. Use the version switcher in the sidebar to select docs matching your installed version. ### Install from source (authorized contributors) Source installation is available to authorized contributors. Access instructions are maintained internally by the project maintainers. --- ## Create a project The optional `cli` extra provides the `edri` command. `edri new` creates a project skeleton with one placeholder Manager: ```bash python -m pip install "edri[cli,uvicorn]==" edri new myapp cd myapp python -m pip install -r requirements.txt python run.py ``` In another terminal: ```bash curl -H "Accept: application/json" http://localhost:8080/ping ``` The generated layout: ```text myapp/ ├── run.py ├── requirements.txt ├── component/ │ └── example/ │ ├── __init__.py │ └── manager.py ├── event/ │ └── example/ │ ├── __init__.py │ ├── api/ │ │ ├── __init__.py │ │ └── ping.py │ └── core/ │ ├── __init__.py │ ├── internal.py │ └── scheduled.py ├── config/ │ ├── __init__.py │ └── setting.py └── utility/ └── __init__.py ``` * `event//api/` holds public `@api` events, one module per event with its response class; `__init__.py` re-exports the events. * `event//core/internal.py` holds events exchanged between Managers; `core/scheduled.py` holds events fired by the Scheduler. * `component//__init__.py` re-exports the Manager; its logic is in `manager.py`. `edri new NAME` refuses an existing non-empty directory. `--directory DIR` creates the project in `DIR` instead of `./NAME`. `--force` adds the files to an existing non-empty directory and never overwrites a file; if any file would be overwritten, nothing is written. ### Shell completion `edri completion SHELL` prints the completion script for `bash`, `zsh` or `fish`. Enable it once, for example in `~/.bashrc`: ```bash eval "$(edri completion bash)" ``` Use `zsh` in `~/.zshrc`, or `edri completion fish | source` in `~/.config/fish/config.fish`. Completion offers the subcommands, their options and paths for `--directory`. Installing the package does not enable it, because pip cannot place scripts where a shell looks for them. ## Minimal example: REST API Let's build a simple REST endpoint that returns a greeting. ### 1. Define the event and response Create `events/greeting.py`: ```python from http import HTTPMethod from edri.api.dataclass.api_event import api, ApiType from edri.dataclass.event import Event from edri.dataclass.response import Response, response @response class GreetingResponse(Response): message: str timestamp: str @api( url="/hello/{name}", method=HTTPMethod.GET, exclude={ApiType.HTML, ApiType.WS}, ) class Greeting(Event): name: str response: GreetingResponse ``` ### 2. Define the Manager Create `managers/greeting.py`: ```python from datetime import datetime from edri.abstract import ManagerBase, request from events.greeting import Greeting class GreetingManager(ManagerBase): @request def greet(self, event: Greeting) -> None: event.response.message = f"Hello, {event.name}!" event.response.timestamp = datetime.now().isoformat() ``` ### 3. Create the entry point Create `main.py`: ```python from edri import EDRI from managers.greeting import GreetingManager if __name__ == "__main__": edri = EDRI() edri.add_component(GreetingManager(edri.router_queue)) edri.start_api() edri.run() ``` ### 4. Run it ```bash python main.py ``` ### 5. Call it ```bash curl -H "Accept: application/json" http://localhost:8080/hello/World ``` Response: ```json { "data": { "message": "Hello, World!", "timestamp": "2025-06-04T12:00:00" }, "status": "OK" } ``` --- ## Understanding what happened ```mermaid sequenceDiagram participant C as Client (curl) participant L as Listener participant B as Broker participant R as Router participant M as GreetingManager C->>L: GET /hello/World (Accept: application/json) Note over L: parse request · match URL to Greeting
extract name="World" · create Greeting(name="World") L->>B: event (Broker Queue) Note over B: run middleware (if any) B->>R: event (Router Queue) Note over R: look up subscribers for Greeting R->>M: deliver to GreetingManager Note over M: greet() handler sets
response.message = "Hello, World!"
→ auto-sent on return M->>R: response Note over R: look up subscribers for the response R->>B: forward response Note over B: run response middleware (if any) B->>L: forward response Note over L: serialize to JSON L->>C: HTTP 200 ``` --- ## Next steps Now that you have a working EDRI application, explore: | Topic | Document | |------------------------------------|-----------------------------------------------| | Events in detail (lifecycle, types, inheritance) | {doc}`/event` | | API Events (input extraction, URL) | {doc}`/api_event` | | Validation with `inject(...)` | {doc}`/validation` | | Manager patterns | {doc}`/manager` | | Workers (threads/processes) | {doc}`/worker` | | Middleware (auth, logging) | {doc}`/middleware` | | HTML API (Jinja2 templates) | {doc}`/html` | | WebSocket API | {doc}`/websocket` | | File downloads | {doc}`/api_download` | | Response directives | {doc}`/response` | ### Concrete examples | Example | File | |------------------------------------------------|-------------------------------------------------------------| | REST CRUD with validation | {doc}`/examples/rest/crud` | | HTML form with Post/Redirect/Get | {doc}`/examples/html/form_post_redirect` | | CPU-bound WorkerProcess | {doc}`/examples/worker/cpu_bound` | | Streaming ZIP via SharedMemoryPipe | {doc}`/examples/worker/shared_memory_pipe` | | Periodic refresh via Scheduler + Store | {doc}`/examples/scheduler/periodic_refresh` | | WebSocket ticket pattern for async processing | {doc}`/examples/websocket/upload` |