dcarbone/php-consul-api
PHP client for the Consul HTTP API. Built for Composer and modeled after HashiCorp’s Go client, with version compatibility guidance and flexible configuration (defaults from Consul env vars or custom config with Guzzle, address, scheme, datacenter, auth, tokens).
Installation
composer require dcarbone/php-consul-api
Register the service provider in config/app.php:
'providers' => [
DCarbone\ConsulApi\ConsulServiceProvider::class,
],
Basic Configuration
Add Consul server URL to .env:
CONSUL_HOST=http://localhost:8500
Publish config (optional):
php artisan vendor:publish --provider="DCarbone\ConsulApi\ConsulServiceProvider"
First Use Case: Health Check
use DCarbone\ConsulApi\Consul;
$consul = app(Consul::class);
$checks = $consul->get('/v1/agent/self')['Checks'];
Service Discovery
// Register a service
$consul->post('/v1/agent/service/register', [
'ID' => 'my-service',
'Name' => 'My Service',
'Address' => '127.0.0.1',
'Port' => 8080,
'Check' => [
'HTTP' => 'http://127.0.0.1:8080/health',
'Interval' => '10s',
],
]);
// Query services
$services = $consul->get('/v1/catalog/service/my-service');
Key-Value Store
// Set/get a key
$consul->put('/v1/kv/my-app/config', json_encode(['debug' => true]));
$config = json_decode($consul->get('/v1/kv/my-app/config')[0]['Value'], true);
Event-Driven Patterns
// Watch for changes (e.g., service updates)
$consul->watch('/v1/catalog/service/my-service', function ($data) {
// Handle service changes (e.g., trigger cache refresh)
}, 5); // Check every 5 seconds
$this->app->bind('consul', function ($app) {
return new Consul($app['config']['consul.custom_host']);
});
$services = Cache::remember('consul-services', now()->addMinutes(1), function () {
return $consul->get('/v1/catalog/service/my-service');
});
Rate Limiting
429 Too Many Requests by:
retry option in the client:
$consul->get('/v1/health/service/my-service', ['retry' => 3]);
ACL Tokens
$consul->setToken('my-acl-token');
403 Forbidden errors if ACLs are misconfigured.Connection Timeouts
'timeout' => 10, // seconds
Watch Indexes
watch method requires a valid Index from the initial response. Always fetch the latest index first:
$initial = $consul->get('/v1/kv/my-key');
$consul->watch('/v1/kv/my-key', $initial['Index'], ...);
$consul->setDebug(true); // Logs raw requests/responses
404 Not Found: Verify the endpoint (e.g., /v1/agent/check/register vs /v1/agent/service/register).500 Internal Server Error: Check Consul server logs for malformed requests.Custom Middleware Add middleware to modify requests/responses:
$consul->addMiddleware(function ($request) {
$request->headers->set('X-Custom-Header', 'value');
});
Event Listeners
Extend the Consul class to add custom methods:
class ExtendedConsul extends Consul {
public function registerServiceWithRetry($service, $retries = 3) {
for ($i = 0; $i < $retries; $i++) {
try {
return parent::post('/v1/agent/service/register', $service);
} catch (\Exception $e) {
if ($i === $retries - 1) throw $e;
sleep(1);
}
}
}
}
Testing
Use the MockHandler from Guzzle for unit tests:
use GuzzleHttp\Handler\MockHandler;
use GuzzleHttp\Psr7\Response;
$mock = new MockHandler([
new Response(200, [], json_encode(['Checks' => []])),
]);
$consul = new Consul(new Client(['handler' => $mock]));
How can I help you explore Laravel packages today?