Schema Registry
Surgewave includes a Confluent-compatible Schema Registry.
Overview
Schema Registry manages schemas for:
- Avro - Apache Avro schemas
- JSON Schema - JSON-based schemas
- Protobuf - Protocol Buffers
- FlatBuffers - Memory-efficient serialization
Configuration
{
"Surgewave": {
"SchemaRegistry": {
"Enabled": true,
"DataPath": "./data/schemas",
"DefaultCompatibility": "Backward"
}
}
}
| Option | Type | Default | Description |
|---|---|---|---|
Enabled |
bool | false | Enable Schema Registry |
DataPath |
string | ./data/schemas | Path to store schema data |
DefaultCompatibility |
string | Backward | Default compatibility for new subjects |
CLI Usage
List Subjects
surgewave schema list
surgewave schema list --include-deleted
Register Schema
# Avro from string
surgewave schema register user-value --schema '{
"type": "record",
"name": "User",
"fields": [
{"name": "id", "type": "int"},
{"name": "name", "type": "string"},
{"name": "email", "type": "string"}
]
}'
# From file
surgewave schema register user-value --file user.avsc --type AVRO
surgewave schema register events-value --file events.proto --type PROTOBUF
Describe Subject
surgewave schema describe user-value
Get Schema
surgewave schema get --id 1
surgewave schema get --subject user-value --version latest
surgewave schema get --subject user-value --version 2
Compatibility
# Check before registering
surgewave schema compatibility check user-value --file new-user.avsc
# Get current level
surgewave schema compatibility get --subject user-value
# Set compatibility
surgewave schema compatibility set BACKWARD --subject user-value
Delete
surgewave schema delete-subject user-value
surgewave schema delete-version user-value 1
Compatibility Levels
| Level | Description |
|---|---|
| NONE | No compatibility checking |
| BACKWARD | New can read old |
| FORWARD | Old can read new |
| FULL | Both backward and forward |
| BACKWARD_TRANSITIVE | Backward with all versions |
| FORWARD_TRANSITIVE | Forward with all versions |
| FULL_TRANSITIVE | Full with all versions |
REST API
| Endpoint | Method | Description |
|---|---|---|
/subjects |
GET | List all subjects |
/subjects/{subject}/versions |
GET | List versions |
/subjects/{subject}/versions |
POST | Register schema |
/subjects/{subject}/versions/{version} |
GET | Get schema |
/schemas/ids/{id} |
GET | Get by ID |
/config |
GET/PUT | Global config |
/config/{subject} |
GET/PUT | Subject config |
/compatibility/subjects/{subject}/versions/{version} |
POST | Check compatibility |
Client Usage
.NET Producer
using Kuestenlogik.Surgewave.Client;
using Kuestenlogik.Surgewave.Schema.Registry.Serdes.Avro;
await using var producer = new SurgewaveProducer<string, User>(options =>
{
options.BootstrapServers = "localhost:9092";
options.AsyncValueSerializer = new SchemaRegistryAvroSerializer<User>(
new AvroSerializerConfig
{
SchemaRegistryUrl = "https://localhost:9093"
});
});
await producer.ProduceAsync("users", "user-1", new User { Id = 1, Name = "Alice" });
.NET Consumer
await using var consumer = new SurgewaveConsumer<string, User>(options =>
{
options.BootstrapServers = "localhost:9092";
options.GroupId = "user-processor";
options.AsyncValueDeserializer = new SchemaRegistryAvroDeserializer<User>(
new AvroSerializerConfig
{
SchemaRegistryUrl = "https://localhost:9093"
});
});
consumer.Subscribe("users");
while (true)
{
var record = await consumer.ConsumeAsync();
if (record != null)
Console.WriteLine($"User: {record.Value.Name}");
}
Schema Types
Avro
{
"type": "record",
"name": "Order",
"namespace": "com.example",
"fields": [
{"name": "id", "type": "long"},
{"name": "customerId", "type": "string"},
{"name": "amount", "type": "double"},
{"name": "status", "type": {"type": "enum", "name": "Status", "symbols": ["PENDING", "COMPLETED"]}}
]
}
JSON Schema
{
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
"properties": {
"id": {"type": "integer"},
"name": {"type": "string"},
"email": {"type": "string", "format": "email"}
},
"required": ["id", "name"]
}
Protobuf
syntax = "proto3";
package example;
message User {
int32 id = 1;
string name = 2;
string email = 3;
}
Additional Formats
Surgewave supports 8 additional serialization formats via Schema Registry handlers:
| Format | Type Name | Content Type | Use Case |
|---|---|---|---|
| Hyperion | HYPERION | application/x-hyperion | Akka.NET integration |
| MessagePack | MSGPACK | application/x-msgpack | High-performance .NET (SignalR) |
| CBOR | CBOR | application/cbor | IoT (CoAP/MQTT) |
| Bond | BOND | application/x-bond | Microsoft/Azure |
| Thrift | THRIFT | application/x-thrift | Apache/Meta |
| MemoryPack | MEMORYPACK | application/x-memorypack | Ultra-fast .NET |
| Cap'n Proto | CAPNPROTO | application/x-capnproto | Zero-copy RPC |
| Orleans | ORLEANS | application/x-orleans | Microsoft Orleans Grains |
Schemaless formats (Hyperion, MessagePack, CBOR, MemoryPack, Orleans) use the type name as a hint. Schema-based formats (Bond, Thrift, Cap'n Proto) support schema validation and compatibility checking.
All formats use the Confluent wire format: [0x00][4-byte schema ID][payload].
Best Practices
- Use Backward Compatibility - Consumers can handle new data
- Add Optional Fields - Never remove or rename required fields
- Version Subjects - Use
-valueand-keysuffixes - Cache Schemas - Use
CachedSchemaRegistryClient
Next Steps
- Transactions - Exactly-once semantics
- Clients - Client integration