A PHP 7.4+ library to consume the Confluent Schema Registry REST API

Overview

Confluent Schema Registry PHP API

schema-registry-ci Actions Status Maintainability Test Coverage Latest Stable Version Total Downloads License

A PHP 7.4+ library to consume the Confluent Schema Registry REST API. It provides low level functions to create PSR-7 compliant requests that can be used as well as high level abstractions to ease developer experience.

Contents

Requirements

Hard dependencies

Dependency Version Reason
php ~7.4 Anything lower has reached EOL
guzzlephp/guzzle ~7.0 Using Request to build PSR-7 RequestInterface
beberlei/assert ~2.7|~3.0 The de-facto standard assertions library for PHP
flix-tech/avro-php ^4.1 Maintained fork of the only Avro PHP implementation: rg/avro-php

Optional dependencies

Dependency Version Reason
doctrine/cache ~1.3 If you want to use the DoctrineCacheAdapter
psr/cache ^1.0 If you want to use the CacheItemPoolAdapter
psr/simple-cache ^1.0 If you want to use the SimpleCacheAdapter

Installation

This library is installed via composer.

composer require "flix-tech/confluent-schema-registry-api=^7.4"

NOTE

If you are still running on a version less than 5.0.3 we recommend updating it immediately since there was a critical bug with the exception handling.

Compatibility

This library follows strict semantic versioning, so you can expect any minor and patch release to be compatible, while major version upgrades will have incompatibilities that will be released in the UPGRADE.md file.

Usage

Asynchronous API

Interface declaration

Example PromisingRegistry

register('test-subject', $schema); // If you want to resolve the promise, you might either get the value or an instance of a SchemaRegistryException // It is more like an Either Monad, since returning Exceptions from rejection callbacks will throw them. // We want to leave that decision to the user of the lib. // TODO: Maybe return an Either Monad instead $promise = $promise->then( static function ($schemaIdOrSchemaRegistryException) { if ($schemaIdOrSchemaRegistryException instanceof SchemaRegistryException) { throw $schemaIdOrSchemaRegistryException; } return $schemaIdOrSchemaRegistryException; } ); // Resolve the promise $schemaId = $promise->wait(); // Get a schema by schema id $promise = $registry->schemaForId($schemaId); // As above you could add additional callbacks to the promise $schema = $promise->wait(); // Get the version of a schema for a given subject. $version = $registry->schemaVersion( 'test-subject', $schema )->wait(); // You can also get a schema by subject and version $schema = $registry->schemaForSubjectAndVersion('test-subject', $version)->wait(); // You can additionally just query for the currently latest schema within a subject. // *NOTE*: Once you requested this it might not be the latest version anymore. $latestSchema = $registry->latestVersion('test-subject')->wait(); // Sometimes you want to find out the global schema id for a given schema $schemaId = $registry->schemaId('test-subject', $schema)->wait();">


use GuzzleHttp\Client;
use FlixTech\SchemaRegistryApi\Registry\PromisingRegistry;
use FlixTech\SchemaRegistryApi\Exception\SchemaRegistryException;

$registry = new PromisingRegistry(
    new Client(['base_uri' => 'registry.example.com'])
);

// Register a schema with a subject
$schema = AvroSchema::parse('{"type": "string"}');

// The promise will either contain a schema id as int when fulfilled,
// or a SchemaRegistryException instance when rejected.
// If the subject does not exist, it will be created implicitly
$promise = $registry->register('test-subject', $schema);

// If you want to resolve the promise, you might either get the value or an instance of a SchemaRegistryException
// It is more like an Either Monad, since returning Exceptions from rejection callbacks will throw them.
// We want to leave that decision to the user of the lib.
// TODO: Maybe return an Either Monad instead
$promise = $promise->then(
    static function ($schemaIdOrSchemaRegistryException) {
        if ($schemaIdOrSchemaRegistryException instanceof SchemaRegistryException) {
            throw $schemaIdOrSchemaRegistryException;
        }
        
        return $schemaIdOrSchemaRegistryException;
    }
);

