batata_consul_client/lib.rs
1//! batata-consul-client - Rust client for HashiCorp Consul
2//!
3//! # Overview
4//!
5//! This library provides a Rust client for interacting with HashiCorp Consul,
6//! supporting service discovery, health checking, key-value store, sessions,
7//! ACL, and more.
8//!
9//! # Quick Start
10//!
11//! ```rust,no_run
12//! use batata_consul_client::{Client, Config};
13//!
14//! #[tokio::main]
15//! async fn main() -> batata_consul_client::Result<()> {
16//! // Create client with default configuration
17//! let client = Client::new(Config::default())?;
18//!
19//! // Use KV store
20//! let kv = client.kv();
21//! kv.put_string("my/key", "my-value", None).await?;
22//!
23//! let (pair, _meta) = kv.get("my/key", None).await?;
24//! if let Some(p) = pair {
25//! println!("Value: {:?}", p.value_string());
26//! }
27//!
28//! // Register a service
29//! use batata_consul_client::api::agent::{AgentServiceRegistration, AgentServiceCheck};
30//!
31//! let registration = AgentServiceRegistration::new("my-service")
32//! .with_id("my-service-1")
33//! .with_address("127.0.0.1")
34//! .with_port(8080)
35//! .with_check(AgentServiceCheck::http("http://127.0.0.1:8080/health", "10s"));
36//!
37//! client.agent().service_register(®istration).await?;
38//!
39//! // Query healthy services
40//! let (services, _meta) = client.health().service_healthy("my-service", None).await?;
41//! for service in services {
42//! println!("Service: {} at {}:{}",
43//! service.service.service,
44//! service.service.address,
45//! service.service.port
46//! );
47//! }
48//!
49//! Ok(())
50//! }
51//! ```
52//!
53//! # Features
54//!
55//! - **KV Store**: Get, put, delete keys with CAS support and locking
56//! - **Agent**: Register/deregister services, manage checks, TTL
57//! - **Catalog**: Query nodes and services across the cluster
58//! - **Health**: Health check queries with filtering
59//! - **Session**: Distributed locking and leader election
60//! - **ACL**: Token, policy, and role management
61
62pub mod api;
63pub mod client;
64pub mod config;
65pub mod error;
66pub mod types;
67
68pub use client::HttpClient;
69pub use config::{Config, ConfigBuilder, HttpBasicAuth, TlsConfig};
70pub use error::{ConsulError, Result};
71pub use types::*;
72
73use std::sync::Arc;
74
75use api::{ACL, Agent, Catalog, Health, KV, Session};
76
77/// Main Consul client
78///
79/// This is the primary interface for interacting with Consul.
80/// It provides access to all API endpoints through dedicated clients.
81pub struct Client {
82 http_client: Arc<HttpClient>,
83 kv: KV,
84 agent: Agent,
85 catalog: Catalog,
86 health: Health,
87 session: Session,
88 acl: ACL,
89}
90
91impl Client {
92 /// Create a new Consul client with the given configuration
93 pub fn new(config: Config) -> Result<Self> {
94 let http_client = Arc::new(HttpClient::new(config)?);
95
96 Ok(Self {
97 kv: KV::new(http_client.clone()),
98 agent: Agent::new(http_client.clone()),
99 catalog: Catalog::new(http_client.clone()),
100 health: Health::new(http_client.clone()),
101 session: Session::new(http_client.clone()),
102 acl: ACL::new(http_client.clone()),
103 http_client,
104 })
105 }
106
107 /// Create a new client with configuration from environment variables
108 pub fn from_env() -> Result<Self> {
109 let config = Config::from_env()?;
110 Self::new(config)
111 }
112
113 /// Create a new client builder
114 pub fn builder() -> ClientBuilder {
115 ClientBuilder::new()
116 }
117
118 /// Get the KV API client
119 pub fn kv(&self) -> &KV {
120 &self.kv
121 }
122
123 /// Get the Agent API client
124 pub fn agent(&self) -> &Agent {
125 &self.agent
126 }
127
128 /// Get the Catalog API client
129 pub fn catalog(&self) -> &Catalog {
130 &self.catalog
131 }
132
133 /// Get the Health API client
134 pub fn health(&self) -> &Health {
135 &self.health
136 }
137
138 /// Get the Session API client
139 pub fn session(&self) -> &Session {
140 &self.session
141 }
142
143 /// Get the ACL API client
144 pub fn acl(&self) -> &ACL {
145 &self.acl
146 }
147
148 /// Get the underlying HTTP client
149 pub fn http_client(&self) -> &HttpClient {
150 &self.http_client
151 }
152
153 /// Check if the Consul server is reachable
154 pub async fn ping(&self) -> Result<()> {
155 self.http_client.ping().await
156 }
157}
158
159/// Builder for creating a Consul client
160pub struct ClientBuilder {
161 config: Config,
162}
163
164impl ClientBuilder {
165 /// Create a new client builder
166 pub fn new() -> Self {
167 Self {
168 config: Config::default(),
169 }
170 }
171
172 /// Set the Consul server address
173 pub fn address(mut self, address: &str) -> Self {
174 self.config.address = address.to_string();
175 self
176 }
177
178 /// Set the HTTP scheme (http or https)
179 pub fn scheme(mut self, scheme: &str) -> Self {
180 self.config.scheme = scheme.to_string();
181 self
182 }
183
184 /// Set the datacenter
185 pub fn datacenter(mut self, dc: &str) -> Self {
186 self.config.datacenter = Some(dc.to_string());
187 self
188 }
189
190 /// Set the ACL token
191 pub fn token(mut self, token: &str) -> Self {
192 self.config.token = Some(token.to_string());
193 self
194 }
195
196 /// Set HTTP basic authentication
197 pub fn http_auth(mut self, username: &str, password: &str) -> Self {
198 self.config.http_auth = Some(HttpBasicAuth::new(username, password));
199 self
200 }
201
202 /// Set TLS configuration
203 pub fn tls_config(mut self, tls: TlsConfig) -> Self {
204 self.config.tls_config = Some(tls);
205 self
206 }
207
208 /// Set request timeout
209 pub fn timeout(mut self, timeout: std::time::Duration) -> Self {
210 self.config.timeout = timeout;
211 self
212 }
213
214 /// Set the namespace (Enterprise only)
215 pub fn namespace(mut self, ns: &str) -> Self {
216 self.config.namespace = Some(ns.to_string());
217 self
218 }
219
220 /// Set the partition (Enterprise only)
221 pub fn partition(mut self, partition: &str) -> Self {
222 self.config.partition = Some(partition.to_string());
223 self
224 }
225
226 /// Build the client
227 pub fn build(self) -> Result<Client> {
228 Client::new(self.config)
229 }
230}
231
232impl Default for ClientBuilder {
233 fn default() -> Self {
234 Self::new()
235 }
236}
237
238/// Prelude module for common imports
239pub mod prelude {
240 pub use crate::{
241 Client, ClientBuilder, Config, ConfigBuilder, ConsulError, QueryOptions, Result, TlsConfig,
242 WriteOptions,
243 api::{
244 acl::{ACLPolicy, ACLToken, ACLTokenPolicyLink},
245 agent::{AgentServiceCheck, AgentServiceRegistration},
246 catalog::{CatalogDeregistration, CatalogRegistration, CatalogServiceRegistration},
247 kv::KVPair,
248 session::{SessionBehavior, SessionRequest},
249 },
250 };
251}