Guide

REST and gRPC API

Ze exposes a programmatic API over REST (HTTP/JSON) and gRPC. Both transports share one engine -- they produce identical command output and support the same commands.

Quick Start

Enable REST in your config:

environment {
    api-server {
        rest {
            enabled true;
            server { ip 127.0.0.1; port 8081; }
        }
    }
}

REST is plaintext HTTP and only starts on loopback addresses. To expose REST remotely, keep Ze bound to 127.0.0.1 or ::1 and terminate TLS in a trusted local proxy.

Or via environment variable:

ze.api-server.rest.enabled=true
ze.api-server.rest.listen=127.0.0.1:8081

Query the API:

curl http://localhost:8081/api/v1/commands
curl -X POST http://localhost:8081/api/v1/execute \
    -H "Content-Type: application/json" \
    -d '{"command":"bgp summary"}'

Open interactive docs: http://localhost:8081/api/v1/docs

Authentication

Three modes, in order of precedence:

Mode How to enable How clients authenticate
Per-user (recommended) Run ze init to create the zefs user database Authorization: Bearer username:password
Single token Set ze.api-server.token=<secret> or YANG api-server { token "secret"; } Authorization: Bearer <secret>
Leave both unset

Per-user mode uses the same user list as SSH and the web UI. Each request authenticates as a specific user, and the engine enforces per-user authorization via the existing dispatcher.

On startup, ze prints the active auth mode:

API auth mode: per-user (1 users from zefs)

If neither per-user nor token is configured, ze warns:

warning: API auth mode: NONE (no users, no token) -- set ze.api-server.token or initialize zefs

In no-auth mode the built-in api identity is read-only. Command reads work, but write commands, REST config sessions, and gRPC config sessions return 403.

REST Endpoints

Command execution

Method Path Description
GET /api/v1/commands List all commands with metadata
GET /api/v1/commands/{path} Describe one command (e.g., /bgp/summary)
POST /api/v1/execute Execute any command
GET /api/v1/execute/stream?command=... Stream a registered streaming command, for example monitor event, as Server-Sent Events. It uses the same handler registry, authorization, and accounting path as SSH monitor commands.
GET /api/v1/complete?partial=... Tab completion (future)

POST /api/v1/execute body:

{
  "command": "show bgp rib routes",
  "params": {"family": "ipv4/unicast"}
}

Response:

{
  "status": "done",
  "data": { ... }
}

Convenience routes

These map to the generic Execute endpoint internally. The data returned is identical to calling execute directly.

Method Path Maps to
GET /api/v1/peers bgp summary
GET /api/v1/peers/{name} peer {name} detail
DELETE /api/v1/peers/{name} request peer {name} teardown
POST /api/v1/peers/{name}/refresh request peer {name} refresh
GET /api/v1/rib/{family} show bgp rib family {family}
GET /api/v1/rib/{family}/best show bgp rib best family {family}
GET /api/v1/system/version show version
GET /api/v1/system/status show status
POST /api/v1/system/reload request reload

Config editing

Method Path Description
GET /api/v1/config/running Current running config
POST /api/v1/config/sessions Start a candidate session, returns {"session-id": "..."}
PUT /api/v1/config/sessions/{id} Set a value: {"path":"bgp.router-id","value":"10.0.0.1"}
DELETE /api/v1/config/sessions/{id}/{path} Delete a config path
GET /api/v1/config/sessions/{id}/diff Preview pending changes
POST /api/v1/config/sessions/{id}/commit Apply changes
DELETE /api/v1/config/sessions/{id} Discard session

Sessions are owned by the authenticated user. Another user cannot access a session they did not create (returns 403 Forbidden). Idle sessions expire after 30 minutes.

No-auth REST/gRPC callers cannot create config sessions. Configure a token or per-user authentication for API-driven config changes.

Documentation

Path Description
/api/v1/openapi.json OpenAPI 3.1 specification (auto-generated from YANG)
/api/v1/docs Interactive Swagger UI (assets vendored, offline-capable)