// Resolve the promise
$schemaId = $promise->wait();

// Get a schema by schema id
$promise = $registry->schemaForId($schemaId);
// As above you could add additional callbacks to the promise
$schema = $promise->wait();

// Get the version of a schema for a given subject.
$version = $registry->schemaVersion(
    'test-subject',
    $schema
)->wait();

// You can also get a schema by subject and version
$schema = $registry->schemaForSubjectAndVersion('test-subject', $version)->wait();

// You can additionally just query for the currently latest schema within a subject.
// *NOTE*: Once you requested this it might not be the latest version anymore.
$latestSchema = $registry->latestVersion('test-subject')->wait();

// Sometimes you want to find out the global schema id for a given schema
$schemaId = $registry->schemaId('test-subject', $schema)->wait();

Synchronous API

Interface declaration

Example BlockingRegistry

register('test-subject', $schema);">


use FlixTech\SchemaRegistryApi\Registry\BlockingRegistry;
use FlixTech\SchemaRegistryApi\Registry\PromisingRegistry;
use GuzzleHttp\Client;

$registry = new BlockingRegistry(
    new PromisingRegistry(
        new Client(['base_uri' => 'registry.example.com'])
    )
);

// What the blocking registry does is actually resolving the promises
// with `wait` and adding a throwing rejection callback.
$schema = AvroSchema::parse('{"type": "string"}');

// This will be an int, and not a promise
$schemaId = $registry->register('test-subject', $schema);

Caching

There is a CachedRegistry that accepts a CacheAdapter together with a Registry. It supports both async and sync APIs.

NOTE:

From version 4.x of this library the API for the CacheAdapterInterface has been changed in order to allow caching of schema ids by hash of a given schema.

Example



use FlixTech\SchemaRegistryApi\Registry\BlockingRegistry;
use FlixTech\SchemaRegistryApi\Registry\PromisingRegistry;
use FlixTech\SchemaRegistryApi\Registry\CachedRegistry;
use FlixTech\SchemaRegistryApi\Registry\Cache\AvroObjectCacheAdapter;
use FlixTech\SchemaRegistryApi\Registry\Cache\DoctrineCacheAdapter;
use Doctrine\Common\Cache\ArrayCache;
use GuzzleHttp\Client;

$asyncApi = new PromisingRegistry(
    new Client(['base_uri' => 'registry.example.com'])
);

$syncApi = new BlockingRegistry($asyncApi);

$doctrineCachedSyncApi = new CachedRegistry(
    $asyncApi,
    new DoctrineCacheAdapter(
        new ArrayCache()
    )
);

// All adapters support both APIs, for async APIs additional fulfillment callbacks will be registered.
$avroObjectCachedAsyncApi = new CachedRegistry(
    $syncApi,
    new AvroObjectCacheAdapter()
);

// NEW in version 4.x, passing in custom hash functions to cache schema ids via the schema hash
// By default the following function is used internally
$defaultHashFunction = static function (AvroSchema $schema) {
   return md5((string) $schema); 
};

// You can also define your own hash callable
$sha1HashFunction = static function (AvroSchema $schema) {
   return sha1((string) $schema); 
};

// Pass the hash function as optional 3rd parameter to the CachedRegistry constructor
$avroObjectCachedAsyncApi = new CachedRegistry(
    $syncApi,
    new AvroObjectCacheAdapter(),
    $sha1HashFunction
);

Low Level API

There is a low-level API that provides simple functions that return PSR-7 request objects for the different endpoints of the registry. See Requests/Functions for more information.

There are also requests to use the new DELETE API of the schema registry.

Testing

This library uses a Makefile to run the test suite and requires docker.

You can set the default variables by copying variables.mk.dist to variables.mk and change them to your liking.

