# How Modly's PythonBridge Communicates with the FastAPI Backend

> Discover how Modly's PythonBridge connects your Electron app to a FastAPI backend. Learn how it translates IPC messages into REST API calls for seamless communication.

- Repository: [lightningpixel/modly](https://github.com/lightningpixel/modly)
- Tags: internals
- Published: 2026-08-15

---

**Modly's PythonBridge functions as a lightweight HTTP client within Electron's main process, translating IPC messages from the renderer into REST API calls to a local FastAPI server running at `http://127.0.0.1:8000`.**

The `lightningpixel/modly` repository implements a hybrid desktop architecture that combines Electron's frontend capabilities with Python's machine-learning ecosystem. The **PythonBridge** module enables the React-based UI to trigger model execution and workflow management by forwarding requests to a dedicated FastAPI backend, keeping the interface responsive while leveraging Python's computational power.

## Bootstrap and Configuration

When the Electron application initializes, the main entry point at [`electron/main/index.ts`](https://github.com/lightningpixel/modly/blob/main/electron/main/index.ts) imports the bridge module from [`electron/main/python-bridge.ts`](https://github.com/lightningpixel/modly/blob/main/electron/main/python-bridge.ts). This module defines a constant `API_BASE_URL` that points to the local FastAPI server, defaulting to `http://127.0.0.1:8000`. All subsequent HTTP requests use this base URL to communicate with the Python backend.

The bridge initializes automatically during the Electron main process startup, establishing the connection parameters before any renderer process requests occur.

## HTTP Request Wrapper Implementation

The `PythonBridge` class in [`electron/main/python-bridge.ts`](https://github.com/lightningpixel/modly/blob/main/electron/main/python-bridge.ts) provides thin wrapper functions—including `get`, `post`, and `delete`—built on top of the native **fetch** API. Each wrapper automatically prefixes the endpoint path with `API_BASE_URL`, injects JSON content headers, and serializes the request body.

```typescript
export const API_BASE_URL = 'http://127.0.0.1:8000';

export class PythonBridge {
  static async post<T>(endpoint: string, body: any): Promise<T> {
    const resp = await fetch(`${API_BASE_URL}${endpoint}`, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify(body),
    });
    if (!resp.ok) {
      throw new Error(`HTTP ${resp.status}`);
    }
    return (await resp.json()) as T;
  }

  // Convenience method used by IPC handlers
  static async runWorkflow(data: any) {
    return this.post<{ success: boolean; result: any }>(
      '/workflow/run',
      data
    );
  }
}

```

These static methods return typed promises, allowing the IPC layer to await Python-backed operations synchronously while maintaining type safety throughout the TypeScript codebase.

## IPC Integration Layer

The bridge exposes its functionality to the renderer process through **IPC channels** defined in [`electron/main/ipc-handlers.ts`](https://github.com/lightningpixel/modly/blob/main/electron/main/ipc-handlers.ts). This file registers handlers using `ipcMain.handle` that listen for specific channel names and forward payloads to the appropriate `PythonBridge` methods.

```typescript
import { ipcMain } from 'electron';
import { PythonBridge } from './python-bridge';

ipcMain.handle('python-bridge:run-workflow', async (_, payload) => {
  try {
    const result = await PythonBridge.runWorkflow(payload);
    return { ok: true, ...result };
  } catch (e) {
    return { ok: false, error: e.message };
  }
});

```

When a React component in the renderer process needs to execute a Python operation, it invokes the channel using `ipcRenderer.invoke`. The handler receives the message, calls the bridge's HTTP method, and returns the JSON response—or a structured error object—back to the UI.

## Triggering Calls from the Renderer

Renderer-side code typically abstracts the IPC calls through a dedicated API module. For example, triggering a workflow run involves invoking the specific channel registered in the main process handlers.

```typescript
// renderer/src/api.ts
import { ipcRenderer } from 'electron';

// Trigger a workflow run
export async function runWorkflow(payload: any) {
  const result = await ipcRenderer.invoke(
    'python-bridge:run-workflow',
    payload
  );
  return result; // { success: true, data: … } or error object
}

```

This pattern decouples the React components from Electron's IPC mechanics, allowing the frontend to treat Python-backed operations as standard async function calls.

## FastAPI Backend Endpoints

The FastAPI server resides in the `api/` directory and launches via [`api/main.py`](https://github.com/lightningpixel/modly/blob/main/api/main.py). It registers routers that expose the endpoints consumed by the PythonBridge:

- **[`api/routers/workflow_runs.py`](https://github.com/lightningpixel/modly/blob/main/api/routers/workflow_runs.py)**: Defines the `/workflow/run` endpoint that handles model loading and inference execution
- **[`api/routers/status.py`](https://github.com/lightningpixel/modly/blob/main/api/routers/status.py)**: Provides the `/status` endpoint for health checks and server state monitoring

These endpoints perform the heavy-lifting in Python—such as executing machine learning models and managing workflow state—and return JSON results that the bridge relays back to the Electron UI. The backend operates independently on `localhost:8000`, maintaining stateful connections to the Python ML libraries while the Electron front end remains stateless.

## Error Handling and Logging

The `PythonBridge` implements centralized error handling that catches network failures, HTTP errors, and server exceptions. When `fetch` requests fail or return non-OK status codes, the bridge converts these into consistent error objects and logs them via the shared utility in [`electron/main/logger.ts`](https://github.com/lightningpixel/modly/blob/main/electron/main/logger.ts).

This architecture ensures that the renderer process receives predictable error structures—containing `ok: false` and an error message property—allowing the UI to display user-friendly notifications without exposing internal stack traces or network details.

## Summary

- **Configuration**: [`electron/main/python-bridge.ts`](https://github.com/lightningpixel/modly/blob/main/electron/main/python-bridge.ts) defines `API_BASE_URL` pointing to `http://127.0.0.1:8000` and initializes when [`electron/main/index.ts`](https://github.com/lightningpixel/modly/blob/main/electron/main/index.ts) loads.
- **HTTP Client**: The `PythonBridge` class provides `get`, `post`, and `delete` wrappers around the native fetch API, serializing JSON and handling base URL prefixing automatically.
- **IPC Layer**: [`electron/main/ipc-handlers.ts`](https://github.com/lightningpixel/modly/blob/main/electron/main/ipc-handlers.ts) registers channels like `'python-bridge:run-workflow'` that bridge renderer invocations to HTTP calls.
- **Backend**: FastAPI endpoints in [`api/routers/workflow_runs.py`](https://github.com/lightningpixel/modly/blob/main/api/routers/workflow_runs.py) and [`api/routers/status.py`](https://github.com/lightningpixel/modly/blob/main/api/routers/status.py) handle the Python logic, returning JSON via [`api/main.py`](https://github.com/lightningpixel/modly/blob/main/api/main.py).
- **Reliability**: Errors are caught, logged via [`electron/main/logger.ts`](https://github.com/lightningpixel/modly/blob/main/electron/main/logger.ts), and returned as structured objects to the renderer for graceful UI degradation.

## Frequently Asked Questions

### What URL does Modly's PythonBridge use to connect to the FastAPI server?

By default, the bridge targets `http://127.0.0.1:8000` as defined by the `API_BASE_URL` constant in [`electron/main/python-bridge.ts`](https://github.com/lightningpixel/modly/blob/main/electron/main/python-bridge.ts). This localhost binding ensures that the Electron frontend communicates with the Python backend only on the local machine, minimizing network latency for model inference operations.

### How does the renderer process trigger Python model execution?

The renderer uses Electron's `ipcRenderer.invoke` method with the channel name `'python-bridge:run-workflow'`, passing the workflow payload as an argument. The `ipcMain.handle` listener in [`electron/main/ipc-handlers.ts`](https://github.com/lightningpixel/modly/blob/main/electron/main/ipc-handlers.ts) receives this message, forwards it to `PythonBridge.runWorkflow()`, and returns the FastAPI response to the React component.

### Which specific files define the FastAPI endpoints that the bridge calls?

The FastAPI application starts in [`api/main.py`](https://github.com/lightningpixel/modly/blob/main/api/main.py), which mounts routers including [`api/routers/workflow_runs.py`](https://github.com/lightningpixel/modly/blob/main/api/routers/workflow_runs.py) (defining the `/workflow/run` endpoint) and [`api/routers/status.py`](https://github.com/lightningpixel/modly/blob/main/api/routers/status.py) (defining status and health check routes). These files contain the Python logic for executing workflows and managing backend state.

### How does Modly handle communication failures between the bridge and FastAPI?

The PythonBridge wraps all fetch calls in try-catch blocks within the IPC handlers. When network errors occur or the FastAPI server returns error status codes, the catch block returns a structured object with `ok: false` and an error message property. This response format allows the renderer to detect failures and display appropriate user notifications while detailed logs are written via [`electron/main/logger.ts`](https://github.com/lightningpixel/modly/blob/main/electron/main/logger.ts).