Skip to content

Commit a83cced

Browse files
authored
Merge pull request #4049 from BrighterCommand/feature/3828-AsyncAPI-Neuroglia-SDK
feat(#3828): AsyncAPI 3.0 generation with Neuroglia SDK
2 parents 3afa682 + 730a0f2 commit a83cced

47 files changed

Lines changed: 5773 additions & 259 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

Brighter.slnx

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,10 @@
66
<Platform Name="x86" />
77
</Configurations>
88
<Folder Name="/samples/" />
9+
<Folder Name="/samples/AsyncAPI/">
10+
<Project Path="samples/AsyncAPI/KafkaAsyncAPI/KafkaAsyncAPI.csproj" />
11+
<Project Path="samples/AsyncAPI/RMQAsyncAPI/RMQAsyncAPI.csproj" />
12+
</Folder>
913
<Folder Name="/samples/Analyzer/">
1014
<Project Path="samples/Analyzer/AnalyzerSamples/AnalyzerSamples.csproj" />
1115
</Folder>
@@ -192,6 +196,7 @@
192196
<Folder Name="/tests/">
193197
<File Path="tests/README.md" />
194198
<Project Path="tests/Paramore.Brighter.Analyzer.Tests/Paramore.Brighter.Analyzer.Tests.csproj" />
199+
<Project Path="tests/Paramore.Brighter.AsyncAPI.Tests/Paramore.Brighter.AsyncAPI.Tests.csproj" />
195200
<Project Path="tests/Paramore.Brighter.AWS.Tests/Paramore.Brighter.AWS.Tests.csproj" />
196201
<Project Path="tests/Paramore.Brighter.AWS.V4.Tests/Paramore.Brighter.AWS.V4.Tests.csproj" />
197202
<Project Path="tests/Paramore.Brighter.AWSScheduler.Tests/Paramore.Brighter.AWSScheduler.Tests.csproj" />
@@ -230,6 +235,8 @@
230235
<Project Path="src/Paramore.Brighter.Analyzer.Package/Paramore.Brighter.Analyzer.Package.csproj" />
231236
<Project Path="src/Paramore.Brighter.Analyzer/Paramore.Brighter.Analyzer.csproj" />
232237
<Project Path="src/Paramore.Brighter.Archive.Azure/Paramore.Brighter.Archive.Azure.csproj" />
238+
<Project Path="src/Paramore.Brighter.AsyncAPI.NJsonSchema/Paramore.Brighter.AsyncAPI.NJsonSchema.csproj" />
239+
<Project Path="src/Paramore.Brighter.AsyncAPI/Paramore.Brighter.AsyncAPI.csproj" />
233240
<Project Path="src/Paramore.Brighter.Dapper/Paramore.Brighter.Dapper.csproj" />
234241
<Project Path="src/Paramore.Brighter.DynamoDb.V4/Paramore.Brighter.DynamoDb.V4.csproj" />
235242
<Project Path="src/Paramore.Brighter.DynamoDb/Paramore.Brighter.DynamoDb.csproj" />

Directory.Packages.props

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,8 @@
9595
<PackageVersion Include="MQTTnet" Version="4.3.7.1207" />
9696
<PackageVersion Include="MySqlConnector" Version="2.5.0" />
9797
<PackageVersion Include="Newtonsoft.Json" Version="13.0.4" />
98+
<PackageVersion Include="Neuroglia.AsyncApi.Core" Version="3.0.6" />
99+
<PackageVersion Include="Neuroglia.AsyncApi.IO" Version="3.0.6" />
98100
<PackageVersion Include="NJsonSchema" Version="11.6.1" />
99101
<PackageVersion Include="NJsonSchema.NewtonsoftJson" Version="11.6.1" />
100102
<PackageVersion Include="NUnit" Version="4.6.0" />
@@ -149,6 +151,7 @@
149151
<PackageVersion Include="System.Text.RegularExpressions" Version="4.3.1" />
150152
<PackageVersion Include="System.Threading.Channels" Version="10.0.7" />
151153
<PackageVersion Include="TUnit" Version="0.67.10" />
154+
<PackageVersion Include="YamlDotNet" Version="16.3.0" />
152155
<PackageVersion Include="xunit" Version="2.9.3" />
153156
<PackageVersion Include="Xunit.SkippableFact" Version="1.5.61" />
154157
<PackageVersion Include="xunit.runner.visualstudio" Version="3.1.5">

docs/features/asyncapi-sdk-adoption/RESEARCH.md

Lines changed: 576 additions & 0 deletions
Large diffs are not rendered by default.

progress.txt

Lines changed: 525 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
#region Licence
2+
/* The MIT License (MIT)
3+
Copyright © 2026 Jonny Olliff-Lee <jonny.ollifflee@gmail.com>
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in
13+
all copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21+
THE SOFTWARE. */
22+
23+
#endregion
24+
25+
using Paramore.Brighter;
26+
27+
namespace KafkaAsyncAPI.Events
28+
{
29+
/// <summary>
30+
/// An event published when an order is created.
31+
/// Decorated with [PublicationTopic] to demonstrate assembly scanning discovery.
32+
/// </summary>
33+
[PublicationTopic("order.created")]
34+
public class OrderCreatedEvent : Event
35+
{
36+
public OrderCreatedEvent() : base(Id.Random()) { }
37+
38+
public string OrderId { get; set; } = string.Empty;
39+
public decimal Amount { get; set; }
40+
}
41+
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
#region Licence
2+
/* The MIT License (MIT)
3+
Copyright © 2026 Jonny Olliff-Lee <jonny.ollifflee@gmail.com>
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in
13+
all copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21+
THE SOFTWARE. */
22+
23+
#endregion
24+
25+
using Paramore.Brighter;
26+
27+
namespace KafkaAsyncAPI.Events
28+
{
29+
/// <summary>
30+
/// An event received when a payment is processed.
31+
/// Discovered via DI subscription registration.
32+
/// </summary>
33+
public class PaymentReceivedEvent : Event
34+
{
35+
public PaymentReceivedEvent() : base(Id.Random()) { }
36+
37+
public string PaymentId { get; set; } = string.Empty;
38+
public decimal Amount { get; set; }
39+
}
40+
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
#region Licence
2+
/* The MIT License (MIT)
3+
Copyright © 2026 Jonny Olliff-Lee <jonny.ollifflee@gmail.com>
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in
13+
all copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21+
THE SOFTWARE. */
22+
23+
#endregion
24+
25+
using System;
26+
using Paramore.Brighter;
27+
using KafkaAsyncAPI.Events;
28+
29+
namespace KafkaAsyncAPI.Handlers
30+
{
31+
public class PaymentReceivedEventHandler : RequestHandler<PaymentReceivedEvent>
32+
{
33+
public override PaymentReceivedEvent Handle(PaymentReceivedEvent @event)
34+
{
35+
Console.WriteLine($"Payment received: {{{@event.PaymentId}}} for {{{@event.Amount:C}}}");
36+
return base.Handle(@event);
37+
}
38+
}
39+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
<PropertyGroup>
3+
<OutputType>Exe</OutputType>
4+
<TargetFrameworks>net9.0;net10.0</TargetFrameworks>
5+
<LangVersion>latest</LangVersion>
6+
<Nullable>enable</Nullable>
7+
</PropertyGroup>
8+
<ItemGroup>
9+
<ProjectReference Include="..\..\..\src\Paramore.Brighter\Paramore.Brighter.csproj" />
10+
<ProjectReference Include="..\..\..\src\Paramore.Brighter.Extensions.DependencyInjection\Paramore.Brighter.Extensions.DependencyInjection.csproj" />
11+
<ProjectReference Include="..\..\..\src\Paramore.Brighter.ServiceActivator\Paramore.Brighter.ServiceActivator.csproj" />
12+
<ProjectReference Include="..\..\..\src\Paramore.Brighter.ServiceActivator.Extensions.DependencyInjection\Paramore.Brighter.ServiceActivator.Extensions.DependencyInjection.csproj" />
13+
<ProjectReference Include="..\..\..\src\Paramore.Brighter.ServiceActivator.Extensions.Hosting\Paramore.Brighter.ServiceActivator.Extensions.Hosting.csproj" />
14+
<ProjectReference Include="..\..\..\src\Paramore.Brighter.MessagingGateway.Kafka\Paramore.Brighter.MessagingGateway.Kafka.csproj" />
15+
<ProjectReference Include="..\..\..\src\Paramore.Brighter.AsyncAPI\Paramore.Brighter.AsyncAPI.csproj" />
16+
<ProjectReference Include="..\..\..\src\Paramore.Brighter.AsyncAPI.NJsonSchema\Paramore.Brighter.AsyncAPI.NJsonSchema.csproj" />
17+
</ItemGroup>
18+
<ItemGroup>
19+
<PackageReference Include="Microsoft.Extensions.DependencyInjection" />
20+
<PackageReference Include="Serilog" />
21+
<PackageReference Include="Serilog.Extensions.Hosting" />
22+
<PackageReference Include="Serilog.Sinks.Console" />
23+
</ItemGroup>
24+
</Project>
Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
#region Licence
2+
/* The MIT License (MIT)
3+
Copyright © 2026 Jonny Olliff-Lee <jonny.ollifflee@gmail.com>
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in
13+
all copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21+
THE SOFTWARE. */
22+
23+
#endregion
24+
25+
using System;
26+
using System.Collections.Generic;
27+
using Microsoft.Extensions.DependencyInjection;
28+
using Microsoft.Extensions.Hosting;
29+
using Paramore.Brighter;
30+
using Paramore.Brighter.AsyncAPI;
31+
using Neuroglia.AsyncApi.v3;
32+
using Paramore.Brighter.Extensions.DependencyInjection;
33+
using Paramore.Brighter.MessagingGateway.Kafka;
34+
using Paramore.Brighter.ServiceActivator.Extensions.DependencyInjection;
35+
using KafkaAsyncAPI.Events;
36+
using Serilog;
37+
38+
Log.Logger = new LoggerConfiguration()
39+
.WriteTo.Console()
40+
.CreateLogger();
41+
42+
var generateAsyncApi = args.Length > 0 && args[0] == "--generate-asyncapi";
43+
44+
var kafkaConfig = new KafkaMessagingGatewayConfiguration
45+
{
46+
Name = "paramore.brighter.kafkaasyncapi",
47+
BootStrapServers = new[] { "localhost:9092" }
48+
};
49+
50+
var kafkaMessageConsumerFactory = new KafkaMessageConsumerFactory(kafkaConfig);
51+
52+
// KafkaProducerRegistryFactory.Create() opens a real broker connection at construction
53+
// time, so we only build the registry when actually starting the producer side. In
54+
// --generate-asyncapi mode the [PublicationTopic]-decorated event types are picked up
55+
// by assembly scanning, so the document still describes publications correctly.
56+
var host = new HostBuilder()
57+
.ConfigureServices((_, services) =>
58+
{
59+
var brighter = services.AddConsumers(options =>
60+
{
61+
options.Subscriptions = new Subscription[]
62+
{
63+
new KafkaSubscription<PaymentReceivedEvent>(
64+
new SubscriptionName("paramore.asyncapi.payment"),
65+
new ChannelName("payment.received"),
66+
new RoutingKey("payment.received"),
67+
groupId: "kafka-asyncapi-sample",
68+
timeOut: TimeSpan.FromMilliseconds(200),
69+
messagePumpType: MessagePumpType.Reactor,
70+
makeChannels: OnMissingChannel.Create)
71+
};
72+
options.DefaultChannelFactory = new ChannelFactory(kafkaMessageConsumerFactory);
73+
});
74+
75+
if (!generateAsyncApi)
76+
{
77+
var producerRegistry = new KafkaProducerRegistryFactory(
78+
kafkaConfig,
79+
new KafkaPublication<OrderCreatedEvent>[]
80+
{
81+
new()
82+
{
83+
Topic = new RoutingKey("order.created"),
84+
NumPartitions = 3,
85+
MessageSendMaxRetries = 3,
86+
MessageTimeoutMs = 1000,
87+
MaxInFlightRequestsPerConnection = 1
88+
}
89+
}).Create();
90+
91+
brighter.AddProducers(configure =>
92+
{
93+
configure.ProducerRegistry = producerRegistry;
94+
});
95+
}
96+
97+
brighter.UseAsyncApi(opts =>
98+
{
99+
opts.Title = "Kafka AsyncAPI Sample";
100+
opts.Version = "1.0.0";
101+
opts.Description = "Sample demonstrating AsyncAPI 3.0 generation with Kafka, showcasing subscription, publication, and assembly scanning discovery";
102+
opts.Servers = new Dictionary<string, V3ServerDefinition>
103+
{
104+
["kafka"] = new V3ServerDefinition
105+
{
106+
Host = "localhost:9092",
107+
Protocol = "kafka",
108+
Description = "Local Kafka broker"
109+
}
110+
};
111+
})
112+
.AutoFromAssemblies();
113+
})
114+
.UseSerilog()
115+
.Build();
116+
117+
if (generateAsyncApi)
118+
{
119+
var document = await host.GenerateAsyncApiDocumentAsync("asyncapi.json");
120+
Console.WriteLine($"AsyncAPI document generated: {document.Info.Title} v{document.Info.Version} (JSON + YAML)");
121+
return;
122+
}
123+
124+
Console.WriteLine("Run with --generate-asyncapi to generate the AsyncAPI document.");
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
#region Licence
2+
/* The MIT License (MIT)
3+
Copyright © 2026 Jonny Olliff-Lee <jonny.ollifflee@gmail.com>
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in
13+
all copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21+
THE SOFTWARE. */
22+
23+
#endregion
24+
25+
using Paramore.Brighter;
26+
27+
namespace RMQAsyncAPI.Events
28+
{
29+
/// <summary>
30+
/// An event published when an order is created.
31+
/// Decorated with [PublicationTopic] to demonstrate assembly scanning discovery.
32+
/// </summary>
33+
[PublicationTopic("order.created")]
34+
public class OrderCreatedEvent : Event
35+
{
36+
public OrderCreatedEvent() : base(Id.Random()) { }
37+
38+
public string OrderId { get; set; } = string.Empty;
39+
public decimal Amount { get; set; }
40+
}
41+
}

0 commit comments

Comments
 (0)