hashicorp/consul
api — Go HTTP client
The github.com/hashicorp/consul/api module is the canonical Go client for Consul. The CLI uses it; external Go applications use it; SDKs in other languages model their surfaces after it.
Module shape
api/ is a separate Go module with its own go.mod. The root module replaces it to ./api so contributions stay in lockstep with the agent's HTTP behavior.
api/
├── api.go # Client/Config; HTTP transport
├── kv.go, kv_test.go
├── catalog.go, health.go, agent.go
├── acl.go, namespace.go, partition.go
├── connect.go, connect_ca.go, connect_intention.go
├── config_entry*.go # Per-kind config entry helpers (~10 files)
├── operator_*.go # Autopilot, raft, license, segment, audit, usage
├── peering.go
├── prepared_query.go
├── snapshot.go
├── session.go, lock.go, semaphore.go
├── txn.go # Transaction API
├── api_test.go, *_test.go
├── mock_api_test.go
├── watch/ # Long-poll watch helpers
└── ...Each *.go file groups operations on one resource (catalog, KV, ACL, intentions, ...).
Key abstractions
| Type | File | Purpose |
|---|---|---|
Client |
api/api.go |
The connection holder — wraps http.Client and Config |
Config |
api/api.go |
Address, scheme, datacenter, token, TLS, retry policy |
QueryOptions / WriteOptions |
api/api.go |
Per-call modifiers: token, datacenter, namespace, partition, blocking-query parameters |
QueryMeta / WriteMeta |
api/api.go |
Returned metadata: LastIndex, LastContact, KnownLeader, request duration |
KV, Health, Catalog, ... |
per-file struct | Sub-clients accessed via client.KV(), client.Health(), ... |
Lock, Semaphore |
api/lock.go, api/semaphore.go |
Higher-level primitives built on KV+Sessions |
Watch |
api/watch/watch.go |
Type-safe blocking-query helper for app-level watchers |
Usage shape
client, err := api.NewClient(api.DefaultConfig())
if err != nil { panic(err) }
kv := client.KV()
pair, meta, err := kv.Get("foo", &api.QueryOptions{WaitIndex: lastIdx, WaitTime: 30*time.Second})
if err != nil { ... }
lastIdx = meta.LastIndex
fmt.Println(pair.Key, string(pair.Value))The "blocking query" pattern (WaitIndex + WaitTime) is the standard way client apps stay in sync with config changes; the server holds the request open until the data changes or the wait expires.
Auth
Config.Token accepts an ACL token; TokenFile reads from disk; environment variables CONSUL_HTTP_TOKEN / CONSUL_HTTP_TOKEN_FILE are respected by DefaultConfig. mTLS settings live under Config.TLSConfig.
Watches
api/watch/ is a small DSL for declarative watchers:
plan, err := watch.Parse(map[string]any{
"type": "service",
"service": "web",
})
plan.Handler = func(idx uint64, raw any) {
services := raw.([]*api.ServiceEntry)
fmt.Println(idx, len(services))
}
plan.Run("127.0.0.1:8500")Watch types: key, keyprefix, services, nodes, service, checks, event. Each translates into a blocking-query loop with the relevant API endpoint.
How the CLI uses it
Every CLI subcommand under command/ constructs an api.Client via command/flags/HTTPFlags.APIClient() and calls into the api package. Adding behavior in api/ automatically benefits the CLI and any external user.
Testing
api/api_test.go and friends spin up a testutil.TestServer (from the sdk module) and exercise the client end-to-end. api/mock_api_test.go mocks the HTTP endpoint for tighter unit tests.
Versioning
The module follows Consul's release cadence. Backwards-compatibility is taken seriously; deprecated fields stay for several releases. Public API changes go through review explicitly because external consumers are pinned.
Entry points for modification
- Add a new endpoint method: pick the right file (e.g.,
api/peering.gofor peering), add a method on the sub-client struct, mirror the JSON encoding the agent expects. - Add a config option: extend
api.Config, plumb it throughNewClientand thehttp.Clientsetup. - Add a watch type: extend
api/watch/funcs.goand the dispatch inapi/watch/watch.go.
Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.