Build the local docker image

PHP_VERSION=7.3 XDEBUG_VERSION=2.9.8 make docker

Unit tests, Coding standards and static analysis

PHP_VERSION=7.3 make ci-local

Integration tests

This library uses a docker-compose configuration to fire up a schema registry for integration testing, hence docker-compose from version 1.18.x is required to run those tests.

The platform can be controlled with the following environment variables
CONFLUENT_VERSION=latest
CONFLUENT_NETWORK_SUBNET=172.68.0.0/24
SCHEMA_REGISTRY_IPV4=172.68.0.103
KAFKA_BROKER_IPV4=172.68.0.102
ZOOKEEPER_IPV4=172.68.0.101
Building the confluent platform with a specific version and run the integration tests
CONFLUENT_VERSION=5.2.3 make platform
make phpunit-integration
make clean

Contributing

In order to contribute to this library, follow this workflow:

  • Fork the repository
  • Create a feature branch
  • Work on the feature
  • Run tests to verify that the tests are passing
  • Open a PR to the upstream
  • Be happy about contributing to open source!
Comments
  • Fixed error message for connection exceptions

    Fixed error message for connection exceptions

    Hi there!

    There is only handling of Guzzle RequestExceptions. When my team and I got another type of exception - package drives us crazy with it's message šŸ˜… I've changed this behavior, and turn this:

    image

    into this:

    image

    opened by Elnadrion 7
  • support non-root paths in base_uri

    support non-root paths in base_uri

    resolves #61

    Given a Guzzle client with a base uri like http://example.com/myregistryliveshere/.

    Requests where created with a relative path with a leading /. Guzzle interprets this as a path from the root and replaces /myregistryliveshere/ with the given path.

    To make Guzzle combine the path correctly with the given base_uri, the relative path must not start with a /. Then it is appended at the end of the base_uri, preserving the path in the base_uri.

    opened by Yspadadden 3
  • Guzzle7 with uri template

    Guzzle7 with uri template

    This PR hopes to address issue #55 and #57. It appeared that the main blocker was the removal of the UriTemplate class out of Guzzle7. That specific class was added back as its own repository by the Guzzle team, which I was able to add and it integrated pretty seamlessly. I was able to run all the tests including the docker integration tests and all of them passed. This is my first PR to an open source repo so I apologize in advance for any errors on my part, I'm happy to make any recommended changes. Thanks!

    opened by Stephentoe 3
  • Allow guzzlehttp/psr7 ^1.7|^2.1

    Allow guzzlehttp/psr7 ^1.7|^2.1

    I got a conflict on guzzlehttp/psr7 when installing this package. Other dependencies of the project I am working on have ^1.7|^2.1 as version constraint. So why not add it in this package.

    I've ran the tests, all seems well!

    opened by rtuin 2
  • Add Guzzle 7 support

    Add Guzzle 7 support

    Once the UriTemplate class was heavily used and it had been removed from Guzzle 7 it was not possible to add support for the next guzzle major version.

    Replace usages of UriTemplate with sprintf calls and update composer.json with support for guzzle 7.

    Fixes #57 Fixes #55

    opened by fcoedno 2
  • breaking changes / semver

    breaking changes / semver

    the recent 7.3.0 release made some breaking changes. (deleting / renaming of classes)

    im not actually requiring this project directly, but it is required by flix-tech/avro-serde-php with a version selector of ~7.1 which will select the latest version up until 8.0 gets released.

    if you dont want to follow semver then that is fine, but in that case you need to be more careful with required versions so that users of your (otherwise) great libraries dont have to deal with breaking changes

    bug 
    opened by rs-sliske 2
  • Add support for psr cache interfaces

    Add support for psr cache interfaces

    opened by fcoedno 2
  • deser with Cached Registry do not retrieve to schema-registry new schema at run time

    deser with Cached Registry do not retrieve to schema-registry new schema at run time

    https://github.com/jobcloud/php-kafka-lib/issues/72

    look like the avro deserializer (with cached registry) do not fetch new schema versions at run time but deserialize with the existing cached schema even if it's not the one used to serialize the message

    the deserilization should (like it work for the confluent lib) fetch the new schema if user did not fix the version ( id of schema) it want for deserialization

    opened by raphaelauv 1
  • Fix SimpleCacheAdapter to fix exception caused when the store returns a string of the numeric value

    Fix SimpleCacheAdapter to fix exception caused when the store returns a string of the numeric value

    When using SimpleCacheAdapter with the Laravel Redis cache adapter, the method getIdWithHash tries to return the string representation of the value in the store directly. Giving the following exception Symfony\Component\Debug\Exception\FatalThrowableError with message 'Return value of FlixTech\SchemaRegistryApi\Registry\Cache\SimpleCacheAdapter::getIdWithHash() must be of the type int or null, string returned'

    opened by danlitman 1
  • basic auth

    basic auth

    Say I have my schema registry endpoint protected using basic auth from Nginx. Would I be able to define the login details somewhere special or just in the url like this?:

    https://username:[email protected]/
    
    opened by MrMoronIV 1
  • Fix jsonSerialize on PHP 8.1+

    Fix jsonSerialize on PHP 8.1+

    During inheritance of JsonSerializable: Uncaught ErrorException: Return type of FlixTech\SchemaRegistryApi\Schema\AvroReference::jsonSerialize() should either be compatible with JsonSerializable::jsonSerialize(): mixed, or the #[\ReturnTypeWillChange] attribute should be used to temporarily suppress the notice
    
    opened by BafS 0
  • Why do we fail kafka consumer if the previous version for the subject not found?

    Why do we fail kafka consumer if the previous version for the subject not found?

    Kafka schema registry allows a user to permanently/softly delete a subject version without any issues. Why does this client fail consumption of message if version 1 was not found?

    Version tested on: 7.5.0

    opened by varunkamra 1
  • Support for importing and merging referenced schema

    Support for importing and merging referenced schema

    Hi There,

    I have a use case where I am using the this repo to get a schema from the schema registry which contains another schema as a reference. Is there a way to call the referenced schema and merge it into the main schema? As the https://github.com/flix-tech/schema-registry-php-client/blob/master/src/Registry/PromisingRegistry.php#L142 sends the response to the AvroSchema::parse() method which expects the referenced schema to present within the main schema.

    Please let me know if there is an alternative way to do this or if I am missing anything. Thanks

    opened by itsavinash 0