The OpenAPI spec is generated lazily on first request so it captures all plugin commands registered during startup. Documentation routes use the same Bearer authentication policy as the API when auth is configured.

gRPC Services

Proto definitions: api/proto/ze.proto, package ze.api.v1.

Enable gRPC:

environment {
    api-server {
        grpc {
            enabled true;
            server { ip 127.0.0.1; port 50051; }
        }
    }
}

Loopback gRPC can run plaintext for local tooling. Non-loopback gRPC listeners must be authenticated and must configure TLS with both tls-cert and tls-key.

ZeService

Generic command execution and discovery.

RPC Type Purpose
Execute unary Run a command, get result
Stream server-stream Stream a registered streaming command, for example monitor event, over a gRPC server stream. It uses the same handler registry, authorization, and accounting path as SSH monitor commands.
ListCommands unary Enumerate all commands
DescribeCommand unary Metadata for one command
Complete unary Tab completion (future)

CommandResponse.data is JSON-encoded bytes for identical content with REST.

ZeConfigService

Typed config session management (same semantics as REST config sessions).

RPC Purpose
GetRunningConfig Current running config
EnterSession Start a candidate session
SetConfig / DeleteConfig Modify the candidate
DiffSession Preview pending changes
CommitSession Apply changes
DiscardSession Throw away changes

gRPC authentication

Pass the same Bearer username:password or Bearer <token> as REST, via the authorization metadata key:

metadata = [('authorization', 'Bearer alice:password123')]
stub.Execute(CommandRequest(command='bgp summary'), metadata=metadata)

gRPC reflection

Reflection is enabled by default. Discover the schema with grpcurl on a plaintext loopback listener:

grpcurl -plaintext localhost:50051 list
grpcurl -plaintext localhost:50051 describe ze.api.v1.ZeService
grpcurl -plaintext -d '{"command":"bgp summary"}' \
    -H "authorization: Bearer alice:password123" \
    localhost:50051 ze.api.v1.ZeService/Execute

TLS

Configure TLS via YANG before binding gRPC outside loopback:

environment {
    api-server {
        grpc {
            enabled true;
            tls-cert "/etc/ze/server.pem";
            tls-key "/etc/ze/server.key";
        }
    }
}

Both fields must be set together. Minimum TLS version is 1.2. Startup fails if an authenticated non-loopback gRPC listener is configured without TLS.

CORS

For browser-based clients, set an allowed origin:

environment {
    api-server {
        rest {
            enabled true;
            cors-origin "https://dashboard.example.com";
        }
    }
}

Preflight OPTIONS requests are handled automatically.

Environment Variables

Variable Default Description
ze.api-server.rest.enabled false Enable REST API server
ze.api-server.rest.listen 0.0.0.0:8081 REST listen address schema default; only loopback is accepted at server startup, so set this to ::1:<port> when enabling REST. 127.0.0.1:8081
ze.api-server.grpc.enabled false Enable gRPC API server
ze.api-server.grpc.listen 0.0.0.0:50051 gRPC listen address; non-loopback requires authentication and TLS
ze.api-server.token (empty) Single bearer token (if per-user auth not wanted)

Precedence: env > YANG config. Values set in env override YANG.

Input Validation

Both transports validate command input against shell injection:

These checks prevent command tokenizer confusion when user input flows into dispatcher command strings.

Differences Between Transports

The transports are functionally equivalent. Pick based on client needs:

Feature REST gRPC
Discovery OpenAPI 3.1 + Swagger UI gRPC reflection + grpcurl
Streaming Internal SSE hook, production hub returns streaming not supported Internal server-stream RPC, production hub returns streaming not supported
Browser support Needs grpc-web proxy
Tooling curl, any HTTP client grpcurl, any gRPC client
Overhead JSON Protobuf (smaller wire format)
TLS via reverse proxy today built-in