Skip to content

SteveGilvarry/zm-api

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

131 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

πŸŽ₯ zm_api

A modern, fast, type-safe REST API for ZoneMinder

Rebuilding ZoneMinder's aging Perl/PHP API surface as a single, well-tested Rust service β€” with live streaming, fine-grained access control, and OpenAPI docs baked in.

Tests Coverage Rust Axum SeaORM License Status


✨ Why zm_api?

ZoneMinder is a rock-solid surveillance platform, but its API grew organically across Perl, PHP, and CGI over two decades. zm_api replaces that surface with one cohesive service:

  • πŸ¦€ One binary, one language β€” no PHP-FPM, no CGI, no Perl runtime to babysit.
  • ⚑ Fast & async β€” built on Axum + Tokio; streaming endpoints don't block the API.
  • πŸ”’ Secure by default β€” JWT auth, per-feature RBAC, and row-level monitor ACLs.
  • πŸ“– Self-documenting β€” every endpoint is in an auto-generated OpenAPI spec + Swagger UI.
  • πŸ§ͺ Actually tested β€” ~600 unit + integration tests, with a coverage gate in CI.
  • πŸ—„οΈ Drop-in schema β€” talks directly to an existing ZoneMinder MySQL/MariaDB database.

πŸš€ Features

πŸ“Ή Monitors & Events

Full CRUD for monitors, events, frames, zones, and event metadata β€” paginated, filterable, and searchable. Monitor state & alarm control. Per-monitor snapshots straight from the live stream.

🎬 Live Streaming

Three delivery paths from one API:

  • HLS β€” fragmented-MP4 playlists for any HTML5 <video> element.
  • MSE β€” low-latency fMP4 pushed over a WebSocket.
  • WebRTC β€” native peer connection with ICE/SDP signaling.

Plus recorded-event playback (video, byte-range seeking, thumbnails).

πŸ•ΉοΈ PTZ Control

Pan/tilt/zoom with native protocol drivers and a Perl-bridge fallback β€” ONVIF and vendor protocols, presets, and continuous control.

πŸ” Access Control

  • JWT access + refresh tokens.
  • Feature RBAC β€” ZoneMinder's 8 permission columns (Stream, Events, Control, Monitors, Groups, Devices, Snapshots, System) enforced on every route.
  • Row-level ACLs β€” Monitors_Permissions / Groups_Permissions resolved per request, so a user only ever sees the monitors they're granted (default-allow, fully backward compatible).

πŸ› οΈ Operations

Daemon supervision (zmc/zma) with a Unix-socket IPC shim for legacy zmdc.pl compatibility, storage & server management, configs, logs, montage layouts, and system control β€” all behind graceful SIGTERM/SIGINT shutdown.

🧱 Production hardening

TLS with optional ACME/Let's Encrypt, security headers, gzip/brotli compression (streaming routes excluded), request-body limits, and opt-in per-IP rate limiting.


πŸ—οΈ Architecture

A clean, one-way layered flow β€” handlers never touch the database directly.

flowchart TD
    Client["🌐 Client / Browser / ZM UI"] -->|HTTPS · JWT| Stack

    subgraph Stack["Middleware stack"]
        direction LR
        T[trace] --> C[compression] --> H[security headers] --> R[rate limit] --> O[CORS]
    end

    Stack --> Auth{"auth Β· RBAC Β· monitor ACL"}
    Auth -->|allowed| Handlers["πŸ“₯ Handlers β€” extraction & validation"]
    Auth -->|denied| Reject["401 / 403 / 404"]

    Handlers --> Services["βš™οΈ Services β€” business logic"]
    Services --> Repos["πŸ—ƒοΈ Repositories β€” SeaORM queries"]
    Repos --> DB[("πŸ›’οΈ MariaDB / MySQL<br/>ZoneMinder schema")]

    Handlers -.live & playback.-> Streaming["🎬 HLS · MSE · WebRTC"]
    Streaming -.-> Cameras[("πŸ“· ZoneMinder capture daemons")]
Loading
Layer Path Responsibility
Routes src/routes/ Endpoint wiring & middleware layering
Handlers src/handlers/ Request extraction, validation, response mapping
Services src/service/ Business logic
Repositories src/repo/ Database queries
Entities src/entity/ SeaORM models (generated from the ZM schema)
DTOs src/dto/ Request/response types (OpenAPI schemas)

🧰 Tech Stack

