Tutorial: Use Schema Registry on Confluent Platform to define schemas for a client application

Use Confluent Schema Registry on Confluent Platform to enable client applications to read and write Avro data, check schema compatibility as schemas evolve, and manage schemas in Confluent Control Center. The following steps walk through the full workflow.

Schema Registry terms: topic, schema, and subject

What is a topic versus a schema versus a subject?

  • An Apache Kafka® topic contains messages, and each message is a key-value pair. The producer can serialize the message key, the message value, or both, as Avro, JSON Schema, or Protobuf.

  • A schema defines the structure of the data format. The Kafka topic name can be independent of the schema name.

  • The schema subject is a Schema Registry-defined scope in which schemas can evolve. The name of the subject depends on the configured subject name strategy, which, by default, derives the subject name from the topic name.

You can change the subject name strategy on a per-topic basis, so different topics aren’t locked into the same strategy. To learn more, see Change the subject naming strategy for a topic.

Subjects can be logically grouped into schema contexts to create separate sub-registries within a single Schema Registry. Contexts serve as the basis for Schema Linking as described in Contexts, and are also useful in scenarios that require more nuanced schema management.

Message keys are optional. For example, a message’s value might be an Avro record while its key is a primitive, such as string or integer. Keys are typically primitives, though they can also be complex types, such as record or array. How you structure the key depends on your application’s requirements. For detailed examples of key and value schemas, see Formats, Serializers, and Deserializers.

For example, consider a retail business streaming transactions in a Kafka topic named transactions. A producer is writing data with a schema Payment to that Kafka topic transactions. If the producer is serializing the message value as Avro, then Schema Registry has a subject called transactions-value.

If the producer is also serializing the message key as Avro, Schema Registry would have a subject called transactions-key. For simplicity, this tutorial considers only the message value. The subject transactions-value defines the scope in which schemas for that subject can evolve, and Schema Registry checks compatibility within this scope. That Schema Registry subject transactions-value contains at least one schema called Payment.

In this scenario, if you evolve the schema Payment and produce new messages to the topic transactions, Schema Registry checks that those newly evolved schemas are compatible with older schemas in the subject transactions-value. Schema Registry then adds those new schemas to the subject.

Set up your Confluent Platform tutorial environment

Prerequisites

Verify that you have installed the following on your local machine:

  • Confluent Platform

  • Confluent CLI

  • Java 8 or 11 to run Confluent Platform. For full information about Confluent Platform Java prerequisites, see Java under Supported Versions and Interoperability.

  • Maven to compile the client Java code

  • jq tool to nicely format the results from querying the Schema Registry REST endpoint

Start Confluent Platform and configure client connection settings

  1. Use the quick start to bring up a single-node Confluent Platform development environment. With a single-line confluent local command, you can have a basic Kafka cluster with Schema Registry, Control Center, and other services running on your local machine.

    confluent local start
    

    Your output should resemble:

    Starting zookeeper
    zookeeper is [UP]
    Starting kafka
    kafka is [UP]
    Starting schema-registry
    schema-registry is [UP]
    Starting kafka-rest
    kafka-rest is [UP]
    Starting connect
    connect is [UP]
    Starting ksql-server
    ksql-server is [UP]
    Starting control-center
    control-center is [UP]
    
  2. Clone the Confluent examples repo from GitHub and work in the clients/avro/ subdirectory, which provides the sample code you will compile and run in this tutorial.

    git clone https://github.com/confluentinc/examples.git
    
    cd examples/clients/avro
    
    git checkout 8.3.2-post
    
  3. Create a local configuration file with all the connection information for the Kafka and Schema Registry services running on your local machine, and save it to $HOME/.confluent/java.config, where $HOME represents your user home directory. It should resemble the following:

    # Required connection configs for Kafka producer, consumer, and admin
    bootstrap.servers=localhost:9092
    
    # Required connection configs for Schema Registry
    schema.registry.url=http://localhost:8081
    

Create the transactions topic

