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"
}
}
| Code | HTTP Status | Description |
|---|---|---|
NOT_FOUND | 404 | Resource not found |
INVALID_REQUEST | 400 | Malformed request |
UNAUTHORIZED | 401 | Missing/invalid auth |
INTERNAL_ERROR | 500 | Server error |
Best Practices
- Use batch endpoints - Reduce HTTP overhead
- Enable CORS for web dashboards - Required for browser access
- Set appropriate timeouts - Long uploads need more time
- Use API key auth in production - Never expose unauthenticated
- Deploy behind reverse proxy - nginx/traefik for TLS