Releases(7.6.1)
Owner
Flix.TECH
We are the IT department of FlixBus. We ā¤ technology, open source and building things. We are hiring!
Flix.TECH
A small library for validating International Bankaccount Numbers (IBANs) based on the IBAN Registry provided by SWIFT

A small library for validating International Bankaccount Numbers (IBANs) based on the IBAN Registry provided by SWIFT

Jan SchƤdlich 69 Dec 18, 2022
EasyRdf is a PHP library designed to make it easy to consume and produce RDF.

EasyRdf EasyRdf is a PHP library designed to make it easy to consume and produce RDF. It was designed for use in mixed teams of experienced and inexpe

EasyRdf 578 Dec 23, 2022
Private Composer registry for private PHP packages on AWS Serverless

Tug Tug is a Composer private registry for private PHP packages installable with Composer (1 and 2). The main idea of this project is to have an inter

Fxp 33 Oct 5, 2022
Composer registry manager that help to easily switch to the composer repository you want

CRM - Composer Registry Manager Composer Registry Manager can help you easily and quickly switch between different composer repositories. ē®€ä½“äø­ę–‡ Install

Tao 500 Dec 29, 2022
šŸ’³ WordPress/WooCoommerce Brazilian Fields in Registry

Brazilian Fields in WordPress Registry A wordpress plugin that can be used for customize your website. Brazilian fields are added to the wordpress reg

