Skip to content

Commit

Permalink
[Schema Registry] Custom & JSON schema GA (#44472)
Browse files Browse the repository at this point in the history
* initial commit

* lru cache should be internal

* feedback
  • Loading branch information
m-redding authored Jul 1, 2024
1 parent 3bc0e09 commit 250b92c
Show file tree
Hide file tree
Showing 22 changed files with 282 additions and 98 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ namespace Azure.Data.SchemaRegistry
public static Azure.Data.SchemaRegistry.SchemaFormat Avro { get { throw null; } }
public static Azure.Data.SchemaRegistry.SchemaFormat Custom { get { throw null; } }
public static Azure.Data.SchemaRegistry.SchemaFormat Json { get { throw null; } }
public static Azure.Data.SchemaRegistry.SchemaFormat Protobuf { get { throw null; } }
public bool Equals(Azure.Data.SchemaRegistry.SchemaFormat other) { throw null; }
[System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)]
public override bool Equals(object obj) { throw null; }
Expand Down Expand Up @@ -69,16 +68,22 @@ internal SchemaRegistrySchema() { }
public string Definition { get { throw null; } }
public Azure.Data.SchemaRegistry.SchemaProperties Properties { get { throw null; } }
}
public abstract partial class SchemaValidator
{
protected SchemaValidator() { }
public abstract string GenerateSchema(System.Type dataType);
public abstract bool TryValidate(object data, System.Type dataType, string schemaDefinition, out System.Collections.Generic.IEnumerable<System.Exception> validationErrors);
}
}
namespace Azure.Data.SchemaRegistry.Serialization
{
public partial class SchemaRegistrySerializer
{
protected SchemaRegistrySerializer() { }
public SchemaRegistrySerializer(Azure.Data.SchemaRegistry.SchemaRegistryClient client, Azure.Core.SchemaValidator schemaValidator) { }
public SchemaRegistrySerializer(Azure.Data.SchemaRegistry.SchemaRegistryClient client, Azure.Core.SchemaValidator schemaValidator, Azure.Data.SchemaRegistry.Serialization.SchemaRegistrySerializerOptions serializerOptions) { }
public SchemaRegistrySerializer(Azure.Data.SchemaRegistry.SchemaRegistryClient client, string groupName, Azure.Core.SchemaValidator schemaValidator) { }
public SchemaRegistrySerializer(Azure.Data.SchemaRegistry.SchemaRegistryClient client, string groupName, Azure.Core.SchemaValidator schemaValidator, Azure.Data.SchemaRegistry.Serialization.SchemaRegistrySerializerOptions serializerOptions) { }
public SchemaRegistrySerializer(Azure.Data.SchemaRegistry.SchemaRegistryClient client, Azure.Data.SchemaRegistry.SchemaValidator schemaValidator) { }
public SchemaRegistrySerializer(Azure.Data.SchemaRegistry.SchemaRegistryClient client, Azure.Data.SchemaRegistry.SchemaValidator schemaValidator, Azure.Data.SchemaRegistry.Serialization.SchemaRegistrySerializerOptions serializerOptions) { }
public SchemaRegistrySerializer(Azure.Data.SchemaRegistry.SchemaRegistryClient client, Azure.Data.SchemaRegistry.SchemaValidator schemaValidator, string groupName) { }
public SchemaRegistrySerializer(Azure.Data.SchemaRegistry.SchemaRegistryClient client, Azure.Data.SchemaRegistry.SchemaValidator schemaValidator, string groupName, Azure.Data.SchemaRegistry.Serialization.SchemaRegistrySerializerOptions serializerOptions) { }
public object Deserialize(Azure.Messaging.MessageContent content, System.Type dataType, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
public System.Threading.Tasks.ValueTask<object> DeserializeAsync(Azure.Messaging.MessageContent content, System.Type dataType, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
public System.Threading.Tasks.ValueTask<TData> DeserializeAsync<TData>(Azure.Messaging.MessageContent content, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ SchemaRegistrySchema schema = avroClient.GetSchema(schemaId);
string definition = schema.Definition;
```

### Register a Json schema (preview)
### Register a Json schema

Register a Json schema to be stored in the Azure Schema Registry.

Expand Down Expand Up @@ -75,7 +75,7 @@ string definition = @"
Response<SchemaProperties> schemaProperties = jsonClient.RegisterSchema(groupName, name, definition, format);
```

### Retrieve a Json schema (preview)
### Retrieve a Json schema

Retrieve a previously registered schema's content from the Azure Schema Registry with either a schema ID or the group name, schema name, and version. This is the same regardless of schema format.

Expand All @@ -84,7 +84,7 @@ SchemaRegistrySchema schema = jsonClient.GetSchema(schemaId);
string definition = schema.Definition;
```

### Register a custom schema (preview)
### Register a custom schema

Register a custom schema to be stored in the Azure Schema Registry.

Expand All @@ -102,7 +102,7 @@ string definition = @"
Response<SchemaProperties> schemaProperties = customClient.RegisterSchema(groupName, name, definition, format);
```

### Retrieve a custom schema (preview)
### Retrieve a custom schema

Retrieve a previously registered schema's content from the Azure Schema Registry with either a schema ID or the group name, schema name, and version. This is the same regardless of schema format.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ In order to serialize an `EventData` instance with JSON information, you can do

```C# Snippet:SchemaRegistryJsonSerializeEventData
// The serializer serializes into JSON by default
var serializer = new SchemaRegistrySerializer(client, groupName, new SampleJsonValidator());
var serializer = new SchemaRegistrySerializer(client, new SampleJsonValidator(), groupName);

var employee = new Employee { Age = 42, Name = "Caketown" };
EventData eventData = (EventData)await serializer.SerializeAsync(employee, messageType: typeof(EventData));
Expand Down Expand Up @@ -87,7 +87,7 @@ You can also use generic methods to serialize and deserialize the data. This may

```C# Snippet:SchemaRegistryJsonSerializeEventDataGenerics
// The serializer serializes into JSON by default
var serializer = new SchemaRegistrySerializer(client, groupName, new SampleJsonValidator());
var serializer = new SchemaRegistrySerializer(client, new SampleJsonValidator(), groupName);

var employee = new Employee { Age = 42, Name = "Caketown" };
EventData eventData = await serializer.SerializeAsync<EventData, Employee>(employee);
Expand All @@ -113,7 +113,7 @@ It is also possible to serialize and deserialize using `MessageContent`. Use thi

```C# Snippet:SchemaRegistryJsonSerializeDeserializeMessageContent
// The serializer serializes into JSON by default
var serializer = new SchemaRegistrySerializer(client, groupName, new SampleJsonValidator());
var serializer = new SchemaRegistrySerializer(client, new SampleJsonValidator(), groupName);
MessageContent content = await serializer.SerializeAsync<MessageContent, Employee>(employee);

Employee deserializedEmployee = await serializer.DeserializeAsync<Employee>(content);
Expand All @@ -129,7 +129,7 @@ var newtonsoftSerializerOptions = new SchemaRegistrySerializerOptions
{
Serializer = new NewtonsoftJsonObjectSerializer()
};
var newtonsoftSerializer = new SchemaRegistrySerializer(client, groupName, new SampleJsonValidator(), newtonsoftSerializerOptions);
var newtonsoftSerializer = new SchemaRegistrySerializer(client, new SampleJsonValidator(), groupName, newtonsoftSerializerOptions);
```

If you'd like to configure the `JsonObjectSerializer`, you can pass `JsonSerializerOptions` into the 'JsonObjectSerializer`'s constructor:
Expand All @@ -143,7 +143,7 @@ var serializerOptions = new SchemaRegistrySerializerOptions
{
Serializer = new JsonObjectSerializer(jsonSerializerOptions)
};
var serializer = new SchemaRegistrySerializer(client, groupName, new SampleJsonValidator(), serializerOptions);
var serializer = new SchemaRegistrySerializer(client, new SampleJsonValidator(), groupName, serializerOptions);
```

## Troubleshooting
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@

<ItemGroup>
<PackageReference Include="Azure.Core" />
<PackageReference Include="Azure.Core.Experimental" />
</ItemGroup>

<!-- Shared source from Azure.Core -->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,9 @@ namespace Azure.Data.SchemaRegistry
[CodeGenMember("TextPlainCharsetUtf8")]
public static ContentType Custom { get; } = new ContentType(CustomValue);

/// <summary> text/vnd.ms.protobuf. </summary>
[CodeGenMember("TextVndMsProtobuf")]
public static ContentType Protobuf { get; } = new ContentType(ProtobufValue);
///// <summary> text/vnd.ms.protobuf. </summary>
//[CodeGenMember("TextVndMsProtobuf")]
//public static ContentType Protobuf { get; } = new ContentType(ProtobufValue);

/// <inheritdoc />
[EditorBrowsable(EditorBrowsableState.Never)]
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,14 @@

#nullable enable

namespace Azure.Core
namespace Azure.Data.SchemaRegistry
{
/// <summary>
/// A simple LRU cache implementation using a doubly linked list and dictionary.
/// </summary>
/// <typeparam name="TKey">The type of key.</typeparam>
/// <typeparam name="TValue">The type of value.</typeparam>
public class LruCache<TKey, TValue> : IEnumerable<KeyValuePair<TKey, TValue>>
internal class LruCache<TKey, TValue> : IEnumerable<KeyValuePair<TKey, TValue>>
where TKey : notnull
{
private readonly int _capacity;
Expand Down
10 changes: 5 additions & 5 deletions sdk/schemaregistry/Azure.Data.SchemaRegistry/src/SchemaFormat.cs
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,8 @@ public SchemaFormat(string value)
/// <summary> Custom Serialization schema type. </summary>
public static SchemaFormat Custom { get; } = new SchemaFormat(CustomValue);

/// <summary> Protobuf Serialization schema type. </summary>
public static SchemaFormat Protobuf { get; } = new SchemaFormat(ProtobufValue);
///// <summary> Protobuf Serialization schema type. </summary>
//public static SchemaFormat Protobuf { get; } = new SchemaFormat(ProtobufValue);

/// <summary> Determines if two <see cref="SchemaFormat"/> values are the same. </summary>
public static bool operator ==(SchemaFormat left, SchemaFormat right) => left.Equals(right);
Expand Down Expand Up @@ -67,8 +67,8 @@ internal ContentType ToContentType()
return ContentType.Avro;
case JsonValue:
return ContentType.Json;
case ProtobufValue:
return ContentType.Protobuf;
//case ProtobufValue:
// return ContentType.Protobuf;
default:
return ContentType.Custom;
}
Expand All @@ -92,7 +92,7 @@ internal static SchemaFormat FromContentType(string contentTypeValue)
}
return contentSubType[1] switch
{
ProtobufContentType => SchemaFormat.Protobuf,
//ProtobufContentType => SchemaFormat.Protobuf,
_ => SchemaFormat.Custom,
};
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
using System;
using System.Collections.Generic;

namespace Azure.Core
namespace Azure.Data.SchemaRegistry
{
/// <summary>
/// This abstract class allows any available library to be used to generate schemas from .NET types and validate
Expand All @@ -27,22 +27,6 @@ public abstract class SchemaValidator
/// <returns></returns>
public abstract bool TryValidate(object data, Type dataType, string schemaDefinition, out IEnumerable<Exception> validationErrors);

/// <summary>
/// Validates that <paramref name="data"/> is valid according to <paramref name="schemaDefinition"/>. If the object is not valid,
/// this method throws an <see cref="AggregateException"/> containing all of the validation errors.
/// </summary>
/// <param name="data">The data to validate.</param>
/// <param name="dataType">The type of data to validate.</param>
/// <param name="schemaDefinition">The schema definition to validate against.</param>
/// <exception cref="AggregateException"> <paramref name="data"/> is not valid according to the <paramref name="schemaDefinition"/>.</exception>
public virtual void Validate(object data, Type dataType, string schemaDefinition)
{
if (!TryValidate(data, dataType, schemaDefinition, out var errors))
{
throw new AggregateException("The validate method determined the object was invalid according to the schema.", errors);
}
}

/// <summary>
/// Generates a schema from <paramref name="dataType"/> and returns it as a string.
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
// Licensed under the MIT License.

using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
Expand Down Expand Up @@ -38,7 +40,7 @@ public class SchemaRegistrySerializer
/// <param name="client">The <see cref="SchemaRegistryClient"/> instance to use for looking up schemas.</param>
/// <param name="schemaValidator">The instance inherited from <see cref="SchemaValidator"/> to use to generate and validate schemas.</param>
public SchemaRegistrySerializer(SchemaRegistryClient client, SchemaValidator schemaValidator)
: this(client, null, schemaValidator)
: this(client, schemaValidator, groupName: null)
{
}

Expand All @@ -51,7 +53,7 @@ public SchemaRegistrySerializer(SchemaRegistryClient client, SchemaValidator sch
/// <param name="schemaValidator">The instance inherited from <see cref="SchemaValidator"/> to use to generate and validate schemas.</param>
/// <param name="serializerOptions">The set of <see cref="SchemaRegistrySerializerOptions"/> to use when configuring the serializer.</param>
public SchemaRegistrySerializer(SchemaRegistryClient client, SchemaValidator schemaValidator, SchemaRegistrySerializerOptions serializerOptions)
: this(client, null, schemaValidator, serializerOptions)
: this(client, schemaValidator, null, serializerOptions)
{
}

Expand All @@ -62,8 +64,8 @@ public SchemaRegistrySerializer(SchemaRegistryClient client, SchemaValidator sch
/// <param name="client">The <see cref="SchemaRegistryClient"/> instance to use for looking up schemas.</param>
/// <param name="groupName">The Schema Registry group name that contains the schemas that will be used to serialize.</param>
/// <param name="schemaValidator">The instance inherited from <see cref="SchemaValidator"/> to use to generate and validate schemas.</param>
public SchemaRegistrySerializer(SchemaRegistryClient client, string groupName, SchemaValidator schemaValidator)
: this(client, groupName, schemaValidator, default)
public SchemaRegistrySerializer(SchemaRegistryClient client, SchemaValidator schemaValidator, string groupName)
: this(client, schemaValidator, groupName, default)
{
}

Expand All @@ -75,7 +77,7 @@ public SchemaRegistrySerializer(SchemaRegistryClient client, string groupName, S
/// <param name="groupName">The Schema Registry group name that contains the schemas that will be used to serialize.</param>
/// <param name="schemaValidator">The instance inherited from <see cref="SchemaValidator"/> to use to generate and validate schemas.</param>
/// <param name="serializerOptions">The set of <see cref="SchemaRegistrySerializerOptions"/> to use when configuring the serializer.</param>
public SchemaRegistrySerializer(SchemaRegistryClient client, string groupName, SchemaValidator schemaValidator, SchemaRegistrySerializerOptions serializerOptions)
public SchemaRegistrySerializer(SchemaRegistryClient client, SchemaValidator schemaValidator, string groupName, SchemaRegistrySerializerOptions serializerOptions)
{
_client = client ?? throw new ArgumentNullException(nameof(client));
_groupName = groupName;
Expand Down Expand Up @@ -299,7 +301,11 @@ internal async ValueTask<MessageContent> SerializeInternalAsync(
}

// Attempt to validate
_schemaValidator.Validate(value, dataType, schemaString);
var isValid = _schemaValidator.TryValidate(value, dataType, schemaString, out var validationErrors);
if (!isValid)
{
throw new AggregateException(validationErrors);
}

try
{
Expand All @@ -315,7 +321,7 @@ internal async ValueTask<MessageContent> SerializeInternalAsync(
}
catch (Exception ex) when (ex is not RequestFailedException)
{
throw new Exception("An error occured while attempting to get the Id for the schema.", ex);
throw new Exception("An error occurred while attempting to get the Id for the schema.", ex);
}
}

Expand Down Expand Up @@ -516,7 +522,11 @@ private async ValueTask<object> DeserializeInternalAsync(
}

// Attempt to validate
_schemaValidator.Validate(objectToReturn, dataType, schemaDefinition);
var isValid = _schemaValidator.TryValidate(objectToReturn, dataType, schemaDefinition, out var validationErrors);
if (!isValid)
{
throw new AggregateException(validationErrors);
}

return objectToReturn;
}
Expand Down
Loading

0 comments on commit 250b92c

Please sign in to comment.