diff --git a/Neuroglia.AsyncApi.sln b/Neuroglia.AsyncApi.sln index e82a8ef..089f831 100644 --- a/Neuroglia.AsyncApi.sln +++ b/Neuroglia.AsyncApi.sln @@ -78,6 +78,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Neuroglia.AsyncApi.Client.B EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Neuroglia.AsyncApi.Client.Bindings.Stomp", "src\Neuroglia.AsyncApi.Client.Bindings.Stomp\Neuroglia.AsyncApi.Client.Bindings.Stomp.csproj", "{5CC985FA-4EC3-4BC3-A2FF-1377B248BBA6}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ZvooveSampleApi", "samples\ZvooveSampleApi\ZvooveSampleApi.csproj", "{D4E2E2B0-AF17-4C4E-B2A4-DB320F15A05B}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -176,6 +178,10 @@ Global {5CC985FA-4EC3-4BC3-A2FF-1377B248BBA6}.Debug|Any CPU.Build.0 = Debug|Any CPU {5CC985FA-4EC3-4BC3-A2FF-1377B248BBA6}.Release|Any CPU.ActiveCfg = Release|Any CPU {5CC985FA-4EC3-4BC3-A2FF-1377B248BBA6}.Release|Any CPU.Build.0 = Release|Any CPU + {D4E2E2B0-AF17-4C4E-B2A4-DB320F15A05B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D4E2E2B0-AF17-4C4E-B2A4-DB320F15A05B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D4E2E2B0-AF17-4C4E-B2A4-DB320F15A05B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D4E2E2B0-AF17-4C4E-B2A4-DB320F15A05B}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -206,6 +212,7 @@ Global {FDE484DC-57FE-457E-BE71-184B7A74516F} = {4B933DF9-CD24-44B1-AF64-0D5E75B9AB45} {EC39BF64-56CB-4080-9C84-988F70E601D8} = {4B933DF9-CD24-44B1-AF64-0D5E75B9AB45} {5CC985FA-4EC3-4BC3-A2FF-1377B248BBA6} = {4B933DF9-CD24-44B1-AF64-0D5E75B9AB45} + {D4E2E2B0-AF17-4C4E-B2A4-DB320F15A05B} = {D5DC0A71-F39C-4AA1-A284-66E622868D47} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {DC433DEB-01E5-4328-B0BB-6FFFE8C7363F} diff --git a/samples/ZvooveSampleApi/Messages.cs b/samples/ZvooveSampleApi/Messages.cs new file mode 100644 index 0000000..43b01ad --- /dev/null +++ b/samples/ZvooveSampleApi/Messages.cs @@ -0,0 +1,77 @@ +#region License +// Copyright � 2021-Present Neuroglia SRL. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"), +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#endregion + +using Neuroglia.AsyncApi.v3; + +namespace ZvooveSampleApi; + + +[Message(Name = MessageType, Description = "Internal event for keeping user data in sync on update")] +public record InternalUserEvent +{ + public const string MessageType = "internal.user.event"; + + public int UserId { get; init; } +} +// +// [MessageIdentity(MessageType)] +// [AsyncApiMessage(MessageType, Summary = "User was created.")] +// [RabbitMqMessageBinding(MessageType = MessageType)] +public record UserCreated +{ + public const string MessageType = "user.created"; + + public int UserId { get; init; } +} +// +// [MessageIdentity(MessageType)] +// [AsyncApiMessage(MessageType, Summary = "User was updated.")] +// [RabbitMqMessageBinding(MessageType = MessageType)] +public record UserUpdated +{ + public const string MessageType = "user.updated"; + + public int UserId { get; init; } +} +// +// [MessageIdentity(MessageType)] +// [AsyncApiMessage(MessageType, Summary = "User was deleted.")] +// [RabbitMqMessageBinding(MessageType = MessageType)] +public record UserDeleted +{ + public const string MessageType = "user.deleted"; + + public int UserId { get; init; } +} +// +// [MessageIdentity(MessageType)] +// [AsyncApiMessage(MessageType, Summary = "User is requested to be disabled.")] +// [RabbitMqMessageBinding(MessageType = MessageType)] +// public record DisableUser +// { +// public const string MessageType = "user.disable"; +// +// public int UserId { get; init; } +// } +// +// [MessageIdentity(MessageType)] +// [AsyncApiMessage(MessageType, Summary = "User authorization rules changed.")] +// [RabbitMqMessageBinding(MessageType = MessageType)] +// public record AuthzChanged +// { +// public const string MessageType = "authz.changed"; +// +// public int UserId { get; init; } +// } \ No newline at end of file diff --git a/samples/ZvooveSampleApi/Program.cs b/samples/ZvooveSampleApi/Program.cs new file mode 100644 index 0000000..4eb5816 --- /dev/null +++ b/samples/ZvooveSampleApi/Program.cs @@ -0,0 +1,141 @@ +// Copyright � 2021-Present Neuroglia SRL. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"), +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +using Json.Schema; +using Neuroglia.AsyncApi; +using Neuroglia.AsyncApi.Bindings.Amqp; +using Neuroglia.Data.Schemas.Json; +using ZvooveSampleApi; +using Json.Schema.Generation; +using Neuroglia.Serialization; +using System.Text.Json; +using JsonSerializer = Neuroglia.Serialization.Json.JsonSerializer; + +var builder = WebApplication.CreateBuilder(args); + +builder.Services.AddHttpClient(); +builder.Services.AddRazorPages() + .AddRazorRuntimeCompilation(); +builder.Services.AddAsyncApiUI(); +builder.Services.AddAsyncApiGeneration(c => +{ + c.Build(); +}); +builder.Services.AddAsyncApiDocument(document => document + .UsingAsyncApiV3() + .WithTitle("User Service API") + .WithVersion("1.0.0") + .WithDescription("The User Service with several usecases to try out the mapping of rabbitmq into asyncapi spec.") + .WithLicense("Apache 2.0", new Uri("https://www.apache.org/licenses/LICENSE-2.0.html")) + .WithDefaultContentType("application/json") + .WithServer("production", server => server + .WithHost("amqps://rabbit.zvoove-local.cloud") + .WithProtocol(AsyncApiProtocol.Amqp) + .WithBinding(new AmqpServerBindingDefinition())) + .WithChannel("publicExchange", channel => channel + // .WithServer("#/servers/production") + .WithDescription("The endpoint used to publish and subscribe to user events") + .WithBinding(new AmqpChannelBindingDefinition() + { + Type = AmqpChannelType.RoutingKey, + Exchange = new AmqpExchangeDefinition() + { + Name = "users.events", + Type = AmqpExchangeType.Topic, + Durable = true, + AutoDelete = false, + }, + }) + .WithMessage("userCreated", message => message + .Use("#/components/messages/userCreated")) + .WithMessage("userUpdated", message => message + .Use("#/components/messages/userUpdated")) + .WithMessage("userDeleted", message => message + .Use("#/components/messages/userDeleted"))) + .WithOperation("publicUserCreated", operation => operation + .WithAction(Neuroglia.AsyncApi.v3.V3OperationAction.Send) + .WithTitle("User created operation") + .WithChannel("#/channels/publicExchange") + .WithBinding(new AmqpOperationBindingDefinition() + { + Cc = [UserCreated.MessageType], + }) + .WithMessage("#/channels/publicExchange/messages/userCreated")) + .WithOperation("publicUserUpdated", operation => operation + .WithAction(Neuroglia.AsyncApi.v3.V3OperationAction.Send) + .WithTitle("User updated operation") + .WithChannel("#/channels/publicExchange") + .WithBinding(new AmqpOperationBindingDefinition() + { + Cc = [UserUpdated.MessageType], + }) + .WithMessage("#/channels/publicExchange/messages/userUpdated")) + .WithOperation("publicUserDeleted", operation => operation + .WithAction(Neuroglia.AsyncApi.v3.V3OperationAction.Send) + .WithTitle("User deleted operation") + .WithChannel("#/channels/publicExchange") + .WithBinding(new AmqpOperationBindingDefinition() + { + Cc = [UserDeleted.MessageType], + }) + .WithMessage("#/channels/publicExchange/messages/userDeleted")) + .WithMessageComponent("userCreated", message => message + .WithName(UserCreated.MessageType) + .WithDescription("User created event") + .WithBinding(new AmqpMessageBindingDefinition() + { + MessageType = UserCreated.MessageType, + ContentEncoding = "application/json", + }) + .WithContentType("application/json") + .WithPayloadSchema(schema => schema + .WithJsonSchema(schemaBuilder => schemaBuilder.FromType())) + .WithCorrelationId(setup => setup + .WithLocation("$message.payload#/subject"))) + .WithMessageComponent("userUpdated", message => message + .WithName(UserUpdated.MessageType) + .WithDescription("User created event") + .WithBinding(new AmqpMessageBindingDefinition() + { + MessageType = UserUpdated.MessageType, + ContentEncoding = "application/json", + }) + .WithContentType("application/json") + .WithPayloadSchema(schema => schema + .WithJsonSchema(schemaBuilder => schemaBuilder.FromType())) + .WithCorrelationId(setup => setup + .WithLocation("$message.payload#/subject"))) + .WithMessageComponent("userDeleted", message => message + .WithName(UserDeleted.MessageType) + .WithDescription("User created event") + .WithBinding(new AmqpMessageBindingDefinition() + { + MessageType = UserDeleted.MessageType, + ContentEncoding = "application/json", + }) + .WithContentType("application/json") + .WithPayloadSchema(schema => schema + .WithJsonSchema(schemaBuilder => schemaBuilder.FromType())) + .WithCorrelationId(setup => setup + .WithLocation("$message.payload#/subject")))); +builder.Services.AddSingleton(); +builder.Services.AddSingleton(); + +var app = builder.Build(); +app.UseStaticFiles(); +app.UseRouting(); +app.UseAuthorization(); +app.MapAsyncApiDocuments(); +app.MapRazorPages(); + +app.Run(); \ No newline at end of file diff --git a/samples/ZvooveSampleApi/Properties/launchSettings.json b/samples/ZvooveSampleApi/Properties/launchSettings.json new file mode 100644 index 0000000..bc0a0f6 --- /dev/null +++ b/samples/ZvooveSampleApi/Properties/launchSettings.json @@ -0,0 +1,30 @@ +{ + "$schema": "http://json.schemastore.org/launchsettings.json", + "iisSettings": { + "windowsAuthentication": false, + "anonymousAuthentication": true, + "iisExpress": { + "applicationUrl": "http://localhost:25151", + "sslPort": 0 + } + }, + "profiles": { + "http": { + "commandName": "Project", + "dotnetRunMessages": true, + "launchBrowser": true, + "applicationUrl": "http://localhost:5055", + "launchUrl": "asyncapi", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + }, + "IIS Express": { + "commandName": "IISExpress", + "launchBrowser": true, + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + } + } +} diff --git a/samples/ZvooveSampleApi/ZvooveSampleApi.csproj b/samples/ZvooveSampleApi/ZvooveSampleApi.csproj new file mode 100644 index 0000000..2e5554b --- /dev/null +++ b/samples/ZvooveSampleApi/ZvooveSampleApi.csproj @@ -0,0 +1,20 @@ + + + + net9.0 + enable + enable + false + True + + + + + + + + + + + + diff --git a/samples/ZvooveSampleApi/appsettings.Development.json b/samples/ZvooveSampleApi/appsettings.Development.json new file mode 100644 index 0000000..0c208ae --- /dev/null +++ b/samples/ZvooveSampleApi/appsettings.Development.json @@ -0,0 +1,8 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + } +} diff --git a/samples/ZvooveSampleApi/appsettings.json b/samples/ZvooveSampleApi/appsettings.json new file mode 100644 index 0000000..10f68b8 --- /dev/null +++ b/samples/ZvooveSampleApi/appsettings.json @@ -0,0 +1,9 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + }, + "AllowedHosts": "*" +}