Repository: hamba/avro
Pull request #546 (2025-06-11 11:09:07)

adding support for is-compatible-schema endpoint
## Goal of this PR

Adding support for is-compatible-schema endpoint

Closes https://github.com/hamba/avro/issues/547

## How did I test it?

With unit tests



Patch:
diff --git a/registry/client.go b/registry/client.go
index 9f8c040..e2fdd29 100644
--- a/registry/client.go
+++ b/registry/client.go
@@ -58,6 +58,13 @@ type Registry interface {
 
 	// IsRegisteredWithRefs determines if the schema is registered, with optional referenced schemas.
 	IsRegisteredWithRefs(ctx context.Context, subject, schema string, refs ...SchemaReference) (int, avro.Schema, error)
+
+	// IsCompatible determines if the schema is compatible with all schemas in the subject.
+	IsCompatible(ctx context.Context, subject, schema string) (bool, error)
+
+	// IsCompatibleWithRefs determines if the schema is compatible with all schemas in the subject,
+	// with optional referenced schemas.
+	IsCompatibleWithRefs(ctx context.Context, subject, schema string, refs ...SchemaReference) (bool, error)
 }
 
 type schemaPayload struct {
@@ -314,6 +321,32 @@ func (c *Client) IsRegisteredWithRefs(
 	return resp.ID, sch, err
 }
 
+type isCompatibleResponse struct {
+	IsCompatible bool `json:"is_compatible"`
+}
+
+// IsCompatible determines if the schema is compatible with all schemas in the subject.
+func (c *Client) IsCompatible(ctx context.Context, subject, schema string) (bool, error) {
+	return c.IsCompatibleWithRefs(ctx, subject, schema)
+}
+
+// IsCompatibleWithRefs determines if the schema is compatible with all schemas in the subject,
+// with optional referenced schemas.
+func (c *Client) IsCompatibleWithRefs(
+	ctx context.Context,
+	subject,
+	schema string,
+	references ...SchemaReference,
+) (bool, error) {
+	req := schemaPayload{Schema: schema, References: references}
+	reqPath := path.Join("compatibility", "subjects", subject, "versions")
+	var resp isCompatibleResponse
+	if err := c.request(ctx, http.MethodPost, reqPath, req, &resp); err != nil {
+		return false, err
+	}
+	return resp.IsCompatible, nil
+}
+
 // Compatibility levels.
 const (
 	BackwardCL           string = "BACKWARD"


Test patch:
diff --git a/registry/client_test.go b/registry/client_test.go
index 74e35b8..33be708 100644
--- a/registry/client_test.go
+++ b/registry/client_test.go
@@ -761,6 +761,86 @@ func TestClient_SetCompatibilityLevelHandlesInvalidLevel(t *testing.T) {
 	assert.Error(t, err)
 }
 
+func TestClient_IsCompatible(t *testing.T) {
+	subject := "test_subject"
+	s := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+		assert.Equal(t, "POST", r.Method)
+		assert.Equal(t, "/compatibility/subjects/"+subject+"/versions", r.URL.Path)
+
+		body, err := io.ReadAll(r.Body)
+		require.NoError(t, err)
+		var decoded map[string]any
+		err = json.Unmarshal(body, &decoded)
+		require.NoError(t, err)
+
+		assert.Contains(t, decoded, "schema")
+		schema, ok := decoded["schema"].(string)
+		require.True(t, ok)
+		require.Equal(t, schema, "[\"null\",\"string\",\"int\"]")
+
+		_, _ = w.Write([]byte(`{"is_compatible":true}`))
+	}))
+	t.Cleanup(s.Close)
+	client, _ := registry.NewClient(s.URL)
+
+	isCompatible, err := client.IsCompatible(
+		context.Background(),
+		"test_subject",
+		"[\"null\",\"string\",\"int\"]",
+	)
+
+	require.NoError(t, err)
+	assert.Equal(t, true, isCompatible)
+}
+
+func TestClient_IsCompatibleWithRefs(t *testing.T) {
+	subject := "test_subject"
+	s := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+		assert.Equal(t, "POST", r.Method)
+		assert.Equal(t, "/compatibility/subjects/"+subject+"/versions", r.URL.Path)
+
+		body, err := io.ReadAll(r.Body)
+		require.NoError(t, err)
+		var decoded map[string]any
+		err = json.Unmarshal(body, &decoded)
+		require.NoError(t, err)
+
+		assert.Contains(t, decoded, "schema")
+		schema, ok := decoded["schema"].(string)
+		require.True(t, ok)
+		require.Equal(t, schema, "[\"null\",\"string\",\"int\"]")
+
+		assert.Contains(t, decoded, "references")
+		refs, ok := decoded["references"].([]any)
+		require.True(t, ok)
+		require.Len(t, refs, 1)
+		ref, ok := refs[0].(map[string]any)
+		require.True(t, ok)
+
+		assert.Equal(t, "some_schema", ref["name"].(string))
+		assert.Equal(t, "some_subject", ref["subject"].(string))
+		assert.Equal(t, float64(3), ref["version"].(float64))
+
+		_, _ = w.Write([]byte(`{"is_compatible":true}`))
+	}))
+	t.Cleanup(s.Close)
+	client, _ := registry.NewClient(s.URL)
+
+	isCompatible, err := client.IsCompatibleWithRefs(
+		context.Background(),
+		"test_subject",
+		"[\"null\",\"string\",\"int\"]",
+		registry.SchemaReference{
+			Name:    "some_schema",
+			Subject: "some_subject",
+			Version: 3,
+		},
+	)
+
+	require.NoError(t, err)
+	assert.Equal(t, true, isCompatible)
+}
+
 func TestClient_HandlesServerError(t *testing.T) {
 	s := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {}))
 	s.Close()