For the exercises in this tutorial, you produce to and consume from a topic named transactions. Create this topic in Control Center.

  1. Navigate to the Control Center web interface at http://localhost:9021/.

    Important

    It might take a few minutes for Control Center to come online.

    Confluent Control Center landing page showing available clusters
  2. Select the cluster, select Topics, and select Create topic.

    Control Center Topics page with the Create topic button highlighted
  3. Name the topic transactions, and then select Create with defaults.

    Create topic dialog with the topic name field set to transactions

    The new topic appears.

    Control Center Topics list showing the newly created transactions topic

Schema definition

The first thing developers need to do is agree on a basic schema for data. Client applications form a contract:

  • producers will write data in a schema

  • consumers will be able to read that data

Consider the original Payment schema Payment.avsc. To view the schema, run this command:

cat src/main/resources/avro/io/confluent/examples/clients/basicavro/Payment.avsc

Observe the schema definition:

{
 "namespace": "io.confluent.examples.clients.basicavro",
 "type": "record",
 "name": "Payment",
 "fields": [
     {"name": "id", "type": "string"},
     {"name": "amount", "type": "double"}
 ]
}

Here is a break-down of what this schema defines:

  • namespace: a fully qualified name that avoids schema naming conflicts

  • type: Avro data type, for example, record, enum, union, array, map, or fixed

  • name: unique schema name in this namespace

  • fields: one or more simple or complex data types for a record. The first field in this record is called id, and it is of type string. The second field in this record is called amount, and it is of type double.

Client applications writing Avro

Maven

This tutorial uses Maven to configure the project and dependencies. Java applications that have Kafka producers or consumers using Avro require pom.xml files to include, among other things:

  • Confluent Maven repository

  • Confluent Maven plugin repository

  • Dependencies org.apache.avro.avro and io.confluent.kafka-avro-serializer to serialize data as Avro

  • Plugin avro-maven-plugin to generate Java class files from the source schema

The pom.xml file may also include:

  • Plugin kafka-schema-registry-maven-plugin to check compatibility of evolving schemas

For a full pom.xml example, refer to this pom.xml.

Configuring Avro

Kafka applications using Avro data and Schema Registry need to specify at least two configuration parameters:

  • Avro serializer or deserializer

  • Properties to connect to Schema Registry

There are two basic types of Avro records that your application can use:

  • a specific code-generated class, or

  • a generic record

The examples in this tutorial demonstrate how to use the specific Payment class. Using a specific code-generated class requires you to define and compile a Java class for your schema, but it easier to work with in your code.

However, in other scenarios where you need to work dynamically with data of any type and do not have Java classes for your record types, use GenericRecord.

Confluent Platform also provides a serializer and deserializer for writing and reading data in “reflection Avro” format. To learn more, see Reflection Based Avro Serializer and Deserializer.

Java producers

Within the client application, Java producers need to configure the Avro serializer for the Kafka value (or Kafka key) and URL to Schema Registry. Then the producer can write records where the Kafka value is of Payment class.

Example producer code

When constructing the producer, configure the message value class to use the application’s code-generated Payment class. For example:

...
import io.confluent.kafka.serializers.KafkaAvroSerializer;
...
props.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, StringSerializer.class);
props.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, KafkaAvroSerializer.class);
...
KafkaProducer<String, Payment> producer = new KafkaProducer<String, Payment>(props));
final Payment payment = new Payment(orderId, 1000.00d);
final ProducerRecord<String, Payment> record = new ProducerRecord<String, Payment>(TOPIC, payment.getId().toString(), payment);
producer.send(record);
...

Because the pom.xml includes avro-maven-plugin, the Payment class is automatically generated during compile.

In this example, the connection information to the Kafka brokers and Schema Registry is provided by the configuration file that is passed into the code, but if you want to specify the connection information directly in the client application, see this java template.

For a full Java producer example, refer to the producer example.

Run the producer

