How GeoLibre Builds Proxy Requests to the Python Sidecar at /sidecar
GeoLibre resolves the sidecar base URL at runtime using resolveSidecarBaseUrl() in packages/processing/src/sidecar-client.ts, choosing between a local development URL (http://127.0.0.1:8765) or a same-origin proxy path (/sidecar) based on the current protocol, port, and environment.
GeoLibre's browser-based interface needs to communicate with its Python sidecar for geoprocessing tasks—health checks, Whitebox tools, and vector/raster conversions. Rather than hard-coding host and port combinations, the frontend dynamically constructs request URLs. This approach lets the same codebase run in Vite development, Docker deployments, and the native Tauri desktop app without configuration changes.
How the Base URL Is Determined
The function resolveSidecarBaseUrl() in packages/processing/src/sidecar-client.ts implements a cascading decision tree to pick the correct sidecar endpoint.
// packages/processing/src/sidecar-client.ts
function resolveSidecarBaseUrl(): string {
const override = explicitSidecarUrl(); // VITE_SIDECAR_URL env var
if (override) return override;
// When running in a non‑browser context (e.g. during CI) use the local sidecar.
if (typeof window === "undefined" || !window.location) {
return LOCAL_SIDECAR_URL; // "http://127.0.0.1:8765"
}
const { protocol, hostname, port, origin } = window.location;
const isTauri = protocol === "tauri:" || hostname === "tauri.localhost";
const isViteDev = port === "5173";
// Production or Docker builds are served from an http(s) origin.
// In those cases the sidecar is reachable via a **same‑origin reverse proxy**
// that maps "/sidecar" to the real sidecar process, avoiding CORS.
if (!isTauri && !isViteDev && (protocol === "http:" || protocol === "https:")) {
return `${origin}/sidecar`;
}
// Fallback to the local dev sidecar.
return LOCAL_SIDECAR_URL;
}
The function evaluates three conditions in priority order:
- Explicit override — If
VITE_SIDECAR_URLis set, use that value directly. - Tauri desktop or Vite dev server — When
protocol === "tauri:"orport === "5173", connect toLOCAL_SIDECAR_URL(http://127.0.0.1:8765). - Docker or production HTTP(S) origin — Use
${origin}/sidecarto leverage same-origin reverse proxying, eliminating CORS requirements.
The result is cached in DEFAULT_SIDECAR_URL and used for all subsequent sidecar API calls.
How Requests Are Sent with sidecarFetch
Every sidecar operation flows through a thin wrapper that handles authentication token injection:
function sidecarFetch(input: string, init?: RequestInit): Promise<Response> {
if (!sidecarAuthToken) return fetch(input, init); // desktop injects token via nginx
const headers = new Headers(init?.headers);
headers.set("X-GeoLibre-Token", sidecarAuthToken);
return fetch(input, { ...init, headers });
}
- Browser/Docker builds:
sidecarAuthTokenisnull, so requests pass through unmodified. - Tauri desktop builds: The Tauri shell generates a token and injects it via nginx;
sidecarFetchadds theX-GeoLibre-Tokenheader.
A typical health check implementation demonstrates the pattern:
export async function checkSidecarHealth(): Promise<SidecarHealth> {
const res = await sidecarFetch(`${DEFAULT_SIDECAR_URL}/health`);
if (!res.ok) throw new Error("Sidecar health check failed");
return res.json();
}
All endpoints—/algorithms, /whitebox/*, /vector/*, /raster/*—follow this same construction pattern.
Server-Side Proxy Configuration
GeoLibre ensures /sidecar requests never trigger the SPA router:
// apps/geolibre-desktop/vite.config.ts (excerpt)
navigateFallbackDenylist: [/^\/sidecar\//, /^\/__geolibre_/, /\/[^/?]+\.[^/]+$/],
Two proxy layers handle the actual forwarding:
| Environment | Implementation | Behavior |
|---|---|---|
| Vite dev server | vite-proxy-guard.ts middleware |
Forwards /sidecar/* to the running FastAPI dev server or Docker sidecar container |
| Production/Docker | nginx reverse proxy | Maps /sidecar/* to 127.0.0.1:8765 with automatic token injection for desktop builds |
This architecture guarantees same-origin requests in production, avoiding CORS preflight overhead and complexity.
Complete Request Flow
- UI code imports from
@geolibre/processingand calls a sidecar function. resolveSidecarBaseUrl()evaluateswindow.locationto choose between local development URL or/sidecarproxy path.- The endpoint path (e.g.,
/whitebox/tools) is appended to the base URL. sidecarFetchexecutesfetch, adding the auth token only in Tauri desktop builds.- Vite middleware or nginx routes the request to the Python FastAPI sidecar.
Practical Code Examples
Health Check on Application Startup
import { checkSidecarHealth } from "@geolibre/processing";
async function ensureSidecar() {
try {
const { status } = await checkSidecarHealth();
console.log("Sidecar status:", status);
} catch (e) {
console.error("Sidecar unreachable:", e);
}
}
Executing a Whitebox Tool
import { runWhiteboxTool } from "@geolibre/processing";
async function hillshade(input: string, output: string) {
const jobId = await runWhiteboxTool("hillshade", {
inputs: [{ name: "dem", path: input }],
outputs: [{ name: "output", path: output }],
});
// Poll job status, retrieve results...
}
Both examples automatically use the correct base URL without caller awareness of the deployment context.
Key Source Files
| File | Purpose |
|---|---|
packages/processing/src/sidecar-client.ts |
URL resolution, auth token handling, and fetch wrapper for all sidecar communication |
apps/geolibre-desktop/vite.config.ts |
Vite configuration with SPA fallback denial for /sidecar routes |
apps/geolibre-desktop/vite-proxy-guard.ts |
Development middleware for proxying binary and sidecar requests |
backend/geolibre_server/pyproject.toml |
FastAPI sidecar package definition serving the actual endpoints |
Summary
resolveSidecarBaseUrl()dynamically selects betweenhttp://127.0.0.1:8765and${origin}/sidecarbased on environment detection.sidecarFetchprovides a unified request interface with optional token authentication for Tauri desktop builds.- Same-origin proxying via Vite middleware or nginx eliminates CORS handling in production deployments.
- The design supports three deployment modes—development, Docker, and Tauri desktop—from a single codebase.
Frequently Asked Questions
How does GeoLibre avoid CORS issues between browser and sidecar?
GeoLibre uses same-origin reverse proxying. In production and Docker builds, the browser sends requests to /sidecar on its own origin, which nginx forwards to 127.0.0.1:8765. The browser sees the sidecar as same-origin, so no CORS preflight or headers are required.
What environment variable overrides the sidecar URL?
Set VITE_SIDECAR_URL to force a specific base URL. This bypasses all automatic detection and is useful when running the Vite dev server on non-standard ports or proxying through external infrastructure.
How does authentication work for the sidecar in desktop builds?
The Tauri shell generates a unique token at startup and configures nginx to inject it as the X-GeoLibre-Token header. The sidecarFetch function adds this header when sidecarAuthToken is populated. Browser builds omit the token entirely.
Why is navigateFallbackDenylist needed in vite.config.ts?
Without this denylist, the Vite PWA plugin's SPA router would intercept /sidecar/health and similar paths, returning the single-page application shell instead of proxying to the Python backend. The regex /^\/sidecar\// ensures these requests reach the actual sidecar API.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →