nats.net icon indicating copy to clipboard operation
nats.net copied to clipboard

[PROPOSAL] Make ad-hoc JSON Serialization the Default with INatsClient and Make INatsConnection a low-level API

Open mtmk opened this issue 8 months ago • 7 comments

Proposed change

(1) Add NATS.Client.Serializers.Json to NATS.Net main package and NATS.Extensions.Microsoft.DependencyInjection package then add the ad-hoc serialization to the default serialization registry without breaking the AOT compilation (i.e. compile without trimming warnings) for the rest of the packages. Applications requiring AOT compilation will have to reference packages individually, which is usually the case in the examples I saw out there in the wild.

(2) To achieve this, we need to provide an abstraction over NatsConnection. Changing the existing NatsConnection and default NatsOpts would make the NATS.Client.Core project not AOT-friendly. Hence, we have to introduce a new thin abstraction over NatsConnection, which can be implemented in the NATS.Net package:

// wire-up Raw + Primitive + ad-hoc JSON serializers
// in a new serializer registry
await using var client = NatsClient();

// Only expose high level APIs but provide full functionality
await client.PublishAsync();
await foreach(var msg in client.SubscribeAsync()) {}

INatsConnection connection = client.Connection;

(3) With this we make INatsConnection a low level API giving us a chance to open up some of the calls which were marked as internal. This will give us a chance to write the mistakes of having JetStream, KV, Object store and services packages depending on core internals. We should aim to remove all internal access to core, including the tests.

Use case

Most applications does not require highly optimized generated serialization suitable for AOT compilations. Developers new to NATS .NET frequently get confused about serialization options when they first start using it. Having ad-hoc JSON serialization also provides a more progressive pathway to gradually increased feature set and complexity as the application requirements evolve.

  • Enable new developers pick up NATS .NET quickly.
  • Constructing the client with new NatsClient() is arguably more intuitive and similar to how other APIs work e.g. HttpClient
  • Serialization does the expected thing for most commonly used types such as byte[], Memory<byte>, string, int, etc. then all the custom types applications use as DTOs, falling back to JSON serialization automatically.
  • For applications using AOT, developers can still use individual packages.
  • When an application evolves to need lower level APIs, NatsClient can be swapped out with NatsConnection with little to no code change since NatsClient would only have a subset of NatsConnection interface.

mtmk avatar May 29 '24 18:05 mtmk