Run the following commands in a shell from examples/clients/avro.

  1. To run this producer, first compile the project:

    mvn clean compile package
    
  2. From the Control Center navigation menu at http://localhost:9021/, make sure the cluster is selected, and then select Topics.

    Next, select the transactions topic and go to the Messages tab.

    No messages appear, because you haven’t produced any messages to this topic yet.

  3. Run ProducerExample, which produces Avro-formatted messages to the transactions topic. Pass in the path to the file you created earlier, $HOME/.confluent/java.config.

    mvn exec:java -Dexec.mainClass=io.confluent.examples.clients.basicavro.ProducerExample \
      -Dexec.args="$HOME/.confluent/java.config"
    

    The command takes a moment to run. When it completes, you should see:

    ...
    Successfully produced 10 messages to a topic called transactions
    [INFO] ------------------------------------------------------------------------
    [INFO] BUILD SUCCESS
    [INFO] ------------------------------------------------------------------------
    ...
    
  4. Messages now appear in Control Center when you inspect the transactions topic. Control Center dynamically deserializes the newly arriving Avro-serialized data.

    At http://localhost:9021/, select the cluster, and then go to Topics > transactions > Messages.

    Tip

    If no messages appear, rerun the producer, verify it completed successfully, and check Control Center again. Because messages don’t persist in the console, you should view them immediately after you run the producer.

    Control Center Messages tab showing deserialized Avro messages in the transactions topic

Java consumers

Within the client application, Java consumers need to configure the Avro deserializer for the Kafka value (or Kafka key) and URL to Schema Registry. Then the consumer can read records where the Kafka value is of Payment class.

Example consumer code

By default, each record is deserialized into an Avro GenericRecord, but in this tutorial the record should be deserialized using the application’s code-generated Payment class. Therefore, configure the deserializer to use Avro SpecificRecord, i.e., SPECIFIC_AVRO_READER_CONFIG should be set to true. For example:

...
import io.confluent.kafka.serializers.KafkaAvroDeserializer;
...
props.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class);
props.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, KafkaAvroDeserializer.class);
props.put(KafkaAvroDeserializerConfig.SPECIFIC_AVRO_READER_CONFIG, true);
...
KafkaConsumer<String, Payment> consumer = new KafkaConsumer<>(props));
consumer.subscribe(Collections.singletonList(TOPIC));
while (true) {
  ConsumerRecords<String, Payment> records = consumer.poll(100);
  for (ConsumerRecord<String, Payment> record : records) {
    String key = record.key();
    Payment value = record.value();
  }
}
...

Because the pom.xml includes avro-maven-plugin, the Payment class is automatically generated during compile.

In this example, the connection information to the Kafka brokers and Schema Registry is provided by the configuration file that is passed into the code, but if you want to specify the connection information directly in the client application, see this java template.

For a full Java consumer example, refer to the consumer example.

Run the consumer

  1. To run this consumer, first compile the project.

    mvn clean compile package
    

    The BUILD SUCCESS message indicates the project built, and the command prompt becomes available again.

  2. Then run ConsumerExample (assuming you already ran the ProducerExample above). Pass in the path to the file you created earlier, $HOME/.confluent/java.config.

    mvn exec:java -Dexec.mainClass=io.confluent.examples.clients.basicavro.ConsumerExample \
      -Dexec.args="$HOME/.confluent/java.config"
    

    You should see:

    ...
    key = id0, value = {"id": "id0", "amount": 1000.0}
    key = id1, value = {"id": "id1", "amount": 1000.0}
    key = id2, value = {"id": "id2", "amount": 1000.0}
    key = id3, value = {"id": "id3", "amount": 1000.0}
    key = id4, value = {"id": "id4", "amount": 1000.0}
    key = id5, value = {"id": "id5", "amount": 1000.0}
    key = id6, value = {"id": "id6", "amount": 1000.0}
    key = id7, value = {"id": "id7", "amount": 1000.0}
    key = id8, value = {"id": "id8", "amount": 1000.0}
    key = id9, value = {"id": "id9", "amount": 1000.0}
    ...
    
  3. Press Ctrl+C to stop.

Other Kafka clients

The objective of this tutorial is to learn about Avro and Schema Registry centralized schema management and compatibility checks. To keep examples simple, this tutorial focuses on Java producers and consumers, but other Kafka clients work in similar ways. For examples of other Kafka clients interoperating with Avro and Schema Registry:

Centralized schema management

Viewing schemas in Schema Registry

View the latest schema for a topic from the Control Center Schema tab.

  1. From the Control Center navigation menu at http://localhost:9021/, select the cluster and then select Topics.

  2. Select the transactions topic and go to the Schema tab to retrieve the latest schema from Schema Registry for this topic:

    Control Center Schema tab showing the latest registered schema for the transactions topic

    The schema is identical to the schema file defined for Java client applications.

Schema IDs in messages

Integration with Schema Registry means producers don’t need to write the entire Avro schema into each Kafka message. Instead, producers write the schema ID into the message. The producers writing the messages and the consumers reading the messages must use the same Schema Registry to get the same mapping between a schema and schema ID.

In this example, a producer sends the new schema for Payment to Schema Registry. Schema Registry registers this schema Payment to the subject transactions-value, and returns the schema ID of 1 to the producer. The producer caches this mapping between the schema and schema ID for later message writes, so it only contacts Schema Registry on the first schema write.

When a consumer reads this data, it sees the Avro schema ID of 1 and sends a schema request to Schema Registry. Schema Registry retrieves the schema associated with schema ID 1, and returns the schema to the consumer. The consumer caches this mapping between the schema and schema ID for later message reads, so it only contacts Schema Registry on the first schema ID read.

Using curl to interact with Schema Registry

You can also use curl commands to connect directly to the REST endpoint in Schema Registry to view subjects and associated schemas.

  1. To view all the subjects registered in Schema Registry, assuming Schema Registry is running on the local machine and listening on port 8081:

    curl --silent -X GET http://localhost:8081/subjects/ | jq .
    

    This command returns the following output:

    [
      "transactions-value"
    ]
    

    In this example, the Kafka topic transactions has Avro-serialized message values. By default, Schema Registry derives the subject name from the topic name, so the subject for this topic’s value is transactions-value.

  2. To view the latest schema for this subject in more detail:

    curl --silent -X GET http://localhost:8081/subjects/transactions-value/versions/latest | jq .
    

    This command returns the following output:

    {
      "subject": "transactions-value",
      "version": 1,
      "id": 1,
      "schema": "{\"type\":\"record\",\"name\":\"Payment\",\"namespace\":\"io.confluent.examples.clients.basicavro\",\"fields\":[{\"name\":\"id\",\"type\":\"string\"},{\"name\":\"amount\",\"type\":\"double\"}]}"
    }
    

    Here is what this version of the schema defines:

    • subject: the scope in which schemas for the messages in the topic transactions can evolve

    • version: the schema version for this subject, which starts at 1 for each subject

    • id: the globally unique schema version ID, unique across all schemas in all subjects

    • schema: the structure that defines the schema format

    In the output of the previous curl command, the JSON schema is escaped using backslashes before the double quotes, for example \".

  3. Based on the schema ID, you can also retrieve the associated schema by querying the Schema Registry REST endpoint as follows:

    curl --silent -X GET http://localhost:8081/schemas/ids/1 | jq .
    

    This command returns the following output:

    {
      "schema": "{\"type\":\"record\",\"name\":\"Payment\",\"namespace\":\"io.confluent.examples.clients.basicavro\",\"fields\":[{\"name\":\"id\",\"type\":\"string\"},{\"name\":\"amount\",\"type\":\"double\"}]}"
    }
    

Auto schema registration

By default, client applications automatically register new schemas. If they produce new messages to a new topic, then they will automatically try to register new schemas. This is convenient in development environments, but in production environments it’s recommended that client applications do not automatically register new schemas. Best practice is to register schemas outside of the client application to control when schemas are registered with Schema Registry and how they evolve.

Within the application, you can disable automatic schema registration by setting the configuration parameter auto.register.schemas=false, as shown in the following example.

props.put(AbstractKafkaAvroSerDeConfig.AUTO_REGISTER_SCHEMAS, false);

Tip

  • If you want to enable use.latest.version for producers, you must disable auto schema registration by setting auto.register.schemas to false, and use.latest.version to true. (The opposite of their defaults.) The option auto.register.schemas must be set to false in order for use.latest.version to work.

    Setting auto.register.schemas to false disables auto-registration of the event type, so that it does not override the latest schema in the subject. Setting use.latest.version to true causes the serializer to look up the latest schema version in the subject and use that for serialization. If use.latest.version is set to false (which is the default), the serializer will look for the event type in the subject and fail to find it.

    You can also set use.latest.version on consumers, which causes the consumer to look up the latest schema version in the subject and use that as the target schema during deserialization.

  • See also, Schema Registry Configuration Options for Kafka Connect.

  • The configuration option auto.register.schemas is a Confluent Platform feature; not available in Apache Kafka®.

To manually register the schema outside of the application, you can use Control Center.

First, create a new topic called test in the same way that you created a new topic called transactions earlier in the tutorial. Then from the Schema tab, click Set a schema to define the new schema. Specify values for:

  • namespace: a fully qualified name that avoids schema naming conflicts

  • type: Avro data type, one of record, enum, union, array, map, fixed

  • name: unique schema name in this namespace

  • fields: one or more simple or complex data types for a record. The first field in this record is called id, and it is of type string. The second field in this record is called amount, and it is of type double.

If you were to define the same schema as used earlier, you would enter the following in the schema editor:

{
  "type": "record",
  "name": "Payment",
  "namespace": "io.confluent.examples.clients.basicavro",
  "fields": [
    {
      "name": "id",
      "type": "string"
    },
    {
      "name": "amount",
      "type": "double"
    }
  ]
}

Run the following command to connect directly to the REST endpoint in Schema Registry and define a schema for a new subject for the topic test.

curl -X POST -H "Content-Type: application/vnd.schemaregistry.v1+json" \
  --data '{"schema": "{\"type\":\"record\",\"name\":\"Payment\",\"namespace\":\"io.confluent.examples.clients.basicavro\",\"fields\":[{\"name\":\"id\",\"type\":\"string\"},{\"name\":\"amount\",\"type\":\"double\"}]}"}' \
  http://localhost:8081/subjects/test-value/versions

This command creates a schema with an ID of 1, as shown in the following output:

{"id":1}

Schema evolution and compatibility

Evolving schemas

So far in this tutorial, you have seen the benefit of Schema Registry as being centralized schema management that enables client applications to register and retrieve globally unique schema ids. The main value of Schema Registry, however, is in enabling schema evolution. Similar to how APIs evolve and need to be compatible for all applications that rely on old and new versions of the API, schemas also evolve and likewise need to be compatible for all applications that rely on old and new versions of a schema. This schema evolution is a natural behavior of how applications and data develop over time.

Schema Registry allows for schema evolution and provides compatibility checks to ensure that the contract between producers and consumers is not broken. This allows producers and consumers to update independently and evolve their schemas independently, with assurances that they can read new and legacy data. This is especially important in Kafka because producers and consumers are decoupled applications that are sometimes developed by different teams.

Transitive compatibility checking is important once you have more than two versions of a schema for a given subject. If compatibility is configured as transitive, then it checks compatibility of a new schema against all previously registered schemas; otherwise, it checks compatibility of a new schema only against the latest schema.

For example, if there are three schemas for a subject that change in order X-2, X-1, and X then:

  • transitive: ensures compatibility between X-2 <==> X-1 and X-1 <==> X and X-2 <==> X

  • non-transitive: ensures compatibility between X-2 <==> X-1 and X-1 <==> X, but not necessarily X-2 <==> X

Refer to an example of schema changes which are incrementally compatible, but not transitively so.

The Confluent Schema Registry default compatibility type BACKWARD is non-transitive, which means that it’s not BACKWARD_TRANSITIVE. As a result, new schemas are checked for compatibility only against the latest schema.

These are the compatibility types:

  • BACKWARD: (default) consumers using the new schema can read data written by producers using the latest registered schema

  • BACKWARD_TRANSITIVE: consumers using the new schema can read data written by producers using all previously registered schemas

  • FORWARD: consumers using the latest registered schema can read data written by producers using the new schema

  • FORWARD_TRANSITIVE: consumers using all previously registered schemas can read data written by producers using the new schema

  • FULL: the new schema is forward and backward compatible with the latest registered schema

  • FULL_TRANSITIVE: the new schema is forward and backward compatible with all previously registered schemas

  • NONE: schema compatibility checks are disabled

Refer to Schema Evolution and Compatibility for a more in-depth explanation on the compatibility types.

Failing compatibility checks

Schema Registry checks compatibility as schemas evolve to uphold the producer-consumer contract. Without Schema Registry checking compatibility, your applications could potentially break on schema changes.

In the Payment schema example, let’s say the business now tracks additional information for each payment, for example, a field region that represents the place of sale. Consider the Payment2a schema which includes this extra field region:

cat src/main/resources/avro/io/confluent/examples/clients/basicavro/Payment2a.avsc
{
 "namespace": "io.confluent.examples.clients.basicavro",
 "type": "record",
 "name": "Payment",
 "fields": [
     {"name": "id", "type": "string"},
     {"name": "amount", "type": "double"},
     {"name": "region", "type": "string"}
 ]
}

Before proceeding, because the default Schema Registry compatibility is backward, think about whether this new schema is backward compatible. Specifically, ask yourself whether a consumer can use this new schema to read data written by producers using the older schema without the region field. The answer is no. Consumers will fail reading data with the older schema because the older data does not have the region field, therefore this schema is not backward compatible.

Confluent provides a Schema Registry Maven Plugin, which you can use to check compatibility in development or integrate into your CI/CD pipeline.

Our sample pom.xml includes this plugin to enable compatibility checks.

...
<properties>
  <schemaRegistryUrl>http://localhost:8081</schemaRegistryUrl>
  <schemaRegistryBasicAuthUserInfo></schemaRegistryBasicAuthUserInfo>
</properties>
...
<build>
  <plugins>
  ...
    <plugin>
        <groupId>io.confluent</groupId>
        <artifactId>kafka-schema-registry-maven-plugin</artifactId>
        <version>${confluent.version}</version>
        <configuration>
            <schemaRegistryUrls>
                <param>${schemaRegistryUrl}</param>
            </schemaRegistryUrls>
            <userInfoConfig>${schemaRegistryBasicAuthUserInfo}</userInfoConfig>
            <subjects>
                <transactions-value>src/main/resources/avro/io/confluent/examples/clients/basicavro/Payment2a.avsc</transactions-value>
            </subjects>
        </configuration>
        <goals>
            <goal>test-compatibility</goal>
        </goals>
    </plugin>
...
  </plugins>
</build>

It is currently configured to check compatibility of the new Payment2a schema for the transactions-value subject in Schema Registry.

  1. Run the compatibility check and verify that it fails:

    mvn io.confluent:kafka-schema-registry-maven-plugin:test-compatibility
    

    The following is the error message you get:

    ...
    [ERROR] Schema examples/clients/avro/src/main/resources/avro/io/confluent/examples/clients/basicavro/Payment2a.avsc is not compatible with subject(transactions-value)
    ...
    
  2. Try to register the new schema Payment2a manually to Schema Registry, which is a useful way for non-Java clients to check compatibility:

    curl -X POST -H "Content-Type: application/vnd.schemaregistry.v1+json" \
      --data '{"schema": "{\"type\":\"record\",\"name\":\"Payment\",\"namespace\":\"io.confluent.examples.clients.basicavro\",\"fields\":[{\"name\":\"id\",\"type\":\"string\"},{\"name\":\"amount\",\"type\":\"double\"},{\"name\":\"region\",\"type\":\"string\"}]}"}' \
      http://localhost:8081/subjects/transactions-value/versions
    

    As expected, Schema Registry rejects the schema with an error message that it is incompatible:

    {"error_code":409,"message":"Schema being registered is incompatible with an earlier schema"}
    

Passing compatibility checks