Language Rust (edition 2021)
Web framework Axum 0.8
Async runtime Tokio
ORM SeaORM 1.1 (MySQL/MariaDB)
API docs utoipa + Swagger UI
Auth JSON Web Tokens (jsonwebtoken)
Streaming webrtc, fMP4/MSE, HLS, retina (RTSP)
Media FFmpeg (ffmpeg-next) for H.264 β†’ JPEG

πŸš€ Quick Start

Prerequisites

  • Rust (current stable) β€” install via rustup
  • MariaDB / MySQL with a ZoneMinder schema
  • FFmpeg dev libraries β€” libavutil-dev libavcodec-dev libavformat-dev libavfilter-dev libavdevice-dev libswscale-dev libswresample-dev (Debian/Ubuntu) or brew install ffmpeg

Run it

# 1. Clone
git clone https://github.com/SteveGilvarry/zm-api.git
cd zm-api

# 2. Spin up a local test database (Docker / Apple Container)
./scripts/db-manager.sh start
./scripts/db-manager.sh mysql      # load the ZoneMinder schema

# 3. Build & run
cargo run                          # uses settings/base.toml
APP_PROFILE=prod cargo run         # production profile

The API comes up on the address/port from your active profile (see settings/).

Explore the API

Once running, open the interactive docs:

🧭 Swagger UI http://<host>:<port>/swagger-ui
πŸ“„ OpenAPI spec http://<host>:<port>/api-docs/openapi.json

βš™οΈ Configuration

Settings are layered, last one wins:

  1. settings/base.toml β€” defaults
  2. settings/{APP_PROFILE}.toml β€” dev Β· test Β· test-db Β· prod
  3. Environment variables β€” prefix APP_, nested keys use __
APP_PROFILE=prod
APP_DB__HOST=10.0.0.5            # overrides db.host
APP_CONFIG_DIR=/etc/zm_api       # alternate config directory

πŸ’‘ Local profiles like settings/dev.toml are gitignored β€” keep secrets out of version control.


πŸ§ͺ Testing

# Unit + non-DB tests
cargo test --all-features

# Full integration suite (needs the test database)
./scripts/db-manager.sh start && ./scripts/db-manager.sh mysql
APP_PROFILE=test-db cargo test --test '*' -- --include-ignored

# Coverage report
cargo llvm-cov --all-features --ignore-filename-regex '/(entity|migration)/' \
  -- --include-ignored

CI runs the suite on every push and gates line coverage β€” it can't regress below the floor. Currently ~59% and climbing, ~600 tests across unit + per-domain integration files.


πŸ“ Project Layout

src/
β”œβ”€β”€ routes/      Axum routers & middleware wiring
β”œβ”€β”€ handlers/    HTTP handlers
β”œβ”€β”€ service/     Business logic
β”œβ”€β”€ repo/        Database query layer
β”œβ”€β”€ entity/      SeaORM entities (generated from the ZM schema)
β”œβ”€β”€ dto/         Request/response DTOs
β”œβ”€β”€ streaming/   HLS / MSE / WebRTC pipelines
β”œβ”€β”€ ptz/         PTZ control drivers
β”œβ”€β”€ daemon/      ZoneMinder daemon supervision
β”œβ”€β”€ configure/   Config loading
└── error/       AppError + HTTP mapping
scripts/         DB management, JWT key generation, CI helpers
settings/        Layered TOML configuration
docs/            Deployment, TLS, PTZ & streaming design notes

🀝 Contributing

Before opening a PR, make sure the local quality gates pass:

cargo fmt --all -- --check
cargo clippy --all-targets --all-features -- -D warnings
cargo test --all-features

Work tests-first, keep changes focused, and treat src/entity/ as generated artifacts. See CLAUDE.md for the full development workflow and conventions.


πŸ“„ License

zm_api is dual-licensed:

  • πŸ†“ Open source β€” AGPL-3.0. Free to use, modify, and self-host. If you run a modified version as a network service, the AGPL requires you to publish your changes.
  • πŸ’Ό Commercial license. For embedding zm_api in a closed-source product, or running a modified version as a hosted service without the AGPL's source-sharing obligation, a commercial license is available. Contact the maintainer to enquire.

Contributions are accepted under a Contributor License Agreement so the project can be offered under both licenses β€” see CONTRIBUTING.md.

The db/*.sql schema files are from ZoneMinder and remain under its GPL-2.0 license.


Built with πŸ¦€ for the ZoneMinder community.

About

Rust Axum Based API for ZoneMinder

Resources

License

Contributing

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors