Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
92 changes: 38 additions & 54 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand All @@ -38,59 +38,43 @@ Main classes to know:
## Writing

```csharp
var myFirstAsyncApi = new AsyncApiDocument
{
Info = new AsyncApiInfo
{
Title = "my first asyncapi",
},
Channels = new Dictionary<string, AsyncApiChannel>
{
{
"users", new AsyncApiChannel
{
Subscribe = new AsyncApiOperation
{
OperationId = "users",
Description = "my users channel",
Message = new List<AsyncApiMessage>
{
new AsyncApiMessageReference("#/components/messages/MyMessage"),
},
},
}
},
},
Components = new AsyncApiComponents
{
Messages = new Dictionary<string, AsyncApiMessage>
{
{
"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);
```


Expand Down
8 changes: 5 additions & 3 deletions src/ByteBard.AsyncAPI/Models/AsyncApiOperation.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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<AsyncApiMessage> 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);
Expand Down
177 changes: 177 additions & 0 deletions test/ByteBard.AsyncAPI.Tests/AsyncApiDocumentV3Tests.cs
Original file line number Diff line number Diff line change
@@ -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;
Expand Down Expand Up @@ -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<string, AsyncApiChannel>
{
{
"UserSignup", new AsyncApiChannel
{
Address = "user/signedUp",
Messages = new Dictionary<string, AsyncApiMessage>()
{
{
"UserMessage", new AsyncApiMessage
{
Payload = new AsyncApiJsonSchema()
{
Type = SchemaType.Object,
Properties = new Dictionary<string, AsyncApiJsonSchema>()
{
{
"displayName", new AsyncApiJsonSchema()
{
Type = SchemaType.String,
Description = "Name of the user",
}
},
},
},
}
},
{
"OtherUserMessage", new AsyncApiMessage
{
Payload = new AsyncApiJsonSchema()
{
Type = SchemaType.Object,
Properties = new Dictionary<string, AsyncApiJsonSchema>()
{
{
"displayName", new AsyncApiJsonSchema()
{
Type = SchemaType.String,
Description = "Name of the user",
}
},
},
},
}
},
},
}
},
},
Operations = new Dictionary<string, AsyncApiOperation>()
{
{
"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<string, AsyncApiChannel>
{
{
"UserSignup", new AsyncApiChannel
{
Address = "user/signedUp",
Messages = new Dictionary<string, AsyncApiMessage>()
{
{
"UserMessage", new AsyncApiMessage
{
Payload = new AsyncApiJsonSchema()
{
Type = SchemaType.Object,
Properties = new Dictionary<string, AsyncApiJsonSchema>()
{
{
"displayName", new AsyncApiJsonSchema()
{
Type = SchemaType.String,
Description = "Name of the user",
}
},
},
},
}
},
},
}
},
},
Operations = new Dictionary<string, AsyncApiOperation>()
{
{
"ConsumerUserSignups", new AsyncApiOperation
{
Action = AsyncApiAction.Receive,
Channel = new AsyncApiChannelReference("#/channels/UserSignup"),
}
},
},
};

var yamlV2 = myFirstAsyncApi.SerializeAsYaml(AsyncApiVersion.AsyncApi2_0);
yamlV2.Should().BePlatformAgnosticEquivalentTo(expected);
}
}
}
Loading