Repository: hamba/avro
Pull request #536 (2025-05-12 19:35:39)

feat(registry): add schema metadata properties to schema info
## Goal of this PR

Confluent Schema Registry supports tags, metadata, and rules, which together support the concept of a [Data Contract](https://docs.confluent.io/platform/7.9/schema-registry/fundamentals/data-contracts.html).

This change adds support only for [metadata properties](https://docs.confluent.io/platform/7.9/schema-registry/fundamentals/data-contracts.html#metadata-properties) that may include arbitrary information about the schema, such as who created it:

```json
{
  "schema": "...",
  "metadata": {
    "properties": {
      "owner": "Bob Jones",
      "email": "bob@acme.com"
    }
  }
}
```

Properties may also include [major schema version](https://docs.confluent.io/platform/7.9/schema-registry/fundamentals/data-contracts.html#application-major-versioning) to highlight incompatible changes throughout the schema history:

```json
{
  "schema": "...",
  "metadata": {
    "properties": {
      "application.major.version": "2"
    }
  }
}
```

## How did I test it?

Added new test case.



Patch:
diff --git a/registry/client.go b/registry/client.go
index a6e9981..9f8c040 100644
--- a/registry/client.go
+++ b/registry/client.go
@@ -82,9 +82,14 @@ type credentials struct {
 }
 
 type schemaInfoPayload struct {
-	Schema  string `json:"schema"`
-	ID      int    `json:"id"`
-	Version int    `json:"version"`
+	Schema   string         `json:"schema"`
+	ID       int            `json:"id"`
+	Version  int            `json:"version"`
+	Metadata schemaMetadata `json:"metadata"`
+}
+
+type schemaMetadata struct {
+	Properties map[string]string `json:"properties"`
 }
 
 // Parse converts the string schema registry response into a
@@ -93,6 +98,9 @@ func (s *schemaInfoPayload) Parse() (info SchemaInfo, err error) {
 	info = SchemaInfo{
 		ID:      s.ID,
 		Version: s.Version,
+		Metadata: SchemaMetadata{
+			Properties: s.Metadata.Properties,
+		},
 	}
 	info.Schema, err = avro.Parse(s.Schema)
 	return info, err
@@ -100,9 +108,15 @@ func (s *schemaInfoPayload) Parse() (info SchemaInfo, err error) {
 
 // SchemaInfo represents a schema and metadata information.
 type SchemaInfo struct {
-	Schema  avro.Schema
-	ID      int
-	Version int
+	Schema   avro.Schema
+	ID       int
+	Version  int
+	Metadata SchemaMetadata
+}
+
+// SchemaMetadata represents the schema metadata.
+type SchemaMetadata struct {
+	Properties map[string]string
 }
 
 var defaultClient = &http.Client{


Test patch:
diff --git a/registry/client_test.go b/registry/client_test.go
index 8363c9a..74e35b8 100644
--- a/registry/client_test.go
+++ b/registry/client_test.go
@@ -364,6 +364,26 @@ func TestClient_GetSchemaInfo(t *testing.T) {
 	assert.Equal(t, 1, schemaInfo.Version)
 }
 
+func TestClient_GetSchemaInfoWithMetadata(t *testing.T) {
+	s := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+		assert.Equal(t, "GET", r.Method)
+		assert.Equal(t, "/subjects/foobar/versions/1", r.URL.Path)
+
+		_, _ = w.Write([]byte(`{"subject": "foobar", "version": 1, "id": 2, "metadata": {"properties": {"foo": "bar", "baz": "quux"}}, "schema":"[\"null\",\"string\",\"int\"]"}`))
+	}))
+	t.Cleanup(s.Close)
+	client, _ := registry.NewClient(s.URL)
+
+	schemaInfo, err := client.GetSchemaInfo(context.Background(), "foobar", 1)
+
+	require.NoError(t, err)
+	assert.Equal(t, `["null","string","int"]`, schemaInfo.Schema.String())
+	assert.Equal(t, 2, schemaInfo.ID)
+	assert.Equal(t, 1, schemaInfo.Version)
+	assert.Equal(t, "bar", schemaInfo.Metadata.Properties["foo"])
+	assert.Equal(t, "quux", schemaInfo.Metadata.Properties["baz"])
+}
+
 func TestClient_GetSchemaInfoRequestError(t *testing.T) {
 	s := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 		w.WriteHeader(500)