REST API Server

HTTP API for remote experiment tracking, enabling distributed training workflows and web dashboards.

Toyota Principle: Jidoka

Built-in quality through structured API responses and validation at every endpoint.

Quick Start

#![allow(unused)]
fn main() {
use entrenar::server::{TrackingServer, ServerConfig};

// Configure server
let config = ServerConfig::default()
    .with_host("0.0.0.0")
    .with_port(5000);

// Create and run server
let server = TrackingServer::new(config);
server.run().await?;
}

API Endpoints

Health Check

GET /health

# Response
{
  "status": "healthy",
  "version": "0.2.3",
  "uptime_secs": 3600
}

Experiments

# Create experiment
POST /api/v1/experiments
Content-Type: application/json

{
  "name": "gpt2-finetune",
  "config": {
    "model": "gpt2",
    "dataset": "wikitext"
  }
}

# Response
{
  "id": "exp-abc123",
  "name": "gpt2-finetune",
  "created_at": "2024-12-05T10:30:00Z"
}

# List experiments
GET /api/v1/experiments

# Get experiment
GET /api/v1/experiments/{id}

Runs

# Create run
POST /api/v1/runs
Content-Type: application/json

{
  "experiment_id": "exp-abc123"
}

# Response
{
  "id": "run-xyz789",
  "experiment_id": "exp-abc123",
  "status": "pending",
  "created_at": "2024-12-05T10:31:00Z"
}

# Start run
POST /api/v1/runs/{id}/start

# Complete run
POST /api/v1/runs/{id}/complete
Content-Type: application/json

{
  "status": "success"
}

# Get run
GET /api/v1/runs/{id}

# List runs for experiment
GET /api/v1/experiments/{id}/runs

Metrics

# Log metric
POST /api/v1/runs/{id}/metrics
Content-Type: application/json

{
  "key": "loss",
  "step": 100,
  "value": 0.5
}

# Log batch of metrics
POST /api/v1/runs/{id}/metrics/batch
Content-Type: application/json

{
  "metrics": [
    {"key": "loss", "step": 100, "value": 0.5},
    {"key": "accuracy", "step": 100, "value": 0.85}
  ]
}

# Get metrics
GET /api/v1/runs/{id}/metrics?key=loss

Parameters

# Log parameter
POST /api/v1/runs/{id}/params
Content-Type: application/json

{
  "key": "learning_rate",
  "value": 0.001
}

# Get parameters
GET /api/v1/runs/{id}/params

Artifacts

# Upload artifact
POST /api/v1/runs/{id}/artifacts
Content-Type: multipart/form-data

# Response
{
  "key": "model.safetensors",
  "hash": "sha256:abc123...",
  "size_bytes": 1048576
}

# Download artifact
GET /api/v1/runs/{id}/artifacts/{key}

Client SDK

#![allow(unused)]
fn main() {
use entrenar::server::client::TrackingClient;

let client = TrackingClient::new("http://localhost:5000");

// Create experiment
let exp = client.create_experiment("my-experiment", None).await?;

// Create and start run
let run = client.create_run(&exp.id).await?;
client.start_run(&run.id).await?;

// Log metrics
client.log_metric(&run.id, "loss", 0, 0.5).await?;

// Complete run
client.complete_run(&run.id, "success").await?;
}

Server Configuration

#![allow(unused)]
fn main() {
use entrenar::server::ServerConfig;

let config = ServerConfig::default()
    .with_host("0.0.0.0")
    .with_port(5000)
    .with_cors(true)
    .with_max_body_size(100 * 1024 * 1024)  // 100MB
    .with_request_timeout_secs(300);
}

Authentication

#![allow(unused)]
fn main() {
use entrenar::server::ServerConfig;

// API key authentication
let config = ServerConfig::default()
    .with_auth_type("api_key")
    .with_api_keys(vec!["key1", "key2"]);

// Request with API key
// Authorization: Bearer key1
}

Cargo Run Example

# Start server
cargo run --features server -- server

# With custom port
cargo run --features server -- server --port 8080

# With API key auth
cargo run --features server -- server --auth-type api_key --api-key mysecretkey

Docker Deployment

FROM rust:1.75 as builder
WORKDIR /app
COPY . .
RUN cargo build --release --features server

FROM debian:bookworm-slim
COPY --from=builder /app/target/release/entrenar /usr/local/bin/
EXPOSE 5000
CMD ["entrenar", "server", "--host", "0.0.0.0", "--port", "5000"]
docker build -t entrenar-server .
docker run -p 5000:5000 entrenar-server

Integration with Training

#![allow(unused)]
fn main() {
use entrenar::train::Trainer;
use entrenar::server::client::TrackingClient;

let client = TrackingClient::new("http://localhost:5000");
let exp = client.create_experiment("training-job", None).await?;
let run = client.create_run(&exp.id).await?;

let trainer = Trainer::new(config)
    .with_tracking_client(client, &run.id);

trainer.fit(&model, &dataset)?;
}

Error Responses

{
  "error": {
    "code": "NOT_FOUND",
    "message": "Run not found: run-xyz789"
  }
}
CodeHTTP StatusDescription
NOT_FOUND404Resource not found
INVALID_REQUEST400Malformed request
UNAUTHORIZED401Missing/invalid auth
INTERNAL_ERROR500Server error

Best Practices

  1. Use batch endpoints - Reduce HTTP overhead
  2. Enable CORS for web dashboards - Required for browser access
  3. Set appropriate timeouts - Long uploads need more time
  4. Use API key auth in production - Never expose unauthenticated
  5. Deploy behind reverse proxy - nginx/traefik for TLS

See Also