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); ``` diff --git a/src/ByteBard.AsyncAPI/Models/AsyncApiOperation.cs b/src/ByteBard.AsyncAPI/Models/AsyncApiOperation.cs index eef4788..d7ea083 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..9d3211d 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().BePlatformAgnosticEquivalentTo(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().BePlatformAgnosticEquivalentTo(expected); + } } }