From ed30a2d87bbd7a9ecfca632224f92023c1cfc303 Mon Sep 17 00:00:00 2001 From: VisualBean Date: Sun, 25 May 2025 22:51:04 +0200 Subject: [PATCH 1/5] update readme for V3 --- README.md | 92 +++++++++++++++++++++++-------------------------------- 1 file changed, 38 insertions(+), 54 deletions(-) diff --git a/README.md b/README.md index cdb2b2c..b92fd09 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ V3 is currently in pre-release - so grab that if you need V3 [Wiki and getting started guide](https://github.com/ByteBardOrg/AsyncAPI.NET/wiki) ## Installation -Generally you wan't to use Readers and Bindings. +Generally you want to use Readers and Bindings. They have however been split to allow for different scenarios without polluting with unnecesary packages. Install the NuGet packages: @@ -38,59 +38,43 @@ Main classes to know: ## Writing ```csharp - var myFirstAsyncApi = new AsyncApiDocument - { - Info = new AsyncApiInfo - { - Title = "my first asyncapi", - }, - Channels = new Dictionary - { - { - "users", new AsyncApiChannel - { - Subscribe = new AsyncApiOperation - { - OperationId = "users", - Description = "my users channel", - Message = new List - { - new AsyncApiMessageReference("#/components/messages/MyMessage"), - }, - }, - } - }, - }, - Components = new AsyncApiComponents - { - Messages = new Dictionary - { - { - "MyMessage", new AsyncApiMessage - { - Name = "Hello!", - } - }, - }, - }, - }; - -var yaml = myFirstAsyncApi.SerializeAsYaml(AsyncApi); - -//asyncapi: 2.6.0 -// info: -// title: my first asyncapi -//channels: -// users: -// subscribe: -// operationId: users -// description: my users channel -// message: -// $ref: '#/components/messages/MyMessage' -//components: -// messages: -// MyMessage: -// name: Hello! +var specification = +""" +asyncapi: 3.0.0 +info: + title: UsersAPI + version: 1.0.0 + externalDocs: + description: Find more info here + url: https://www.asyncapi.com + tags: + - name: e-commerce +servers: + production: + host: "rabbitmq.in.mycompany.com:5672" + pathname: "/production" + protocol: "amqp" +channels: + UserSignup: + address: "user/signedup" + messages: + UserMessage: + payload: + type: object + properties: + displayName: + type: string + description: Name of the user +operations: + ConsumeUserSignups: + action: receive + channel: + $ref: "#/channels/UserSignup" +"""; +var reader = new AsyncApiStringReader(); +var document = reader.Read(specification, out var diagnostics); +var v2Document = document.SerializeAsYaml(AsyncApiVersion.AsyncApi2_0); +var v3Document = document.SerializeAsJson(AsyncApiVersion.AsyncApi3_0); ``` From 13ac13fb7ee2e3aad6597c2e9891e2ba7df7787c Mon Sep 17 00:00:00 2001 From: VisualBean Date: Sun, 25 May 2025 23:49:33 +0200 Subject: [PATCH 2/5] message inference for V2 --- .../Models/AsyncApiOperation.cs | 8 +- .../AsyncApiDocumentV3Tests.cs | 177 ++++++++++++++++++ 2 files changed, 182 insertions(+), 3 deletions(-) diff --git a/src/ByteBard.AsyncAPI/Models/AsyncApiOperation.cs b/src/ByteBard.AsyncAPI/Models/AsyncApiOperation.cs index eef4788..77c0c0a 100644 --- a/src/ByteBard.AsyncAPI/Models/AsyncApiOperation.cs +++ b/src/ByteBard.AsyncAPI/Models/AsyncApiOperation.cs @@ -91,16 +91,18 @@ public virtual void SerializeV2(IAsyncApiWriter writer) writer.WriteOptionalObject(AsyncApiConstants.Bindings, this.Bindings, (w, t) => t.SerializeV2(w)); writer.WriteOptionalCollection(AsyncApiConstants.Traits, this.Traits, (w, t) => t.SerializeV2(w)); - if (this.Messages.Count > 1) + IEnumerable messages = this.Messages.Any() ? this.Messages : this.Channel.Messages.Values; + + if (messages.Count() > 1) { writer.WritePropertyName(AsyncApiConstants.Message); writer.WriteStartObject(); - writer.WriteOptionalCollection(AsyncApiConstants.OneOf, this.Messages, (w, t) => t.SerializeV2(w)); + writer.WriteOptionalCollection(AsyncApiConstants.OneOf, messages, (w, t) => t.SerializeV2(w)); writer.WriteEndObject(); } else { - writer.WriteOptionalObject(AsyncApiConstants.Message, this.Messages.FirstOrDefault(), (w, m) => m.SerializeV2(w)); + writer.WriteOptionalObject(AsyncApiConstants.Message, messages.FirstOrDefault(), (w, m) => m.SerializeV2(w)); } writer.WriteExtensions(this.Extensions); diff --git a/test/ByteBard.AsyncAPI.Tests/AsyncApiDocumentV3Tests.cs b/test/ByteBard.AsyncAPI.Tests/AsyncApiDocumentV3Tests.cs index 9042997..3b764cb 100644 --- a/test/ByteBard.AsyncAPI.Tests/AsyncApiDocumentV3Tests.cs +++ b/test/ByteBard.AsyncAPI.Tests/AsyncApiDocumentV3Tests.cs @@ -1,5 +1,8 @@ namespace ByteBard.AsyncAPI.Tests { + using System; + using System.Collections.Concurrent; + using System.Collections.Generic; using FluentAssertions; using ByteBard.AsyncAPI.Bindings; using ByteBard.AsyncAPI.Models; @@ -230,5 +233,179 @@ public void V3_WithComplexInput_CanReSerialize() diagnostics.Warnings.Should().BeEmpty(); reserialized.Should().BePlatformAgnosticEquivalentTo(expected); } + + [Test] + public void V3_SerializeV2_WithNoMessageReference_SerializesChannelMessagesOneOf() + { + var expected = + """ + asyncapi: 2.6.0 + info: + title: my first asyncapi + version: 1.0.0 + channels: + user/signedUp: + publish: + message: + oneOf: + - payload: + type: object + properties: + displayName: + type: string + description: Name of the user + - payload: + type: object + properties: + displayName: + type: string + description: Name of the user + """; + var myFirstAsyncApi = new AsyncApiDocument + { + Info = new AsyncApiInfo + { + Title = "my first asyncapi", + Version = "1.0.0", + }, + Channels = new Dictionary + { + { + "UserSignup", new AsyncApiChannel + { + Address = "user/signedUp", + Messages = new Dictionary() + { + { + "UserMessage", new AsyncApiMessage + { + Payload = new AsyncApiJsonSchema() + { + Type = SchemaType.Object, + Properties = new Dictionary() + { + { + "displayName", new AsyncApiJsonSchema() + { + Type = SchemaType.String, + Description = "Name of the user", + } + }, + }, + }, + } + }, + { + "OtherUserMessage", new AsyncApiMessage + { + Payload = new AsyncApiJsonSchema() + { + Type = SchemaType.Object, + Properties = new Dictionary() + { + { + "displayName", new AsyncApiJsonSchema() + { + Type = SchemaType.String, + Description = "Name of the user", + } + }, + }, + }, + } + }, + }, + } + }, + }, + Operations = new Dictionary() + { + { + "ConsumerUserSignups", new AsyncApiOperation + { + Action = AsyncApiAction.Receive, + Channel = new AsyncApiChannelReference("#/channels/UserSignup"), + } + }, + }, + }; + + var yamlV2 = myFirstAsyncApi.SerializeAsYaml(AsyncApiVersion.AsyncApi2_0); + yamlV2.Should().BeEquivalentTo(expected); + } + + [Test] + public void V3_SerializeV2_WithNoMessageReference_SerializesChannelMessage() + { + var expected = + """ + asyncapi: 2.6.0 + info: + title: my first asyncapi + version: 1.0.0 + channels: + user/signedUp: + publish: + message: + payload: + type: object + properties: + displayName: + type: string + description: Name of the user + """; + var myFirstAsyncApi = new AsyncApiDocument + { + Info = new AsyncApiInfo + { + Title = "my first asyncapi", + Version = "1.0.0", + }, + Channels = new Dictionary + { + { + "UserSignup", new AsyncApiChannel + { + Address = "user/signedUp", + Messages = new Dictionary() + { + { + "UserMessage", new AsyncApiMessage + { + Payload = new AsyncApiJsonSchema() + { + Type = SchemaType.Object, + Properties = new Dictionary() + { + { + "displayName", new AsyncApiJsonSchema() + { + Type = SchemaType.String, + Description = "Name of the user", + } + }, + }, + }, + } + }, + }, + } + }, + }, + Operations = new Dictionary() + { + { + "ConsumerUserSignups", new AsyncApiOperation + { + Action = AsyncApiAction.Receive, + Channel = new AsyncApiChannelReference("#/channels/UserSignup"), + } + }, + }, + }; + + var yamlV2 = myFirstAsyncApi.SerializeAsYaml(AsyncApiVersion.AsyncApi2_0); + yamlV2.Should().BeEquivalentTo(expected); + } } } From 483676eaa077a99355176827af016c550ae45786 Mon Sep 17 00:00:00 2001 From: VisualBean Date: Mon, 26 May 2025 00:00:19 +0200 Subject: [PATCH 3/5] remove test test --- test/ByteBard.AsyncAPI.Tests/AsyncApiDocumentV3Tests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/ByteBard.AsyncAPI.Tests/AsyncApiDocumentV3Tests.cs b/test/ByteBard.AsyncAPI.Tests/AsyncApiDocumentV3Tests.cs index 3b764cb..e3b13bb 100644 --- a/test/ByteBard.AsyncAPI.Tests/AsyncApiDocumentV3Tests.cs +++ b/test/ByteBard.AsyncAPI.Tests/AsyncApiDocumentV3Tests.cs @@ -233,7 +233,7 @@ public void V3_WithComplexInput_CanReSerialize() diagnostics.Warnings.Should().BeEmpty(); reserialized.Should().BePlatformAgnosticEquivalentTo(expected); } - + [Test] public void V3_SerializeV2_WithNoMessageReference_SerializesChannelMessagesOneOf() { From f6b4a6ee016439580526eac208ac5ffd5bf2b85c Mon Sep 17 00:00:00 2001 From: VisualBean Date: Mon, 26 May 2025 00:02:32 +0200 Subject: [PATCH 4/5] fix null ref --- src/ByteBard.AsyncAPI/Models/AsyncApiOperation.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/ByteBard.AsyncAPI/Models/AsyncApiOperation.cs b/src/ByteBard.AsyncAPI/Models/AsyncApiOperation.cs index 77c0c0a..d7ea083 100644 --- a/src/ByteBard.AsyncAPI/Models/AsyncApiOperation.cs +++ b/src/ByteBard.AsyncAPI/Models/AsyncApiOperation.cs @@ -91,9 +91,9 @@ public virtual void SerializeV2(IAsyncApiWriter writer) writer.WriteOptionalObject(AsyncApiConstants.Bindings, this.Bindings, (w, t) => t.SerializeV2(w)); writer.WriteOptionalCollection(AsyncApiConstants.Traits, this.Traits, (w, t) => t.SerializeV2(w)); - IEnumerable messages = this.Messages.Any() ? this.Messages : this.Channel.Messages.Values; + IEnumerable messages = this.Messages.Any() ? this.Messages : this.Channel?.Messages.Values; - if (messages.Count() > 1) + if (messages?.Count() > 1) { writer.WritePropertyName(AsyncApiConstants.Message); writer.WriteStartObject(); @@ -102,7 +102,7 @@ public virtual void SerializeV2(IAsyncApiWriter writer) } else { - writer.WriteOptionalObject(AsyncApiConstants.Message, messages.FirstOrDefault(), (w, m) => m.SerializeV2(w)); + writer.WriteOptionalObject(AsyncApiConstants.Message, messages?.FirstOrDefault(), (w, m) => m.SerializeV2(w)); } writer.WriteExtensions(this.Extensions); From d9c42b7d1349571e2d3f2aac374855d68d0e2da2 Mon Sep 17 00:00:00 2001 From: VisualBean Date: Mon, 26 May 2025 00:06:37 +0200 Subject: [PATCH 5/5] platform agnostic --- test/ByteBard.AsyncAPI.Tests/AsyncApiDocumentV3Tests.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/ByteBard.AsyncAPI.Tests/AsyncApiDocumentV3Tests.cs b/test/ByteBard.AsyncAPI.Tests/AsyncApiDocumentV3Tests.cs index e3b13bb..9d3211d 100644 --- a/test/ByteBard.AsyncAPI.Tests/AsyncApiDocumentV3Tests.cs +++ b/test/ByteBard.AsyncAPI.Tests/AsyncApiDocumentV3Tests.cs @@ -233,7 +233,7 @@ public void V3_WithComplexInput_CanReSerialize() diagnostics.Warnings.Should().BeEmpty(); reserialized.Should().BePlatformAgnosticEquivalentTo(expected); } - + [Test] public void V3_SerializeV2_WithNoMessageReference_SerializesChannelMessagesOneOf() { @@ -331,9 +331,9 @@ public void V3_SerializeV2_WithNoMessageReference_SerializesChannelMessagesOneOf }; var yamlV2 = myFirstAsyncApi.SerializeAsYaml(AsyncApiVersion.AsyncApi2_0); - yamlV2.Should().BeEquivalentTo(expected); + yamlV2.Should().BePlatformAgnosticEquivalentTo(expected); } - + [Test] public void V3_SerializeV2_WithNoMessageReference_SerializesChannelMessage() { @@ -405,7 +405,7 @@ public void V3_SerializeV2_WithNoMessageReference_SerializesChannelMessage() }; var yamlV2 = myFirstAsyncApi.SerializeAsYaml(AsyncApiVersion.AsyncApi2_0); - yamlV2.Should().BeEquivalentTo(expected); + yamlV2.Should().BePlatformAgnosticEquivalentTo(expected); } } }