mateusjunges/confluent-schema-registry-api
PHP 7.4+ client for Confluent Schema Registry REST API. Provides high-level sync/async helpers plus low-level PSR-7 request builders, Avro schema support, and optional caching integration for fetching, registering, and managing schemas.
composer require flix-tech/confluent-schema-registry-api
config/services.php):
'schema-registry' => [
'url' => env('SCHEMA_REGISTRY_URL', 'http://localhost:8081'),
'auth' => [
'basic' => [
'username' => env('SCHEMA_REGISTRY_USER'),
'password' => env('SCHEMA_REGISTRY_PASSWORD'),
],
],
],
use FlixTech\SchemaRegistryApi\Registry\BlockingRegistry;
use GuzzleHttp\Client;
use FlixTech\AvroPhp\AvroSchema;
class SchemaService {
protected $registry;
public function __construct() {
$client = new Client([
'base_uri' => config('services.schema-registry.url'),
'auth' => config('services.schema-registry.auth.basic'),
]);
$this->registry = new BlockingRegistry(
new PromisingRegistry($client)
);
}
public function registerSchema(string $subject, string $schemaJson): int {
$schema = AvroSchema::parse($schemaJson);
return $this->registry->register($subject, $schema);
}
}
Use the package to validate Kafka payloads against registered schemas in a Laravel request handler:
use FlixTech\SchemaRegistryApi\Registry\BlockingRegistry;
use FlixTech\AvroPhp\AvroSchema;
class KafkaWebhookController extends Controller {
protected $registry;
public function __construct(BlockingRegistry $registry) {
$this->registry = $registry;
}
public function handleWebhook(Request $request) {
$payload = $request->json();
$schemaId = $this->registry->schemaId('webhook-payload', AvroSchema::parse($payload));
// Proceed with validated payload
}
}
$schemaId = $registry->register('user-profile', $schema);
$promise = $registry->register('user-profile', $schema);
$promise->then(function ($schemaId) {
// Handle schema ID asynchronously
});
Leverage caching to reduce Schema Registry API calls in high-traffic Laravel applications:
use FlixTech\SchemaRegistryApi\Registry\CachedRegistry;
use FlixTech\SchemaRegistryApi\Registry\Cache\DoctrineCacheAdapter;
use Doctrine\Common\Cache\ArrayCache;
$cache = new DoctrineCacheAdapter(new ArrayCache());
$cachedRegistry = new CachedRegistry($promisingRegistry, $cache);
// Cache schema IDs by schema hash (default: md5)
$schemaId = $cachedRegistry->register('user-profile', $schema);
Bind the registry to Laravel’s container in AppServiceProvider:
public function register() {
$this->app->singleton(BlockingRegistry::class, function ($app) {
$client = new Client([
'base_uri' => config('services.schema-registry.url'),
]);
return new BlockingRegistry(new PromisingRegistry($client));
});
}
Inject the registry into controllers, commands, or jobs:
public function __construct(BlockingRegistry $registry) {
$this->registry = $registry;
}
Use the package to manage schema versions in Laravel migrations:
public function up() {
$schema = AvroSchema::parse(file_get_contents('schemas/user.avsc'));
$schemaId = $this->registry->register('user', $schema);
Schema::create('users', function (Blueprint $table) use ($schemaId) {
$table->id();
$table->integer('schema_id')->default($schemaId);
// ...
});
}
Wrap registry operations in Laravel’s exception handling:
use FlixTech\SchemaRegistryApi\Exception\SchemaRegistryException;
try {
$schemaId = $this->registry->register('user-profile', $schema);
} catch (SchemaRegistryException $e) {
report($e); // Log to Laravel's error reporting
throw new \RuntimeException('Schema registration failed', 0, $e);
}
Use the low-level API to build custom requests (e.g., for schema deletion):
use FlixTech\SchemaRegistryApi\Requests\Functions;
$request = Functions::deleteSchema($client, 'subject', 1);
$response = $client->send($request);
Schema Registry Compatibility:
flix-tech/avro-php). For Protobuf or JSON Schema, you’ll need to pre-process schemas or extend the package.Caching Quirks:
CachedRegistry does not automatically invalidate cached schemas when they’re updated. Implement a custom cache adapter or use a TTL-based strategy.md5 hashing may cause collisions for large schemas. Use sha1 or a custom hash function for critical applications:
$cachedRegistry = new CachedRegistry($promisingRegistry, $cache, 'sha1');
Asynchronous Edge Cases:
SchemaRegistryException, but uncaught exceptions in .then() callbacks will throw. Always handle rejections explicitly:
$promise->then(function ($schemaId) {
return $schemaId;
})->otherwise(function (SchemaRegistryException $e) {
// Log or rethrow
});
.wait() or handle promises in a bounded context (e.g., Laravel jobs).Authentication:
$client = new Client([
'base_uri' => config('services.schema-registry.url'),
'auth' => ['user', 'pass'], // Basic Auth
// 'headers' => ['Authorization' => 'Bearer token'], // Bearer token
]);
Schema Registry Performance:
App\Exceptions\Handler:
public function render($request, Throwable $exception) {
if ($exception instanceof SchemaRegistryException && $exception->getCode() === 429) {
return response()->json(['error' => 'Rate limited'], 429);
}
return parent::render($request, $exception);
}
Enable Guzzle Middleware: Add a logging middleware to debug HTTP requests:
$client = new Client([
'base_uri' => config('services.schema-registry.url'),
'middleware' => [
new \GuzzleHttp\Middleware::tap(function ($request) {
\Log::debug('Schema Registry Request', [
'method' => $request->getMethod(),
'uri' => (string) $request->getUri(),
'body' => (string) $request->getBody(),
]);
}),
],
]);
Validate Schema Registry Health:
Check the registry’s health endpoint in Laravel’s routes/api.php:
Route::get('/schema-registry/health', function () {
$client = new Client(['base_uri' => config('services.schema-registry.url')]);
$response = $client->get('/subjects');
return response()->json(['status' => 'healthy']);
});
Schema Registry Logs:
/var/log/confluent/schema-registry/schema-registry.log (default path).CacheAdapterInterface for custom caching backends (e.g., Redis):
use FlixTech\SchemaRegistryApi\Registry\Cache\CacheAdapterInterface;
use Psr\SimpleCache\
How can I help you explore Laravel packages today?