How the Optional Python FastAPI Sidecar Integrates for Raster and Vector Processing in GeoLibre
GeoLibre's optional Python FastAPI sidecar provides a local HTTP server that offloads heavy geoprocessing tasks to Python's raster and vector libraries, falling back to browser-based engines when unavailable.
GeoLibre is designed as a lightweight desktop UI that runs primarily in the browser, but geographic information systems often demand computational power beyond what JavaScript can efficiently provide. The project solves this through an optional Python FastAPI sidecar living in backend/geolibre_server/, which exposes REST endpoints for raster and vector operations. This architecture lets the desktop application delegate to Python's rich geospatial ecosystem—including rasterio, contourpy, GeoPandas, Shapely, and NumPy—while maintaining seamless operation when the sidecar is absent.
Sidecar Lifecycle and Availability Detection
The FastAPI sidecar follows an on-demand startup pattern integrated with GeoLibre's Tauri shell.
Startup Mechanism
The desktop application launches the sidecar using uv for reproducible, frozen environments:
uv run --frozen --project backend/geolibre_server
The server binds to 127.0.0.1 by default. For browser builds, Tauri reverse-proxies requests to /sidecar, making the sidecar appear as a same-origin endpoint.
Runtime Capability Advertisement
Before presenting processing options, the UI queries status endpoints that gracefully handle missing dependencies:
GET /vector/status— Returns{"available": true}if GeoPandas imports successfullyGET /raster/status— Returns{"available": true}if rasterio and contourpy import successfully
Both endpoints catch ImportError exceptions and return friendly JSON failures rather than crashing. This allows the React UI to automatically enable or disable the "Run" button based on actual capability.
Implementation details: backend/geolibre_server/geolibre_server/app/vector.py (lines 61–74) and backend/geolibre_server/geolibre_server/app/raster.py (lines 14–28).
Vector Processing Flow
The vector pipeline handles GeoJSON transformations through a clean separation between HTTP transport and computational logic.
Request Structure
The VectorToolRequest Pydantic model defines the contract:
class VectorToolRequest(BaseModel):
tool_id: str
geojson: Optional[Dict] = None
parameters: Dict = {}
Source: backend/geolibre_server/geolibre_server/app/vector.py, lines 44–48.
Execution Path
The POST /vector/run endpoint in vector.py (lines 77–107) follows this sequence:
- Unmarshals the request into
VectorToolRequest - Verifies GeoPandas availability via
vector_ops.geopandas_import_error() - Invokes
geolibre_server.vector_ops.run_vector_tool()—a framework-free module containing the actual algorithms - Returns
{"geojson": <result>, "messages": [...]}
The endpoint uses a synchronous function signature, causing FastAPI to run it in a thread pool. This keeps the event loop responsive for status polling while CPU-bound geometry operations execute.
Cross-Platform Consistency
The same vector_ops.py module serves dual purposes. The Vite plugin vite-plugins/copy-vector-ops.ts bundles this file into web builds, enabling a Pyodide fallback that reproduces identical results in browsers without the sidecar. As documented in docs/architecture.md (around line 77), this ensures behavioral parity between desktop and web deployments.
Vector Write-Back Security
Vector operations that modify files undergo strict validation in _validate_write_path (lines 17–53 of vector.py):
- File extension whitelist
- Directory existence and writability
- Conversion root allowlist via
GEOLIBRE_CONVERSION_ROOTS
This prevents path traversal attacks and restricts sidecar file system access to explicitly whitelisted locations.
Raster Processing Flow
Raster operations follow an asynchronous job model suited to long-running GDAL processes.
Request Structure
The RasterToolRequest requires explicit paths:
class RasterToolRequest(BaseModel):
tool_id: str
input_path: str
output_path: str
parameters: Optional[Dict] = None
Source: backend/geolibre_server/geolibre_server/app/raster.py, lines 46–50.
Execution and Background Jobs
The POST /raster/run endpoint in raster.py (lines 38–82):
- Validates paths against
_is_within_roots()fromconversion.py - Calls
_start_job()to queue work in the shared conversion job store - Launches an embedded Python script (hillshade, slope, reproject, etc.) that executes rasterio/NumPy code
- Parses progress from special marker strings in subprocess output
This design separates job management from processing logic, allowing the UI to poll for completion without holding HTTP connections open.
Status Polling and Results
Raster jobs reuse the conversion job API:
GET /conversion/jobs/{id}— Returns current status, progress percentage, and console output- Upon completion:
{"status": "completed", "output_path": "...", "messages": [...]}
The raster endpoint thus integrates with GeoLibre's existing conversion infrastructure rather than inventing parallel machinery.
Security Architecture: The Conversion Allowlist
Both vector and raster pipelines share a unified security boundary through GEOLIBRE_CONVERSION_ROOTS.
| Operation | Validation Function | Location |
|---|---|---|
| Vector file writes | _validate_write_path |
vector.py lines 17–53 |
| Raster input/output | _validate_paths |
Imported from conversion.py |
These helpers guarantee that any file path the sidecar touches resides under an explicitly configured directory tree. This mitigates arbitrary file system access even if request payloads are malformed or malicious.
Desktop UI Integration
The React frontend coordinates sidecar availability through its Zustand store:
// Check sidecar availability on startup
async function checkSidecar() {
const [vec, ras] = await Promise.all([
fetch('http://127.0.0.1:8765/vector/status').then(r => r.json()),
fetch('http://127.0.0.1:8765/raster/status').then(r => r.json()),
]);
console.log('Vector sidecar', vec.available);
console.log('Raster sidecar', ras.available);
}
When both endpoints return available: true, the UI enables a "Run locally (WASM) → Sidecar" toggle. This lets users choose between:
- Client-side engines (Turf.js or Pyodide) for privacy and offline operation
- Python sidecar for large files, native GDAL formats, or algorithms unavailable in JavaScript
If the sidecar is unavailable—missing GeoPandas, for instance—the UI automatically falls back to browser-based processing without user intervention.
Practical Usage Examples
Calling the Vector Endpoint
import requests
payload = {
"tool_id": "buffer",
"geojson": {
"type": "FeatureCollection",
"features": [...]
},
"parameters": {"distance": 1000, "units": "meters"}
}
resp = requests.post(
'http://127.0.0.1:8765/vector/run',
json=payload
)
result = resp.json()
print(result['geojson'])
Running a Raster Hillshade Job
import requests
import time
# Start job
run_payload = {
"tool_id": "hillshade",
"input_path": "/data/dem.tif",
"output_path": "/output/hillshade.tif",
"parameters": {"azimuth": 315, "altitude": 45}
}
resp = requests.post(
'http://127.0.0.1:8765/raster/run',
json=run_payload
)
job_id = resp.json()['job_id']
# Poll for completion
while True:
status = requests.get(
f'http://127.0.0.1:8765/conversion/jobs/{job_id}'
).json()
if status['status'] == 'completed':
print('Result file:', status['output_path'])
break
time.sleep(0.5)
Key Source Files
| Component | Path | Purpose |
|---|---|---|
| Sidecar entry point | backend/geolibre_server/geolibre_server/app/main.py |
FastAPI application factory, route registration |
| Vector HTTP API | backend/geolibre_server/geolibre_server/app/vector.py |
/vector/status, /vector/run endpoints |
| Shared vector algorithms | backend/geolibre_server/geolibre_server/vector_ops.py |
Framework-free processing logic, Pyodide-compatible |
| Raster HTTP API | backend/geolibre_server/geolibre_server/app/raster.py |
/raster/status, /raster/run endpoints |
| Job management & security | backend/geolibre_server/geolibre_server/app/conversion.py |
_is_within_roots, _start_job, polling infrastructure |
| Runtime detection | backend/geolibre_server/geolibre_server/app/runtime.py |
Environment bootstrap, import error handling |
| Architecture documentation | docs/architecture.md |
Pyodide bundling strategy, design rationale |
Summary
- On-demand startup: The Tauri shell launches the FastAPI sidecar via
uv runwhen processing demands exceed browser capabilities - Graceful degradation: Status endpoints (
/vector/status,/raster/status) advertise availability; missing dependencies never crash the server - Unified security model:
GEOLIBRE_CONVERSION_ROOTSrestricts all file operations to whitelisted directories - Framework-free algorithms:
vector_ops.pyruns identically in the sidecar and Pyodide, ensuring consistent results across deployment targets - Async job pattern: Raster operations use background jobs with polling, while vector operations leverage FastAPI's thread pool for synchronous CPU work
Frequently Asked Questions
What happens if GeoPandas or rasterio is not installed?
The sidecar starts successfully but returns {"available": false} from the respective status endpoint. The UI detects this and disables the sidecar toggle, falling back to Turf.js for vectors or disabling raster tools entirely. No errors propagate to the user.
Can I use the sidecar with the web/browser build of GeoLibre?
Yes. When building for web, Tauri reverse-proxies the sidecar at /sidecar so the same origin policy is satisfied. Alternatively, you can deploy the FastAPI server independently and configure the UI to point at it—though this requires handling CORS and authentication yourself.
Why does raster processing use background jobs while vector processing does not?
Raster operations typically invoke GDAL through rasterio, which may run for minutes on large datasets. The job model prevents HTTP timeouts and allows progress tracking. Vector operations are usually faster (geometry buffering, intersection, etc.), so FastAPI's default thread pool provides sufficient concurrency without the complexity of job state management.
Is the sidecar required for GeoLibre to function?
No. The application is designed to work entirely in the browser using JavaScript libraries (Turf.js) and WebAssembly (Pyodide). The Python FastAPI sidecar is strictly an optional accelerator for heavy workloads, large files, and formats only readable by GDAL.
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 →