Vinicius Blazius Goulart 7 Sep 20, 2022
A Symfony bundle built to schedule/consume repetitive tasks

Daily runs Code style Infection PHPUnit Rector Security Static analysis A Symfony bundle built to schedule/consume repetitive tasks Main features Exte

Guillaume Loulier 98 Jan 4, 2023
This is an implementation of PSR specification. It allows you to send and consume message with Redis store as a broker.

This is an implementation of PSR specification. It allows you to send and consume message with Redis store as a broker.

Enqueue 35 Nov 4, 2022
Swaggest JSON-schema implementation for PHP

Swaggest JSON-schema implementation for PHP High definition PHP structures with JSON-schema based validation. Supported schemas: JSON Schema Draft 7 J

null 370 Dec 29, 2022
JSON schema models and generated code to validate and handle various data in PocketMine-MP

DataModels JSON schema models and generated code to validate and handle various data in PocketMine-MP This library uses php-json-schema-model-generato

PMMP 2 Nov 9, 2022
A Magento implementation for validating JSON Structures against a given Schema

Zepgram JsonSchema A Magento implementation for validating JSON Structures against a given Schema with support for Schemas of Draft-3 or Draft-4. Base

Benjamin Calef 1 Nov 5, 2021
Code to accompany the YouTube video "Full PHP cURL API tutorial - how to use a REST API from PHP using cURL"

PHP cURL CRUD Example Example code to accompany this YouTube video. Note that the init_curl.php file contains a placeholder for an API key. DO NOT che

Dave Hollingworth 14 Dec 24, 2022
The fastest way to make a powerful JSON:API compatible Rest API with Laravel.

The first fully customizable Laravel JSON:API builder. "CRUD" and protect your resources with 0 (zero) extra line of code. Installation You can instal

BinarCode 394 Dec 23, 2022
A PHP library to support implementing representations for HATEOAS REST web services.

Hateoas A PHP library to support implementing representations for HATEOAS REST web services. Installation Working With Symfony Usage Introduction Conf

William Durand 998 Dec 5, 2022
API REST para CRUD de usuƔrios

Crud de UsuĆ”rios QUAL A FUNƇƃO DA API? Esta API tem como objetivo cadastrar usuĆ”rios e seus respectivos endereƧos por meio de requests e tambĆ©m fazer

Gabriel Cruz 1 Mar 26, 2022
Desafio de Back-End da Alura: Crie uma API Rest funcional focada em controle financeiro.

Lumen PHP Framework Laravel Lumen is a stunningly fast PHP micro-framework for building web applications with expressive, elegant syntax. We believe d

Rejman Nascimento 0 Dec 31, 2022
ILIAS Rest Api

flux-ilias-rest-api ILIAS Rest Api This is not a ILIAS plugin Installation flux-ilias-rest-api In flux-ilias-ilias-base RUN /flux-ilias-ilias-base/bin

null 4 Dec 14, 2022
Twitter Clone API Rest with Laravel 9

TW Main API (Twitter Clone) Setup Installation Before docker-compose up Get copy the .env.example to .env Set Mail variables Set Pusher Variables with

Jesus Eduardo 0 Jul 31, 2022
A standalone Amazon S3 (REST) client for PHP 5/CURL

Amazon S3 PHP Class Usage OO method (e,g; $s3->getObject(...)): $s3 = new S3($awsAccessKey, $awsSecretKey); Statically (e,g; S3::getObject(...)): S3::

Donovan Schƶnknecht 1k Jan 3, 2023
A Magento 2 module that enables configurable CORS Headers on the GraphQL and REST APIs

Magento 2 CORS Magento Version Support Ever try to work with the Magento GraphQL API or REST API from your browser and see the following? Access to XM

Graycore, LLC 62 Dec 8, 2022