2 releases

Uses new Rust 2024

new 0.0.2 Dec 20, 2025
0.0.1 Dec 20, 2025

#1 in #consul

Apache-2.0

120KB
2.5K SLoC

batata-consul-client

A Rust client library for HashiCorp Consul, supporting service discovery, health checking, key-value store, sessions, ACL, and more.

Features

  • KV Store: Get, put, delete keys with CAS support and distributed locking
  • Agent: Register/deregister services, manage health checks, TTL updates
  • Catalog: Query nodes and services across the cluster
  • Health: Health check queries with status filtering
  • Session: Distributed locking and leader election
  • ACL: Token, policy, and role management

Installation

Add to your Cargo.toml:

[dependencies]
batata-consul-client = "0.0.1"

Quick Start

use batata_consul_client::{Client, Config};

#[tokio::main]
async fn main() -> batata_consul_client::Result<()> {
    // Create client with default configuration (localhost:8500)
    let client = Client::new(Config::default())?;

    // Use KV store
    let kv = client.kv();
    kv.put_string("my/key", "my-value", None).await?;

    let (pair, _meta) = kv.get("my/key", None).await?;
    if let Some(p) = pair {
        println!("Value: {:?}", p.value_string());
    }

    Ok(())
}

Configuration

Default Configuration

let client = Client::new(Config::default())?;

From Environment Variables

let client = Client::from_env()?;

Supported environment variables:

Variable Description
CONSUL_HTTP_ADDR Consul server address (e.g., http://127.0.0.1:8500)
CONSUL_HTTP_TOKEN ACL token
CONSUL_HTTP_AUTH HTTP basic auth (username:password)
CONSUL_HTTP_SSL Enable HTTPS (true or 1)
CONSUL_HTTP_SSL_VERIFY Verify TLS certificates (false or 0 to skip)
CONSUL_CACERT CA certificate path
CONSUL_CLIENT_CERT Client certificate path
CONSUL_CLIENT_KEY Client key path
CONSUL_NAMESPACE Namespace (Enterprise only)
CONSUL_PARTITION Partition (Enterprise only)

Builder Pattern

use std::time::Duration;

let client = Client::builder()
    .address("consul.example.com:8500")
    .scheme("https")
    .token("my-acl-token")
    .datacenter("dc1")
    .timeout(Duration::from_secs(60))
    .build()?;

API Examples

Service Registration

use batata_consul_client::api::agent::{AgentServiceRegistration, AgentServiceCheck};

let registration = AgentServiceRegistration::new("my-service")
    .with_id("my-service-1")
    .with_address("127.0.0.1")
    .with_port(8080)
    .with_tags(vec!["api", "v1"])
    .with_check(AgentServiceCheck::http("http://127.0.0.1:8080/health", "10s"));

client.agent().service_register(&registration).await?;

Service Discovery

// Get healthy instances of a service
let (services, _meta) = client.health().service_healthy("my-service", None).await?;

for service in services {
    println!("{}:{}", service.service.address, service.service.port);
}

KV Store with CAS

let kv = client.kv();

// Get current value
let (pair, _meta) = kv.get("config/key", None).await?;

if let Some(mut p) = pair {
    // Update with CAS (Check-And-Set)
    p.set_value_string("new-value");
    let (success, _) = kv.cas(&p, None).await?;
    println!("CAS update success: {}", success);
}

Blocking Queries

use std::time::Duration;
use batata_consul_client::QueryOptions;

let opts = QueryOptions::new()
    .with_wait(last_index, Duration::from_secs(30));

let (services, meta) = client.health().service("my-service", None, Some(opts)).await?;
// meta.last_index can be used for the next blocking query

Session and Locking

use batata_consul_client::api::session::{SessionRequest, SessionBehavior};

// Create a session
let session_req = SessionRequest::new()
    .with_name("my-lock")
    .with_ttl("30s")
    .with_behavior(SessionBehavior::Release);

let (session_id, _) = client.session().create(&session_req, None).await?;

// Acquire a lock
let (acquired, _) = client.kv().acquire("locks/my-resource", &session_id, None).await?;

if acquired {
    // Do work while holding the lock

    // Release the lock
    client.kv().release("locks/my-resource", &session_id, None).await?;
}

// Destroy the session
client.session().destroy(&session_id, None).await?;

Running Examples

Make sure you have a Consul server running locally:

# Start Consul in dev mode
consul agent -dev

# Run examples
cargo run --example kv_example
cargo run --example service_discovery
cargo run --example health_check

License

Apache-2.0

Dependencies

~14–32MB
~333K SLoC