To maintain backward compatibility, a new schema must assume default values for the new field if it is not provided.

  1. Consider an updated Payment2b schema that has a default value for region. To view the schema, run this command:

    cat src/main/resources/avro/io/confluent/examples/clients/basicavro/Payment2b.avsc
    

    You should see the following output.

    {
     "namespace": "io.confluent.examples.clients.basicavro",
     "type": "record",
     "name": "Payment",
     "fields": [
         {"name": "id", "type": "string"},
         {"name": "amount", "type": "double"},
         {"name": "region", "type": "string", "default": ""}
     ]
    }
    
  2. From UI, click the transactions topic and go to the Schema tab to retrieve the transactions topic’s latest schema from Schema Registry.

  3. Click Edit Schema.

    ../_images/tutorial-c3-edit-schema.png
  4. Add the new field region again, this time including the default value as shown below, then click Save.

    {
     "name": "region",
     "type": "string",
     "default": ""
    }
    
  5. Verify that the new schema is accepted.

    ../_images/tutorial-c3-edit-schema-pass.png

    Note

    If you get error messages about invalid Avro, check syntax; for example, quotes and colons, enclosing brackets, comma-separated from the previous field, and so on.)

  6. Think about the registered schema versions. The Schema Registry subject for the topic transactions that is called transactions-value has two schemas:

    • version 1 is Payment.avsc

    • version 2 is Payment2b.avsc that has the additional field for region with a default empty value.

  7. In the UI, still on the Schema tab for the topic transactions, click Version history and select Turn on version diff to compare the two versions:

    ../_images/tutorial-c3-schema-compare.png
  8. At the command line, go back to the Schema Registry Maven Plugin, update the pom.xml to refer to Payment2b.avsc instead of Payment2a.avsc.

  9. Re-run the compatibility check and verify that it passes:

    mvn io.confluent:kafka-schema-registry-maven-plugin:test-compatibility
    
  10. Verify that get this message showing that the schema passed the compatibility check.

    ...
    [INFO] Schema examples/clients/avro/src/main/resources/avro/io/confluent/examples/clients/basicavro/Payment2b.avsc is compatible with subject(transactions-value)
    ...
    
  1. Run the following command to register the new schema Payment2b directly through the Schema Registry REST endpoint:

    curl -X POST -H "Content-Type: application/vnd.schemaregistry.v1+json" \
      --data '{"schema": "{\"type\":\"record\",\"name\":\"Payment\",\"namespace\":\"io.confluent.examples.clients.basicavro\",\"fields\":[{\"name\":\"id\",\"type\":\"string\"},{\"name\":\"amount\",\"type\":\"double\"},{\"name\":\"region\",\"type\":\"string\",\"default\":\"\"}]}"}' \
      http://localhost:8081/subjects/transactions-value/versions
    

    If successful, the preceding curl command returns the version id of the new schema:

    {"id":2}
    
  2. View the latest subject for transactions-value in Schema Registry:

    curl --silent -X GET http://localhost:8081/subjects/transactions-value/versions/latest | jq .
    

    This command returns the latest Schema Registry subject for the transactions-value topic, including version number, id, and a description of the schema in JSON:

    {
      "subject": "transactions-value",
      "version": 2,
      "id": 2,
      "schema": "{\"type\":\"record\",\"name\":\"Payment\",\"namespace\":\"io.confluent.examples.clients.basicavro\",\"fields\":[{\"name\":\"id\",\"type\":\"string\"},{\"name\":\"amount\",\"type\":\"double\"},{\"name\":\"region\",\"type\":\"string\",\"default\":\"\"}]}"
    }
    

    Notice the changes:

    • version: changed from 1 to 2

    • id: changed from 1 to 2

    • schema: updated with the new field region that has a default value

Changing compatibility type

The default compatibility type is backward, but you may change it globally or per subject.

To change the compatibility type per subject from the UI, click the transactions topic and go to the Schema tab to retrieve the transactions topic’s latest schema from Schema Registry. Click Edit Schema and then click Compatibility Mode.

../_images/c3-edit-compatibility.png

Notice that the compatibility for this topic is set to the default backward, but you may change this as needed.

Run the following example command to change the compatibility type for the subject transactions-value through the Schema Registry REST endpoint.

curl -X PUT -H "Content-Type: application/vnd.schemaregistry.v1+json" \
       --data '{"compatibility": "BACKWARD_TRANSITIVE"}' \
       http://localhost:8081/config/transactions-value