Skip to content

Serialize & Deserialize should have access to headers #1074

@adminnz

Description

@adminnz

Proposed change

Provide the NatsHeaders to the Deserialize method.

public interface INatsDeserialize<out T>
{
    T? Deserialize(in ReadOnlySequence<byte> buffer, NatsHeaders? headers);
}

Provide the ability for the Serialize to provide the headers for the serialized payload.

public interface INatsSerialize<in T>
{
    void Serialize(IBufferWriter<byte> bufferWriter, T value, out NatsHeaders? headers);
}

Use case

  • If an endpoint wants to handle $SYS.REQ.USER.AUTH request messages that have encrypted contents, you need access to the headers to correctly deserialize to a NatsAuthorizationRequestClaims.
  • A consumer might need access to a header to understand the version of a message, encoding, etc.

The current INatsDeserialize interface only gives you the payload bytes, and so there is no way (that i can see) to implement a clean message handler when you need header information for deserializing.

This would improve the code readability and maintainability, and allow it to be implemented like other "simple" messages.

Because currently the code for $SYS.REQ.USER.AUTH would have to do:

await _svcServer.AddEndpointAsync<byte[]>(HandleMessage, subject: "$SYS.REQ.USER.AUTH");

async ValueTask HandleMessage(NatsSvcMsg<byte[]> message)
{
var request = DecodeMessage(message);
/// handle request
}

NatsAuthorizationRequest DecodeMessage(NatsSvcMsg<byte[]> message)
{
    string jwt;
    if (message.Headers.TryGetValue("Nats-Server-Xkey", out var serverKey))
    {
        var encryptionKeyPair = FindEncryptionKey(serverKey);
        var decrypted = encryptionKeyPair.Open(message.Data);
        jwt = Encoding.ASCII.GetString(decrypted);
    }
    else
    {
        jwt = Encoding.ASCII.GetString(message.Data);
    }
     var arc = NatsJwt.DecodeClaims<NatsAuthorizationRequestClaims>(jwt);
    return arc.AuthorizationRequest;

}

If the headers were available, it would allow for Serialization/Deserialization to be handled the same way other "simple" messages are.

await _svcServer.AddEndpointAsync<NatsAuthorizationRequest>(HandleMessage, subject: "$SYS.REQ.USER.AUTH", serializer: new NatsAuthorizationRequestDeserializer());

async ValueTask HandleMessage(NatsSvcMsg<NatsAuthorizationRequest> message)
{
    var request = message.Data;
    //handle request
}

class NatsAuthorizationRequestDeserializer: INatsDeserialize<NatsAuthorizationRequest>
{
    public T? Deserialize(in ReadOnlySequence<byte> buffer, NatsHeaders? headers)
    {
        string jwt;
        if (headers.TryGetValue("Nats-Server-Xkey", out var serverKey))
        {
            var encryptionKeyPair = FindEncryptionKey(serverKey);
            var decrypted = encryptionKeyPair.Open(buffer);
            jwt = Encoding.ASCII.GetString(decrypted);
        }
        else
        {
            jwt = Encoding.ASCII.GetString(buffer);
        }
         var arc = NatsJwt.DecodeClaims<NatsAuthorizationRequestClaims>(jwt);
        return arc.AuthorizationRequest;
    }
}

Contribution

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions