From b2ae5d1b48099a3d50234d5fb5c38e734f84996d Mon Sep 17 00:00:00 2001 From: Vitalii Lakatosh Date: Sat, 11 Apr 2026 00:15:01 +0300 Subject: [PATCH 01/33] Add api documentation in Blog minimal api --- .../ApiEndpoints/AccountsApiEndpoints.cs | 30 +++++++++++--- .../ApiEndpoints/CommentsApiEndpoints.cs | 39 +++++++++++++++---- .../ApiEndpoints/MessagesApiEndpoints.cs | 28 +++++++++++-- .../ApiEndpoints/PostsApiEndpoints.cs | 35 ++++++++++++++--- 4 files changed, 110 insertions(+), 22 deletions(-) diff --git a/BlogWebApp/BlogMinimalApi/ApiEndpoints/AccountsApiEndpoints.cs b/BlogWebApp/BlogMinimalApi/ApiEndpoints/AccountsApiEndpoints.cs index 63f278f8..f7bc7c76 100644 --- a/BlogWebApp/BlogMinimalApi/ApiEndpoints/AccountsApiEndpoints.cs +++ b/BlogWebApp/BlogMinimalApi/ApiEndpoints/AccountsApiEndpoints.cs @@ -51,8 +51,13 @@ public void InstallApiRoutes(WebApplication app) return Results.Ok(response); }) + .WithName("Initialize") .Produces>() - .Produces(400); + .Produces(StatusCodes.Status400BadRequest) + .Produces(StatusCodes.Status404NotFound) + .WithSummary("Initialize") + .WithDescription("Initialize") + .HasApiVersion(1.0); // Get All Users @@ -65,7 +70,13 @@ public void InstallApiRoutes(WebApplication app) return Results.Ok(response); }) - .Produces>(); + .WithName("GetAllUsers") + .Produces>() + .Produces(StatusCodes.Status400BadRequest) + .Produces(StatusCodes.Status404NotFound) + .WithSummary("Get All Users") + .WithDescription("Get All Users") + .HasApiVersion(1.0); // Login @@ -151,7 +162,11 @@ public void InstallApiRoutes(WebApplication app) return Results.NoContent(); }) - .Produces(204); + .WithName("SendConfirmationEmail") + .Produces(StatusCodes.Status204NoContent) + .WithSummary("Send Confirmation Email") + .WithDescription("Send Confirmation Email") + .HasApiVersion(1.0); // Users activity privateGroup.MapGet(ApiRoutes.AccountsController.UsersActivity, @@ -163,8 +178,13 @@ public void InstallApiRoutes(WebApplication app) ? Results.NotFound() : Results.Ok(activity); }) - .Produces() - .Produces(404); + .WithName("UsersActivity") + .Produces>() + .Produces(StatusCodes.Status400BadRequest) + .Produces(StatusCodes.Status404NotFound) + .WithSummary("Users Activity") + .WithDescription("Users Activity") + .HasApiVersion(1.0); // Change password privateGroup.MapPut(ApiRoutes.AccountsController.ChangePassword, diff --git a/BlogWebApp/BlogMinimalApi/ApiEndpoints/CommentsApiEndpoints.cs b/BlogWebApp/BlogMinimalApi/ApiEndpoints/CommentsApiEndpoints.cs index f7f69e78..442a323a 100644 --- a/BlogWebApp/BlogMinimalApi/ApiEndpoints/CommentsApiEndpoints.cs +++ b/BlogWebApp/BlogMinimalApi/ApiEndpoints/CommentsApiEndpoints.cs @@ -44,7 +44,13 @@ public void InstallApiRoutes(WebApplication app) return Results.Ok(response); }) - .Produces>(); + .WithName("GetAll") + .Produces>() + .Produces(StatusCodes.Status400BadRequest) + .Produces(StatusCodes.Status404NotFound) + .WithSummary("Get All") + .WithDescription("Get All") + .HasApiVersion(1.0); // Comments Activity @@ -57,8 +63,13 @@ public void InstallApiRoutes(WebApplication app) ? Results.NotFound() : Results.Ok(activity); }) - .Produces() - .Produces(404); + .WithName("CommentsActivity") + .Produces>() + .Produces(StatusCodes.Status400BadRequest) + .Produces(StatusCodes.Status404NotFound) + .WithSummary("Comments Activity") + .WithDescription("Comments Activity") + .HasApiVersion(1.0); // Get Paged Comments @@ -78,8 +89,13 @@ public void InstallApiRoutes(WebApplication app) ? Results.NotFound() : Results.Ok(mapper.Map(result)); }) + //.RequireAuthorization() + .WithName("GetCommentsByFilter") .Produces() - .Produces(404); + .Produces(400) + .WithSummary("Get Comments By Filter") + .WithDescription("Get CommentsBy Filter") + .HasApiVersion(1.0); // Get Comments By Post @@ -101,8 +117,13 @@ public void InstallApiRoutes(WebApplication app) ? Results.NotFound() : Results.Ok(mapper.Map(result)); }) + //.RequireAuthorization() + .WithName("Get Comments By Post") .Produces() - .Produces(404); + .Produces(400) + .WithSummary("Get Comments By Post") + .WithDescription("Get Comments By Post") + .HasApiVersion(1.0); // Get Comment By ID @@ -117,9 +138,13 @@ public void InstallApiRoutes(WebApplication app) ? Results.NotFound() : Results.Ok(mapper.Map(comment)); }) - .WithName(ApiRoutes.CommentsController.GetComment) + .WithName("GetCommentById") .Produces() - .Produces(404); + .Produces(StatusCodes.Status400BadRequest) + .Produces(StatusCodes.Status404NotFound) + .WithSummary("Get Comment By Id") + .WithDescription("Get Comment By Id") + .HasApiVersion(1.0); // ------------------------- // PRIVATE (Authorized) diff --git a/BlogWebApp/BlogMinimalApi/ApiEndpoints/MessagesApiEndpoints.cs b/BlogWebApp/BlogMinimalApi/ApiEndpoints/MessagesApiEndpoints.cs index 1760b36e..5d88cbda 100644 --- a/BlogWebApp/BlogMinimalApi/ApiEndpoints/MessagesApiEndpoints.cs +++ b/BlogWebApp/BlogMinimalApi/ApiEndpoints/MessagesApiEndpoints.cs @@ -46,8 +46,13 @@ public void InstallApiRoutes(WebApplication app) return Results.Ok(response); }) + .WithName("GetAll") .Produces>() - .Produces(404); + .Produces(StatusCodes.Status400BadRequest) + .Produces(StatusCodes.Status404NotFound) + .WithSummary("Get All") + .WithDescription("Get All") + .HasApiVersion(1.0); // GET BY RECIPIENT @@ -65,8 +70,13 @@ public void InstallApiRoutes(WebApplication app) return Results.Ok(mapper.Map>(messages)); }) + .WithName("GetRecipientMessages") .Produces>() - .Produces(404); + .Produces(StatusCodes.Status400BadRequest) + .Produces(StatusCodes.Status404NotFound) + .WithSummary("Get Recipient Messages") + .WithDescription("Get Recipient Messages") + .HasApiVersion(1.0); // GET BY SENDER @@ -84,8 +94,13 @@ public void InstallApiRoutes(WebApplication app) return Results.Ok(mapper.Map>(messages)); }) + .WithName("GetSenderMessages") .Produces>() - .Produces(404); + .Produces(StatusCodes.Status400BadRequest) + .Produces(StatusCodes.Status404NotFound) + .WithSummary("Get Sender Messages") + .WithDescription("Get Sender Messages") + .HasApiVersion(1.0); // GET BY ID @@ -100,8 +115,13 @@ public void InstallApiRoutes(WebApplication app) ? Results.NotFound() : Results.Ok(mapper.Map(message)); }) + .WithName("GetById") .Produces() - .Produces(404); + .Produces(StatusCodes.Status400BadRequest) + .Produces(StatusCodes.Status404NotFound) + .WithSummary("Get By Id") + .WithDescription("Get By Id") + .HasApiVersion(1.0); // ------------------------- diff --git a/BlogWebApp/BlogMinimalApi/ApiEndpoints/PostsApiEndpoints.cs b/BlogWebApp/BlogMinimalApi/ApiEndpoints/PostsApiEndpoints.cs index b89bb887..6ddf73e0 100644 --- a/BlogWebApp/BlogMinimalApi/ApiEndpoints/PostsApiEndpoints.cs +++ b/BlogWebApp/BlogMinimalApi/ApiEndpoints/PostsApiEndpoints.cs @@ -49,8 +49,13 @@ public void InstallApiRoutes(WebApplication app) return Results.Ok( mapper.Map>(posts)); }) + .WithName("GetAllPosts") .Produces>() - .Produces(404); + .Produces(StatusCodes.Status400BadRequest) + .Produces(StatusCodes.Status404NotFound) + .WithSummary("Get All Posts") + .WithDescription("Get All Posts") + .HasApiVersion(1.0); // POSTS ACTIVITY @@ -63,8 +68,13 @@ public void InstallApiRoutes(WebApplication app) ? Results.NotFound() : Results.Ok(activity); }) - .Produces() - .Produces(404); + .WithName("PostsActivity") + .Produces>() + .Produces(StatusCodes.Status400BadRequest) + .Produces(StatusCodes.Status404NotFound) + .WithSummary("Posts Activity") + .WithDescription("Posts Activity") + .HasApiVersion(1.0); // FILTERED POSTS @@ -86,8 +96,12 @@ public void InstallApiRoutes(WebApplication app) ? Results.NotFound() : Results.Ok(mapper.Map(posts)); }) + .WithName("GetPosts") .Produces() - .Produces(404); + .Produces(StatusCodes.Status400BadRequest) + .WithSummary("Get Posts") + .WithDescription("Get Posts") + .HasApiVersion(1.0); // USER POSTS @@ -111,8 +125,12 @@ public void InstallApiRoutes(WebApplication app) ? Results.NotFound() : Results.Ok(mapper.Map(posts)); }) + .WithName("UserPosts") .Produces() - .Produces(404); + .Produces(StatusCodes.Status400BadRequest) + .WithSummary("User Posts") + .WithDescription("User Posts") + .HasApiVersion(1.0); // GET POST BY ID @@ -134,8 +152,13 @@ public void InstallApiRoutes(WebApplication app) : Results.Ok( mapper.Map(post)); }) + .WithName("GetPostById") .Produces() - .Produces(404); + .Produces(StatusCodes.Status400BadRequest) + .Produces(StatusCodes.Status404NotFound) + .WithSummary("Get Post By Id") + .WithDescription("Get Post By Id") + .HasApiVersion(1.0); // ------------------------- From 1d7b275319b61a05248af586936043ae03facf27 Mon Sep 17 00:00:00 2001 From: Vitalii Lakatosh Date: Sat, 11 Apr 2026 00:21:04 +0300 Subject: [PATCH 02/33] Fix CQRS endpoints configurations --- .../Features/Accounts/Login/LoginEndpoint.cs | 3 ++- .../Accounts/Register/RegisterEndpoint.cs | 3 ++- .../CreateComment/CreateCommentEndpoint.cs | 7 +++--- .../GetCommentsByFilterCommand.cs | 7 ++++++ ...s => GetCommentsByFilterCommandHandler.cs} | 16 ++++++------ .../GetCommentsByFilterQuery.cs | 7 ------ .../GetCommentsByPostCommand.cs | 3 +++ .../GetCommentsByPostCommandHandler.cs | 22 ++++++++++++++++ .../GetCommentsByPostQuery.cs | 7 ------ .../GetCommentsByPostQueryHandler.cs | 25 ------------------- .../CreateMessage/CreateMessageEndpoint.cs | 7 +++--- .../GetRecipientMessagesQueryHandler.cs | 2 -- .../Posts/CreatePost/CreatePostCommand.cs | 2 +- .../CreatePost/CreatePostCommandHandler.cs | 6 ++--- .../Posts/CreatePost/CreatePostEndpoint.cs | 11 ++++---- .../Posts/CreatePost/CreatePostRequest.cs | 2 +- .../Posts/GetPosts/GetPostsCommand.cs | 7 ++++++ .../Posts/GetPosts/GetPostsCommandHandler.cs | 24 ++++++++++++++++++ .../Features/Posts/GetPosts/GetPostsQuery.cs | 7 ------ .../Posts/GetPosts/GetPostsQueryHandler.cs | 24 ------------------ .../Posts/UserPosts/UserPostsQuery.cs | 7 ------ .../Posts/UserPosts/UserPostsQueryHandler.cs | 25 ------------------- 22 files changed, 93 insertions(+), 131 deletions(-) create mode 100644 BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Comments/GetCommentsByFilter/GetCommentsByFilterCommand.cs rename BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Comments/GetCommentsByFilter/{GetCommentsByFilterQueryHandler.cs => GetCommentsByFilterCommandHandler.cs} (53%) delete mode 100644 BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Comments/GetCommentsByFilter/GetCommentsByFilterQuery.cs create mode 100644 BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Comments/GetCommentsByPost/GetCommentsByPostCommand.cs create mode 100644 BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Comments/GetCommentsByPost/GetCommentsByPostCommandHandler.cs delete mode 100644 BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Comments/GetCommentsByPost/GetCommentsByPostQuery.cs delete mode 100644 BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Comments/GetCommentsByPost/GetCommentsByPostQueryHandler.cs create mode 100644 BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Posts/GetPosts/GetPostsCommand.cs create mode 100644 BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Posts/GetPosts/GetPostsCommandHandler.cs delete mode 100644 BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Posts/GetPosts/GetPostsQuery.cs delete mode 100644 BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Posts/GetPosts/GetPostsQueryHandler.cs delete mode 100644 BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Posts/UserPosts/UserPostsQuery.cs delete mode 100644 BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Posts/UserPosts/UserPostsQueryHandler.cs diff --git a/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Accounts/Login/LoginEndpoint.cs b/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Accounts/Login/LoginEndpoint.cs index 8ed6406d..3b72bc0e 100644 --- a/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Accounts/Login/LoginEndpoint.cs +++ b/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Accounts/Login/LoginEndpoint.cs @@ -3,6 +3,7 @@ using Carter; using Mapster; using MediatR; +using Microsoft.AspNetCore.Mvc; namespace BlogVerticalSliceCQRSMinimalApi.Features.Accounts.Login; @@ -21,7 +22,7 @@ public void AddRoutes(IEndpointRouteBuilder app) .WithTags("Accounts"); group.MapPost(ApiRoutes.AccountsController.Login, - async (LoginRequest request, ISender sender) => + async ([FromBody] LoginRequest request, [FromServices] ISender sender) => { if (request is null) return Results.BadRequest(); diff --git a/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Accounts/Register/RegisterEndpoint.cs b/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Accounts/Register/RegisterEndpoint.cs index 8c16a3bd..3236e2d7 100644 --- a/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Accounts/Register/RegisterEndpoint.cs +++ b/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Accounts/Register/RegisterEndpoint.cs @@ -4,6 +4,7 @@ using Mapster; using MediatR; using Microsoft.AspNetCore.Identity; +using Microsoft.AspNetCore.Mvc; namespace BlogVerticalSliceCQRSMinimalApi.Features.Accounts.Register; @@ -22,7 +23,7 @@ public void AddRoutes(IEndpointRouteBuilder app) .WithTags("Accounts"); group.MapPost(ApiRoutes.AccountsController.Register, - async (RegisterRequest request, ISender sender) => + async ([FromBody] RegisterRequest request, [FromServices] ISender sender) => { var command = request.Adapt(); diff --git a/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Comments/CreateComment/CreateCommentEndpoint.cs b/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Comments/CreateComment/CreateCommentEndpoint.cs index d064d9f6..b78cfd10 100644 --- a/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Comments/CreateComment/CreateCommentEndpoint.cs +++ b/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Comments/CreateComment/CreateCommentEndpoint.cs @@ -4,6 +4,7 @@ using Carter; using Mapster; using MediatR; +using Microsoft.AspNetCore.Mvc; namespace BlogVerticalSliceCQRSMinimalApi.Features.Comments.CreateComment; @@ -22,9 +23,9 @@ public void AddRoutes(IEndpointRouteBuilder app) .WithTags("Comments"); group.MapPost(ApiRoutes.CommentsController.CreateComment, - async (CreateCommentRequest request, - ISender sender, - HttpContext context) => + async ([FromBody] CreateCommentRequest request, + [FromServices] ISender sender, + [FromServices] HttpContext context) => { var command = request.Adapt(); diff --git a/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Comments/GetCommentsByFilter/GetCommentsByFilterCommand.cs b/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Comments/GetCommentsByFilter/GetCommentsByFilterCommand.cs new file mode 100644 index 00000000..d6c881ec --- /dev/null +++ b/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Comments/GetCommentsByFilter/GetCommentsByFilterCommand.cs @@ -0,0 +1,7 @@ +using Blog.Contracts.V1.Responses.CommentsResponses; +using BlogVerticalSliceCQRSMinimalApi.CQRSExtensions; + +namespace BlogVerticalSliceCQRSMinimalApi.Features.Comments.GetCommentsByFilter; + +public record GetCommentsByFilterCommand(string OrderBy, string SortBy, int? CurrentPage, int? PageSize, string DisplayType) + : ICommand; diff --git a/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Comments/GetCommentsByFilter/GetCommentsByFilterQueryHandler.cs b/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Comments/GetCommentsByFilter/GetCommentsByFilterCommandHandler.cs similarity index 53% rename from BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Comments/GetCommentsByFilter/GetCommentsByFilterQueryHandler.cs rename to BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Comments/GetCommentsByFilter/GetCommentsByFilterCommandHandler.cs index 6bdf48d3..493bab77 100644 --- a/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Comments/GetCommentsByFilter/GetCommentsByFilterQueryHandler.cs +++ b/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Comments/GetCommentsByFilter/GetCommentsByFilterCommandHandler.cs @@ -6,19 +6,17 @@ namespace BlogVerticalSliceCQRSMinimalApi.Features.Comments.GetCommentsByFilter; -public class GetCommentsByFilterQueryHandler( - ICommentsService service, - IMapper mapper) - : IQueryHandler +public class GetCommentsByFilterCommandHandler(ICommentsService service, IMapper mapper) + : ICommandHandler { - public async Task Handle(GetCommentsByFilterQuery query, CancellationToken cancellationToken) + public async Task Handle(GetCommentsByFilterCommand command, CancellationToken cancellationToken) { - query = query with { CurrentPage = query.CurrentPage ?? 1 }; - query = query with { PageSize = 10 }; + command = command with { CurrentPage = command.CurrentPage ?? 1 }; + command = command with { PageSize = 10 }; var result = await service.GetPagedComments( - mapper.Map(query)); + mapper.Map(command)); return mapper.Map(result); } -} \ No newline at end of file +} diff --git a/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Comments/GetCommentsByFilter/GetCommentsByFilterQuery.cs b/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Comments/GetCommentsByFilter/GetCommentsByFilterQuery.cs deleted file mode 100644 index 9728be0c..00000000 --- a/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Comments/GetCommentsByFilter/GetCommentsByFilterQuery.cs +++ /dev/null @@ -1,7 +0,0 @@ -using Blog.Contracts.V1.Responses.CommentsResponses; -using BlogVerticalSliceCQRSMinimalApi.CQRSExtensions; - -namespace BlogVerticalSliceCQRSMinimalApi.Features.Comments.GetCommentsByFilter; - -public record GetCommentsByFilterQuery(string OrderBy, string SortBy, int? CurrentPage, int? PageSize, string DisplayType) - : SortParametersQuery(OrderBy, SortBy, CurrentPage, PageSize, DisplayType), IQuery; \ No newline at end of file diff --git a/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Comments/GetCommentsByPost/GetCommentsByPostCommand.cs b/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Comments/GetCommentsByPost/GetCommentsByPostCommand.cs new file mode 100644 index 00000000..0a0a3d7b --- /dev/null +++ b/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Comments/GetCommentsByPost/GetCommentsByPostCommand.cs @@ -0,0 +1,3 @@ +namespace BlogVerticalSliceCQRSMinimalApi.Features.Comments.GetCommentsByPost; + +public record GetCommentsByPostRequest(int PostId, string OrderBy, string SortBy, int? CurrentPage, int? PageSize, string DisplayType); \ No newline at end of file diff --git a/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Comments/GetCommentsByPost/GetCommentsByPostCommandHandler.cs b/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Comments/GetCommentsByPost/GetCommentsByPostCommandHandler.cs new file mode 100644 index 00000000..90715857 --- /dev/null +++ b/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Comments/GetCommentsByPost/GetCommentsByPostCommandHandler.cs @@ -0,0 +1,22 @@ +using AutoMapper; +using Blog.Contracts.V1.Responses.CommentsResponses; +using Blog.EntityServices.Interfaces; +using Blog.Services.Core.Dtos; +using BlogVerticalSliceCQRSMinimalApi.CQRSExtensions; + +namespace BlogVerticalSliceCQRSMinimalApi.Features.Comments.GetCommentsByPost; + +public class GetCommentsByPostCommandHandler(ICommentsService service, IMapper mapper) + : ICommandHandler +{ + public async Task Handle(GetCommentsByPostCommand command, CancellationToken cancellationToken) + { + command = command with { CurrentPage = command.CurrentPage ?? 1 }; + command = command with { PageSize = 10 }; + + var result = await service.GetPagedCommentsByPostId(command.PostId, + mapper.Map(command)); + + return mapper.Map(result); + } +} diff --git a/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Comments/GetCommentsByPost/GetCommentsByPostQuery.cs b/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Comments/GetCommentsByPost/GetCommentsByPostQuery.cs deleted file mode 100644 index 4a29247d..00000000 --- a/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Comments/GetCommentsByPost/GetCommentsByPostQuery.cs +++ /dev/null @@ -1,7 +0,0 @@ -using Blog.Contracts.V1.Responses.CommentsResponses; -using BlogVerticalSliceCQRSMinimalApi.CQRSExtensions; - -namespace BlogVerticalSliceCQRSMinimalApi.Features.Comments.GetCommentsByPost; - -public record GetCommentsByPostQuery(int PostId, string OrderBy, string SortBy, int? CurrentPage, int? PageSize, string DisplayType) - : SortParametersQuery(OrderBy, SortBy, CurrentPage, PageSize, DisplayType), IQuery; \ No newline at end of file diff --git a/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Comments/GetCommentsByPost/GetCommentsByPostQueryHandler.cs b/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Comments/GetCommentsByPost/GetCommentsByPostQueryHandler.cs deleted file mode 100644 index 3ab0245b..00000000 --- a/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Comments/GetCommentsByPost/GetCommentsByPostQueryHandler.cs +++ /dev/null @@ -1,25 +0,0 @@ -using AutoMapper; -using Blog.Contracts.V1.Responses.CommentsResponses; -using Blog.EntityServices.Interfaces; -using Blog.Services.Core.Dtos; -using BlogVerticalSliceCQRSMinimalApi.CQRSExtensions; - -namespace BlogVerticalSliceCQRSMinimalApi.Features.Comments.GetCommentsByPost; - -public class GetCommentsByPostQueryHandler( - ICommentsService service, - IMapper mapper) - : IQueryHandler -{ - public async Task Handle(GetCommentsByPostQuery query, CancellationToken cancellationToken) - { - query = query with { CurrentPage = query.CurrentPage ?? 1 }; - query = query with { PageSize = 10 }; - - var result = await service.GetPagedCommentsByPostId( - query.PostId, - mapper.Map(query)); - - return mapper.Map(result); - } -} \ No newline at end of file diff --git a/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Messages/CreateMessage/CreateMessageEndpoint.cs b/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Messages/CreateMessage/CreateMessageEndpoint.cs index 645fee19..59ae4400 100644 --- a/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Messages/CreateMessage/CreateMessageEndpoint.cs +++ b/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Messages/CreateMessage/CreateMessageEndpoint.cs @@ -4,6 +4,7 @@ using Carter; using Mapster; using MediatR; +using Microsoft.AspNetCore.Mvc; namespace BlogVerticalSliceCQRSMinimalApi.Features.Messages.CreateMessage; @@ -22,9 +23,9 @@ public void AddRoutes(IEndpointRouteBuilder app) .WithTags("Messages"); group.MapPost("/", - async (CreateMessageRequest request, - ISender sender, - HttpContext context) => + async ([FromBody] CreateMessageRequest request, + [FromServices] ISender sender, + [FromServices] HttpContext context) => { var command = request.Adapt(); diff --git a/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Messages/GetRecipientMessages/GetRecipientMessagesQueryHandler.cs b/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Messages/GetRecipientMessages/GetRecipientMessagesQueryHandler.cs index 91e82369..4dad8824 100644 --- a/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Messages/GetRecipientMessages/GetRecipientMessagesQueryHandler.cs +++ b/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Messages/GetRecipientMessages/GetRecipientMessagesQueryHandler.cs @@ -1,10 +1,8 @@ using AutoMapper; using Blog.Contracts.V1.Responses; -using Blog.Contracts.V1.Responses.Chart; using Blog.Data.Specifications; using Blog.EntityServices.Interfaces; using BlogVerticalSliceCQRSMinimalApi.CQRSExtensions; -using BlogVerticalSliceCQRSMinimalApi.Features.Comments.CommentsActivity; namespace BlogVerticalSliceCQRSMinimalApi.Features.Messages.GetRecipientMessages; diff --git a/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Posts/CreatePost/CreatePostCommand.cs b/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Posts/CreatePost/CreatePostCommand.cs index c2a446d7..aa1fe419 100644 --- a/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Posts/CreatePost/CreatePostCommand.cs +++ b/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Posts/CreatePost/CreatePostCommand.cs @@ -4,6 +4,6 @@ namespace BlogVerticalSliceCQRSMinimalApi.Features.Posts.CreatePost; -public record CreatePostCommand(string Title, string Description, string Content, string ImageUrl, +public record GetPostsCommand(string Title, string Description, string Content, string ImageUrl, string AuthorId, DateTime CreatedAt, IList Tags) : ICommand>; diff --git a/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Posts/CreatePost/CreatePostCommandHandler.cs b/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Posts/CreatePost/CreatePostCommandHandler.cs index 708f0198..fc2552f9 100644 --- a/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Posts/CreatePost/CreatePostCommandHandler.cs +++ b/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Posts/CreatePost/CreatePostCommandHandler.cs @@ -6,10 +6,10 @@ namespace BlogVerticalSliceCQRSMinimalApi.Features.Posts.CreatePost; -public class CreatePostCommandHandler(IPostsService service, IMapper mapper) - : ICommandHandler> +public class GetPostsCommandHandler(IPostsService service, IMapper mapper) + : ICommandHandler> { - public async Task> Handle(CreatePostCommand command, CancellationToken cancellationToken) + public async Task> Handle(GetPostsCommand command, CancellationToken cancellationToken) { var post = new Post { diff --git a/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Posts/CreatePost/CreatePostEndpoint.cs b/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Posts/CreatePost/CreatePostEndpoint.cs index ffabab51..c2991471 100644 --- a/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Posts/CreatePost/CreatePostEndpoint.cs +++ b/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Posts/CreatePost/CreatePostEndpoint.cs @@ -4,10 +4,11 @@ using Carter; using Mapster; using MediatR; +using Microsoft.AspNetCore.Mvc; namespace BlogVerticalSliceCQRSMinimalApi.Features.Posts.CreatePost; -public class CreatePostEndpoint : ICarterModule +public class GetPostsEndpoint : ICarterModule { public void AddRoutes(IEndpointRouteBuilder app) { @@ -22,11 +23,11 @@ public void AddRoutes(IEndpointRouteBuilder app) .WithTags("Posts"); group.MapPost("/", - async (CreatePostRequest request, - ISender sender, - HttpContext context) => + async ([FromBody] GetPostsRequest request, + [FromServices] ISender sender, + [FromServices] HttpContext context) => { - var command = request.Adapt(); + var command = request.Adapt(); var result = await sender.Send(command); diff --git a/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Posts/CreatePost/CreatePostRequest.cs b/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Posts/CreatePost/CreatePostRequest.cs index 11922b88..4f57be8b 100644 --- a/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Posts/CreatePost/CreatePostRequest.cs +++ b/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Posts/CreatePost/CreatePostRequest.cs @@ -2,5 +2,5 @@ namespace BlogVerticalSliceCQRSMinimalApi.Features.Posts.CreatePost; -public class CreatePostRequest(string Title, string Description, string Content, string ImageUrl, +public class GetPostsRequest(string Title, string Description, string Content, string ImageUrl, string AuthorId, DateTime CreatedAt, IList Tags); \ No newline at end of file diff --git a/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Posts/GetPosts/GetPostsCommand.cs b/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Posts/GetPosts/GetPostsCommand.cs new file mode 100644 index 00000000..405268ab --- /dev/null +++ b/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Posts/GetPosts/GetPostsCommand.cs @@ -0,0 +1,7 @@ +using Blog.Contracts.V1.Responses.PostsResponses; +using BlogVerticalSliceCQRSMinimalApi.CQRSExtensions; + +namespace BlogVerticalSliceCQRSMinimalApi.Features.Posts.GetPosts; + +public record GetPostsCommand(string OrderBy, string SortBy, int? CurrentPage, int? PageSize, string DisplayType, string Tag) + : ICommand; diff --git a/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Posts/GetPosts/GetPostsCommandHandler.cs b/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Posts/GetPosts/GetPostsCommandHandler.cs new file mode 100644 index 00000000..7ecad21e --- /dev/null +++ b/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Posts/GetPosts/GetPostsCommandHandler.cs @@ -0,0 +1,24 @@ +using AutoMapper; +using Blog.Contracts.V1.Responses.PostsResponses; +using Blog.EntityServices.Interfaces; +using Blog.Services.Core.Dtos.Posts; +using BlogVerticalSliceCQRSMinimalApi.CQRSExtensions; + +namespace BlogVerticalSliceCQRSMinimalApi.Features.Posts.GetPosts; + +public class GetPostsCommandCommandHandler(IPostsService service, IMapper mapper) + : ICommandHandler +{ + public async Task Handle(GetPostsCommand command, CancellationToken cancellationToken) + { + command = command with { OrderBy = command.OrderBy ?? "asc" }; + command = command with { SortBy = command.SortBy ?? "Title" }; + command = command with { CurrentPage = command.CurrentPage ?? 1 }; + command = command with { PageSize = command.PageSize ?? 10 }; + + var posts = await service.GetPostsAsync( + mapper.Map(command)); + + return mapper.Map(posts); + } +} diff --git a/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Posts/GetPosts/GetPostsQuery.cs b/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Posts/GetPosts/GetPostsQuery.cs deleted file mode 100644 index 3b7ef6df..00000000 --- a/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Posts/GetPosts/GetPostsQuery.cs +++ /dev/null @@ -1,7 +0,0 @@ -using Blog.Contracts.V1.Responses.PostsResponses; -using BlogVerticalSliceCQRSMinimalApi.CQRSExtensions; - -namespace BlogVerticalSliceCQRSMinimalApi.Features.Posts.GetPosts; - -public record GetPostsQuery(string OrderBy, string SortBy, int? CurrentPage, int? PageSize, string DisplayType, string Tag) - : SearchParametersQuery(OrderBy, SortBy, CurrentPage, PageSize, DisplayType), IQuery; \ No newline at end of file diff --git a/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Posts/GetPosts/GetPostsQueryHandler.cs b/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Posts/GetPosts/GetPostsQueryHandler.cs deleted file mode 100644 index aba8a06f..00000000 --- a/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Posts/GetPosts/GetPostsQueryHandler.cs +++ /dev/null @@ -1,24 +0,0 @@ -using AutoMapper; -using Blog.Contracts.V1.Responses.PostsResponses; -using Blog.EntityServices.Interfaces; -using Blog.Services.Core.Dtos.Posts; -using BlogVerticalSliceCQRSMinimalApi.CQRSExtensions; - -namespace BlogVerticalSliceCQRSMinimalApi.Features.Posts.GetPosts; - -public class GetPostsQueryHandler(IPostsService service, IMapper mapper) - : IQueryHandler -{ - public async Task Handle(GetPostsQuery query, CancellationToken cancellationToken) - { - query = query with { OrderBy = query.OrderBy ?? "asc" }; - query = query with { SortBy = query.SortBy ?? "Title" }; - query = query with { CurrentPage = query.CurrentPage ?? 1 }; - query = query with { PageSize = query.PageSize ?? 10 }; - - var posts = await service.GetPostsAsync( - mapper.Map(query)); - - return mapper.Map(posts); - } -} \ No newline at end of file diff --git a/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Posts/UserPosts/UserPostsQuery.cs b/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Posts/UserPosts/UserPostsQuery.cs deleted file mode 100644 index f00c5064..00000000 --- a/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Posts/UserPosts/UserPostsQuery.cs +++ /dev/null @@ -1,7 +0,0 @@ -using Blog.Contracts.V1.Responses.PostsResponses; -using BlogVerticalSliceCQRSMinimalApi.CQRSExtensions; - -namespace BlogVerticalSliceCQRSMinimalApi.Features.Posts.UserPosts; - -public record UserPostsQuery(string OrderBy, string SortBy, int? CurrentPage, int? PageSize, string DisplayType, string Tag, string Id) - : SearchParametersQuery(OrderBy, SortBy, CurrentPage, PageSize, DisplayType), IQuery; \ No newline at end of file diff --git a/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Posts/UserPosts/UserPostsQueryHandler.cs b/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Posts/UserPosts/UserPostsQueryHandler.cs deleted file mode 100644 index 6ab993d5..00000000 --- a/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Posts/UserPosts/UserPostsQueryHandler.cs +++ /dev/null @@ -1,25 +0,0 @@ -using AutoMapper; -using Blog.Contracts.V1.Responses.PostsResponses; -using Blog.EntityServices.Interfaces; -using Blog.Services.Core.Dtos.Posts; -using BlogVerticalSliceCQRSMinimalApi.CQRSExtensions; - -namespace BlogVerticalSliceCQRSMinimalApi.Features.Posts.UserPosts; - -public class UserPostsQueryHandler(IPostsService service, IMapper mapper) - : IQueryHandler -{ - public async Task Handle(UserPostsQuery query, CancellationToken cancellationToken) - { - query = query with { OrderBy = query.OrderBy ?? "asc" }; - query = query with { SortBy = query.SortBy ?? "Title" }; - query = query with { CurrentPage = query.CurrentPage ?? 1 }; - query = query with { PageSize = query.PageSize ?? 10 }; - - var posts = await service.GetUserPostsAsync( - query.Id, - mapper.Map(query)); - - return mapper.Map(posts); - } -} \ No newline at end of file From 388f9c226d6327111781ba5917b25cf3a2378a60 Mon Sep 17 00:00:00 2001 From: Vitalii Lakatosh Date: Sat, 11 Apr 2026 00:22:33 +0300 Subject: [PATCH 03/33] Add CQRS requests --- .../GetCommentsByFilter/GetCommentsByFilterRequest.cs | 3 +++ .../Comments/GetCommentsByPost/GetCommentsByPostRequest.cs | 7 +++++++ 2 files changed, 10 insertions(+) create mode 100644 BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Comments/GetCommentsByFilter/GetCommentsByFilterRequest.cs create mode 100644 BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Comments/GetCommentsByPost/GetCommentsByPostRequest.cs diff --git a/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Comments/GetCommentsByFilter/GetCommentsByFilterRequest.cs b/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Comments/GetCommentsByFilter/GetCommentsByFilterRequest.cs new file mode 100644 index 00000000..5d291f5d --- /dev/null +++ b/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Comments/GetCommentsByFilter/GetCommentsByFilterRequest.cs @@ -0,0 +1,3 @@ +namespace BlogVerticalSliceCQRSMinimalApi.Features.Comments.GetCommentsByFilter; + +public record GetCommentsByFilterRequest(string OrderBy, string SortBy, int? CurrentPage, int? PageSize, string DisplayTypel); diff --git a/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Comments/GetCommentsByPost/GetCommentsByPostRequest.cs b/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Comments/GetCommentsByPost/GetCommentsByPostRequest.cs new file mode 100644 index 00000000..18d00e08 --- /dev/null +++ b/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Comments/GetCommentsByPost/GetCommentsByPostRequest.cs @@ -0,0 +1,7 @@ +using Blog.Contracts.V1.Responses.CommentsResponses; +using BlogVerticalSliceCQRSMinimalApi.CQRSExtensions; + +namespace BlogVerticalSliceCQRSMinimalApi.Features.Comments.GetCommentsByPost; + +public record GetCommentsByPostCommand(int PostId, string OrderBy, string SortBy, int? CurrentPage, int? PageSize, string DisplayType) + : ICommand; \ No newline at end of file From 7e35223ed82f46500ce5cd58e1d1fbacd5ffe02c Mon Sep 17 00:00:00 2001 From: Vitalii Lakatosh Date: Sat, 11 Apr 2026 00:23:47 +0300 Subject: [PATCH 04/33] Add Get posts command and command handler in posts feature --- .../Posts/GetPosts/GetPostsRequest.cs | 3 +++ .../Posts/UserPosts/UserPostsCommand.cs | 7 ++++++ .../UserPosts/UserPostsCommandHandler.cs | 25 +++++++++++++++++++ 3 files changed, 35 insertions(+) create mode 100644 BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Posts/GetPosts/GetPostsRequest.cs create mode 100644 BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Posts/UserPosts/UserPostsCommand.cs create mode 100644 BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Posts/UserPosts/UserPostsCommandHandler.cs diff --git a/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Posts/GetPosts/GetPostsRequest.cs b/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Posts/GetPosts/GetPostsRequest.cs new file mode 100644 index 00000000..9a4a388b --- /dev/null +++ b/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Posts/GetPosts/GetPostsRequest.cs @@ -0,0 +1,3 @@ +namespace BlogVerticalSliceCQRSMinimalApi.Features.Posts.GetPosts; + +public class UserPostsRequest(string OrderBy, string SortBy, int? CurrentPage, int? PageSize, string DisplayType, string Tag); \ No newline at end of file diff --git a/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Posts/UserPosts/UserPostsCommand.cs b/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Posts/UserPosts/UserPostsCommand.cs new file mode 100644 index 00000000..d2d2c37d --- /dev/null +++ b/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Posts/UserPosts/UserPostsCommand.cs @@ -0,0 +1,7 @@ +using Blog.Contracts.V1.Responses.PostsResponses; +using BlogVerticalSliceCQRSMinimalApi.CQRSExtensions; + +namespace BlogVerticalSliceCQRSMinimalApi.Features.Posts.UserPosts; + +public record UserPostsCommand(string OrderBy, string SortBy, int? CurrentPage, int? PageSize, string DisplayType, string Tag, string Id) + : ICommand; diff --git a/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Posts/UserPosts/UserPostsCommandHandler.cs b/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Posts/UserPosts/UserPostsCommandHandler.cs new file mode 100644 index 00000000..1bb6bd46 --- /dev/null +++ b/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Posts/UserPosts/UserPostsCommandHandler.cs @@ -0,0 +1,25 @@ +using AutoMapper; +using Blog.Contracts.V1.Responses.PostsResponses; +using Blog.EntityServices.Interfaces; +using Blog.Services.Core.Dtos.Posts; +using BlogVerticalSliceCQRSMinimalApi.CQRSExtensions; + +namespace BlogVerticalSliceCQRSMinimalApi.Features.Posts.UserPosts; + +public class UserPostsCommandHandler(IPostsService service, IMapper mapper) + : ICommandHandler +{ + public async Task Handle(UserPostsCommand command, CancellationToken cancellationToken) + { + command = command with { OrderBy = command.OrderBy ?? "asc" }; + command = command with { SortBy = command.SortBy ?? "Title" }; + command = command with { CurrentPage = command.CurrentPage ?? 1 }; + command = command with { PageSize = command.PageSize ?? 10 }; + + var posts = await service.GetUserPostsAsync( + command.Id, + mapper.Map(command)); + + return mapper.Map(posts); + } +} From 4ed23faef5a6411e76b4aabfdd5043ad551cd7e3 Mon Sep 17 00:00:00 2001 From: Vitalii Lakatosh Date: Sun, 12 Apr 2026 00:24:17 +0300 Subject: [PATCH 05/33] Add User posts endpoint --- .../Posts/UserPosts/UserPostsEndpoint.cs | 47 +++++++++++++++++++ .../Posts/UserPosts/UserPostsRequest.cs | 3 ++ 2 files changed, 50 insertions(+) create mode 100644 BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Posts/UserPosts/UserPostsEndpoint.cs create mode 100644 BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Posts/UserPosts/UserPostsRequest.cs diff --git a/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Posts/UserPosts/UserPostsEndpoint.cs b/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Posts/UserPosts/UserPostsEndpoint.cs new file mode 100644 index 00000000..9b77c580 --- /dev/null +++ b/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Posts/UserPosts/UserPostsEndpoint.cs @@ -0,0 +1,47 @@ +using Asp.Versioning; +using Blog.Contracts.V1; +using Blog.Contracts.V1.Responses.PostsResponses; +using Carter; +using Mapster; +using MediatR; +using Microsoft.AspNetCore.Mvc; + +namespace BlogVerticalSliceCQRSMinimalApi.Features.Posts.UserPosts; + +public class UserPostsEndpoint : ICarterModule +{ + public void AddRoutes(IEndpointRouteBuilder app) + { + var versionSet = app.NewApiVersionSet() + .HasApiVersion(new ApiVersion(1, 0)) + .ReportApiVersions() + .Build(); + + var group = app.MapGroup(ApiRoutes.PostsController.Posts) + .WithApiVersionSet(versionSet) + .MapToApiVersion(1.0) + .WithTags("Posts"); + + group.MapPost(ApiRoutes.PostsController.UserPosts, + async ([FromBody] UserPostsRequest request, + [FromRoute] string id, + [FromServices] ISender sender) => + { + var command = request.Adapt(); + command = command with { Id = id }; + + var result = await sender.Send(command); + + return result is null + ? Results.NotFound() + : Results.Ok(result); + }) + //.RequireAuthorization() + .WithName("UserPosts") + .Produces() + .Produces(StatusCodes.Status400BadRequest) + .WithSummary("User Posts") + .WithDescription("User Posts") + .HasApiVersion(1.0); + } +} diff --git a/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Posts/UserPosts/UserPostsRequest.cs b/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Posts/UserPosts/UserPostsRequest.cs new file mode 100644 index 00000000..9eedff1b --- /dev/null +++ b/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Posts/UserPosts/UserPostsRequest.cs @@ -0,0 +1,3 @@ +namespace BlogVerticalSliceCQRSMinimalApi.Features.Posts.UserPosts; + +public class UserPostsRequest(string OrderBy, string SortBy, int? CurrentPage, int? PageSize, string DisplayType, string Tag, string Id); \ No newline at end of file From 2e20bbc5bcf7d152a89cf1fd468ff97acb8ad223 Mon Sep 17 00:00:00 2001 From: Vitalii Lakatosh Date: Sun, 12 Apr 2026 00:24:34 +0300 Subject: [PATCH 06/33] Add Posts activity endpoint --- .../PostsActivity/PostsActivityEndpoint.cs | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Posts/PostsActivity/PostsActivityEndpoint.cs diff --git a/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Posts/PostsActivity/PostsActivityEndpoint.cs b/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Posts/PostsActivity/PostsActivityEndpoint.cs new file mode 100644 index 00000000..9fa8f45f --- /dev/null +++ b/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Posts/PostsActivity/PostsActivityEndpoint.cs @@ -0,0 +1,29 @@ +using Blog.Contracts.V1; +using Blog.Contracts.V1.Responses.Chart; +using Carter; +using MediatR; +using Microsoft.AspNetCore.Mvc; + +namespace BlogVerticalSliceCQRSMinimalApi.Features.Posts.PostsActivity; + +public class PostsActivityEndpoint : ICarterModule +{ + public void AddRoutes(IEndpointRouteBuilder app) + { + app.MapGet(ApiRoutes.PostsController.PostsActivity, async ([FromServices] ISender sender) => + { + var result = await sender.Send(new PostsActivityQuery()); + + return result == null + ? Results.NotFound() + : Results.Ok(result); + }) + .WithName("PostsActivity") + .Produces>() + .Produces(StatusCodes.Status400BadRequest) + .Produces(StatusCodes.Status404NotFound) + .WithSummary("Posts Activity") + .WithDescription("Posts Activity") + .HasApiVersion(1.0); + } +} \ No newline at end of file From b95d0601a93a2e4aea066401d223ad2c88d10938 Mon Sep 17 00:00:00 2001 From: Vitalii Lakatosh Date: Sun, 12 Apr 2026 00:24:47 +0300 Subject: [PATCH 07/33] Add Get posts endpoint --- .../Posts/GetPosts/GetPostsEndpoint.cs | 45 +++++++++++++++++++ 1 file changed, 45 insertions(+) create mode 100644 BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Posts/GetPosts/GetPostsEndpoint.cs diff --git a/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Posts/GetPosts/GetPostsEndpoint.cs b/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Posts/GetPosts/GetPostsEndpoint.cs new file mode 100644 index 00000000..1b97357c --- /dev/null +++ b/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Posts/GetPosts/GetPostsEndpoint.cs @@ -0,0 +1,45 @@ +using Asp.Versioning; +using Blog.Contracts.V1; +using Blog.Contracts.V1.Responses.PostsResponses; +using Carter; +using Mapster; +using MediatR; +using Microsoft.AspNetCore.Mvc; + +namespace BlogVerticalSliceCQRSMinimalApi.Features.Posts.GetPosts; + +public class UserPostsEndpoint : ICarterModule +{ + public void AddRoutes(IEndpointRouteBuilder app) + { + var versionSet = app.NewApiVersionSet() + .HasApiVersion(new ApiVersion(1, 0)) + .ReportApiVersions() + .Build(); + + var group = app.MapGroup(ApiRoutes.PostsController.Posts) + .WithApiVersionSet(versionSet) + .MapToApiVersion(1.0) + .WithTags("Posts"); + + group.MapPost(ApiRoutes.PostsController.GetPosts, + async ([FromBody] UserPostsRequest request, + [FromServices] ISender sender) => + { + var command = request.Adapt(); + + var result = await sender.Send(command); + + return result is null + ? Results.NotFound() + : Results.Ok(result); + }) + //.RequireAuthorization() + .WithName("GetPosts") + .Produces() + .Produces(StatusCodes.Status400BadRequest) + .WithSummary("Get Posts") + .WithDescription("Get Posts") + .HasApiVersion(1.0); + } +} From d0a58d898288cfe46759353833522e1985e96086 Mon Sep 17 00:00:00 2001 From: Vitalii Lakatosh Date: Sun, 12 Apr 2026 00:25:05 +0300 Subject: [PATCH 08/33] Add Get post by id endpoint --- .../Posts/GetPostById/GetPostByIdEndpoint.cs | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Posts/GetPostById/GetPostByIdEndpoint.cs diff --git a/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Posts/GetPostById/GetPostByIdEndpoint.cs b/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Posts/GetPostById/GetPostByIdEndpoint.cs new file mode 100644 index 00000000..e63bf5bb --- /dev/null +++ b/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Posts/GetPostById/GetPostByIdEndpoint.cs @@ -0,0 +1,30 @@ +using Blog.Contracts.V1; +using Blog.Contracts.V1.Responses.PostsResponses; +using Blog.Contracts.V1.Responses.UsersResponses; +using Carter; +using MediatR; +using Microsoft.AspNetCore.Mvc; + +namespace BlogVerticalSliceCQRSMinimalApi.Features.Posts.GetPostById; + +public class GetPostByIdEndpoint : ICarterModule +{ + public void AddRoutes(IEndpointRouteBuilder app) + { + app.MapGet(ApiRoutes.PostsController.Show, async ([FromRoute] int id, [FromServices] ISender sender) => + { + var result = await sender.Send(new GetPostByIdQuery(Id: id)); + + return result == null + ? Results.NotFound() + : Results.Ok(result); + }) + .WithName("GetPostById") + .Produces() + .Produces(StatusCodes.Status400BadRequest) + .Produces(StatusCodes.Status404NotFound) + .WithSummary("Get Post By Id") + .WithDescription("Get Post By Id") + .HasApiVersion(1.0); + } +} \ No newline at end of file From 7dde66e5522ec58da5136e95101ca81d3996f62e Mon Sep 17 00:00:00 2001 From: Vitalii Lakatosh Date: Mon, 13 Apr 2026 00:25:32 +0300 Subject: [PATCH 09/33] Add get sender messages endpoint --- .../GetSenderMessagesEndpoint.cs | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Messages/GetSenderMessages/GetSenderMessagesEndpoint.cs diff --git a/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Messages/GetSenderMessages/GetSenderMessagesEndpoint.cs b/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Messages/GetSenderMessages/GetSenderMessagesEndpoint.cs new file mode 100644 index 00000000..9cabd05d --- /dev/null +++ b/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Messages/GetSenderMessages/GetSenderMessagesEndpoint.cs @@ -0,0 +1,32 @@ +using Blog.Contracts.V1; +using Blog.Contracts.V1.Responses; +using Carter; +using MediatR; +using Microsoft.AspNetCore.Mvc; + +namespace BlogVerticalSliceCQRSMinimalApi.Features.Messages.GetSenderMessages; + +public class GetSenderMessagesEndpoint : ICarterModule +{ + public void AddRoutes(IEndpointRouteBuilder app) + { + app.MapGet(ApiRoutes.MessagesController.GetSenderMessages, async ([FromRoute] string senderEmail, [FromServices] ISender sender) => + { + if (string.IsNullOrEmpty(senderEmail)) + return Results.BadRequest("Something went wrong"); + + var result = await sender.Send(new GetSenderMessagesQuery(SenderEmail: senderEmail)); + + return result == null + ? Results.NotFound() + : Results.Ok(result); + }) + .WithName("GetSenderMessages") + .Produces>() + .Produces(StatusCodes.Status400BadRequest) + .Produces(StatusCodes.Status404NotFound) + .WithSummary("Get Sender Messages") + .WithDescription("Get Sender Messages") + .HasApiVersion(1.0); + } +} \ No newline at end of file From 43e2f0911a168ee01f140274ddcbaeb7f1b7c072 Mon Sep 17 00:00:00 2001 From: Vitalii Lakatosh Date: Mon, 13 Apr 2026 00:25:58 +0300 Subject: [PATCH 10/33] Add Get recipient messages endpoint --- .../GetRecipientMessagesEndpoint.cs | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Messages/GetRecipientMessages/GetRecipientMessagesEndpoint.cs diff --git a/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Messages/GetRecipientMessages/GetRecipientMessagesEndpoint.cs b/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Messages/GetRecipientMessages/GetRecipientMessagesEndpoint.cs new file mode 100644 index 00000000..50689545 --- /dev/null +++ b/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Messages/GetRecipientMessages/GetRecipientMessagesEndpoint.cs @@ -0,0 +1,32 @@ +using Blog.Contracts.V1; +using Blog.Contracts.V1.Responses; +using Carter; +using MediatR; +using Microsoft.AspNetCore.Mvc; + +namespace BlogVerticalSliceCQRSMinimalApi.Features.Messages.GetRecipientMessages; + +public class GetRecipientMessagesEndpoint : ICarterModule +{ + public void AddRoutes(IEndpointRouteBuilder app) + { + app.MapGet(ApiRoutes.MessagesController.GetRecipientMessages, async ([FromRoute] string recipientId, [FromServices] ISender sender) => + { + if (string.IsNullOrEmpty(recipientId)) + return Results.BadRequest("Something went wrong"); + + var result = await sender.Send(new GetRecipientMessagesQuery(RecipientId: recipientId)); + + return result == null + ? Results.NotFound() + : Results.Ok(result); + }) + .WithName("GetRecipientMessages") + .Produces>() + .Produces(StatusCodes.Status400BadRequest) + .Produces(StatusCodes.Status404NotFound) + .WithSummary("Get Recipient Messages") + .WithDescription("Get Recipient Messages") + .HasApiVersion(1.0); + } +} \ No newline at end of file From 725732928ce04476a95df6f1bf73173d9afb7821 Mon Sep 17 00:00:00 2001 From: Vitalii Lakatosh Date: Mon, 13 Apr 2026 00:26:26 +0300 Subject: [PATCH 11/33] Add get by id message endpoint --- .../Messages/GetById/GetByIdEndpoint.cs | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Messages/GetById/GetByIdEndpoint.cs diff --git a/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Messages/GetById/GetByIdEndpoint.cs b/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Messages/GetById/GetByIdEndpoint.cs new file mode 100644 index 00000000..252cb506 --- /dev/null +++ b/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Messages/GetById/GetByIdEndpoint.cs @@ -0,0 +1,29 @@ +using Blog.Contracts.V1; +using Blog.Contracts.V1.Responses; +using Carter; +using MediatR; +using Microsoft.AspNetCore.Mvc; + +namespace BlogVerticalSliceCQRSMinimalApi.Features.Messages.GetById; + +public class GetByIdEndpoint : ICarterModule +{ + public void AddRoutes(IEndpointRouteBuilder app) + { + app.MapGet(ApiRoutes.MessagesController.Show, async ([FromRoute] int id, [FromServices] ISender sender) => + { + var result = await sender.Send(new GetByIdQuery(Id: id)); + + return result == null + ? Results.NotFound() + : Results.Ok(result); + }) + .WithName("GetById") + .Produces() + .Produces(StatusCodes.Status400BadRequest) + .Produces(StatusCodes.Status404NotFound) + .WithSummary("Get By Id") + .WithDescription("Get By Id") + .HasApiVersion(1.0); + } +} \ No newline at end of file From 77a48d29990247ff9dec608adbe1705066b92d49 Mon Sep 17 00:00:00 2001 From: Vitalii Lakatosh Date: Mon, 13 Apr 2026 00:26:50 +0300 Subject: [PATCH 12/33] Add Get all messages endpoint --- .../Messages/GetAll/GetAllEndpoint.cs | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Messages/GetAll/GetAllEndpoint.cs diff --git a/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Messages/GetAll/GetAllEndpoint.cs b/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Messages/GetAll/GetAllEndpoint.cs new file mode 100644 index 00000000..d9c7c2b6 --- /dev/null +++ b/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Messages/GetAll/GetAllEndpoint.cs @@ -0,0 +1,28 @@ +using Blog.Contracts.V1.Responses; +using Carter; +using MediatR; +using Microsoft.AspNetCore.Mvc; + +namespace BlogVerticalSliceCQRSMinimalApi.Features.Messages.GetAll; + +public class GetAllEndpoint : ICarterModule +{ + public void AddRoutes(IEndpointRouteBuilder app) + { + app.MapGet("/comments", async ([FromServices] ISender sender) => + { + var result = await sender.Send(new GetAllQuery()); + + return result == null + ? Results.NotFound() + : Results.Ok(result); + }) + .WithName("GetAll") + .Produces>() + .Produces(StatusCodes.Status400BadRequest) + .Produces(StatusCodes.Status404NotFound) + .WithSummary("Get All") + .WithDescription("Get All") + .HasApiVersion(1.0); + } +} \ No newline at end of file From d0975af9ddd62e61c29b84006e2fde2d0de26b13 Mon Sep 17 00:00:00 2001 From: Vitalii Lakatosh Date: Tue, 14 Apr 2026 00:27:27 +0300 Subject: [PATCH 13/33] Add get all posts endpoint --- .../Posts/GetAllPosts/GetAllPostsEndpoint.cs | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Posts/GetAllPosts/GetAllPostsEndpoint.cs diff --git a/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Posts/GetAllPosts/GetAllPostsEndpoint.cs b/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Posts/GetAllPosts/GetAllPostsEndpoint.cs new file mode 100644 index 00000000..f0ff0040 --- /dev/null +++ b/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Posts/GetAllPosts/GetAllPostsEndpoint.cs @@ -0,0 +1,30 @@ +using Blog.Contracts.V1; +using Blog.Contracts.V1.Responses.PostsResponses; +using Blog.Contracts.V1.Responses.UsersResponses; +using Carter; +using MediatR; +using Microsoft.AspNetCore.Mvc; + +namespace BlogVerticalSliceCQRSMinimalApi.Features.Posts.GetAllPosts; + +public class GetAllPostsEndpoint : ICarterModule +{ + public void AddRoutes(IEndpointRouteBuilder app) + { + app.MapGet("/posts", async ([FromServices] ISender sender) => + { + var result = await sender.Send(new GetAllPostsQuery()); + + return result == null + ? Results.NotFound() + : Results.Ok(result); + }) + .WithName("GetAllPosts") + .Produces>() + .Produces(StatusCodes.Status400BadRequest) + .Produces(StatusCodes.Status404NotFound) + .WithSummary("Get All Posts") + .WithDescription("Get All Posts") + .HasApiVersion(1.0); + } +} \ No newline at end of file From e977375f8c6051e342391421a67d6b97753639d9 Mon Sep 17 00:00:00 2001 From: Vitalii Lakatosh Date: Tue, 14 Apr 2026 00:27:43 +0300 Subject: [PATCH 14/33] Add Health check endpoint --- .../Initialize/InitializeEndpoint.cs | 51 +++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100644 BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/HealthCheck/Initialize/InitializeEndpoint.cs diff --git a/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/HealthCheck/Initialize/InitializeEndpoint.cs b/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/HealthCheck/Initialize/InitializeEndpoint.cs new file mode 100644 index 00000000..00c73e34 --- /dev/null +++ b/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/HealthCheck/Initialize/InitializeEndpoint.cs @@ -0,0 +1,51 @@ +using Blog.Contracts.V1; +using Blog.Contracts.V1.Responses.UsersResponses; +using Carter; +using MediatR; +using Microsoft.AspNetCore.Mvc; + +namespace BlogVerticalSliceCQRSMinimalApi.Features.HealthCheck.Initialize; + +public class InitializeEndpoint : ICarterModule +{ + public void AddRoutes(IEndpointRouteBuilder app) + { + app.MapGet("/health-check", async ([FromServices] ISender sender) => + { + try + { + var result = await sender.Send(new InitializeQuery()); + /* + var response = new HealthCheckResponse + { + Status = report.Status.ToString(), + Checks = report.Entries.Select(x => new HealthCheck + { + Component = x.Key, + Status = x.Value.Status.ToString(), + Description = x.Value.Description, + }), + Duration = report.TotalDuration, + }; + + return report.Status == HealthStatus.Healthy + ? this.Ok(response) + : this.StatusCode((int)HttpStatusCode.ServiceUnavailable, response);*/ + + return Results.Ok(); + } + catch (Exception e) + { + return Results.BadRequest(e.InnerException); + } + }) + //.RequireAuthorization() + .WithName("Initialize") + .Produces() + .Produces(StatusCodes.Status400BadRequest) + .Produces(StatusCodes.Status404NotFound) + .WithSummary("Initialize") + .WithDescription("Initialize") + .HasApiVersion(1.0); + } +} \ No newline at end of file From 5ad893e4932aaa778374e7e9a4a0d554bb6d1f63 Mon Sep 17 00:00:00 2001 From: Vitalii Lakatosh Date: Tue, 14 Apr 2026 00:29:03 +0300 Subject: [PATCH 15/33] Add get paged comments command and command handler in comments feature --- .../GetPagedCommentsCommand.cs | 7 ++++++ .../GetPagedCommentsCommandHandler.cs | 22 +++++++++++++++++++ .../GetPagedCommentsRequest.cs | 3 +++ 3 files changed, 32 insertions(+) create mode 100644 BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Comments/GetPagedComments/GetPagedCommentsCommand.cs create mode 100644 BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Comments/GetPagedComments/GetPagedCommentsCommandHandler.cs create mode 100644 BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Comments/GetPagedComments/GetPagedCommentsRequest.cs diff --git a/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Comments/GetPagedComments/GetPagedCommentsCommand.cs b/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Comments/GetPagedComments/GetPagedCommentsCommand.cs new file mode 100644 index 00000000..487c2ec8 --- /dev/null +++ b/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Comments/GetPagedComments/GetPagedCommentsCommand.cs @@ -0,0 +1,7 @@ +using Blog.Contracts.V1.Responses.CommentsResponses; +using BlogVerticalSliceCQRSMinimalApi.CQRSExtensions; + +namespace BlogVerticalSliceCQRSMinimalApi.Features.Comments.GetPagedComments; + +public record GetPagedCommentsCommand(string OrderBy, string SortBy, int? CurrentPage, int? PageSize, string DisplayType) + : ICommand; diff --git a/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Comments/GetPagedComments/GetPagedCommentsCommandHandler.cs b/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Comments/GetPagedComments/GetPagedCommentsCommandHandler.cs new file mode 100644 index 00000000..fa74ead9 --- /dev/null +++ b/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Comments/GetPagedComments/GetPagedCommentsCommandHandler.cs @@ -0,0 +1,22 @@ +using AutoMapper; +using Blog.Contracts.V1.Responses.CommentsResponses; +using Blog.EntityServices.Interfaces; +using Blog.Services.Core.Dtos; +using BlogVerticalSliceCQRSMinimalApi.CQRSExtensions; + +namespace BlogVerticalSliceCQRSMinimalApi.Features.Comments.GetPagedComments; + +public class GetCommentsByFilterCommandHandler(ICommentsService service, IMapper mapper) + : ICommandHandler +{ + public async Task Handle(GetPagedCommentsCommand command, CancellationToken cancellationToken) + { + command = command with { CurrentPage = command.CurrentPage ?? 1 }; + command = command with { PageSize = 10 }; + + var result = await service.GetPagedComments( + mapper.Map(command)); + + return mapper.Map(result); + } +} diff --git a/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Comments/GetPagedComments/GetPagedCommentsRequest.cs b/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Comments/GetPagedComments/GetPagedCommentsRequest.cs new file mode 100644 index 00000000..5b0f7140 --- /dev/null +++ b/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Comments/GetPagedComments/GetPagedCommentsRequest.cs @@ -0,0 +1,3 @@ +namespace BlogVerticalSliceCQRSMinimalApi.Features.Comments.GetPagedComments; + +public record GetCommentsByFilterRequest(string OrderBy, string SortBy, int? CurrentPage, int? PageSize, string DisplayTypel); From 76cb0431f9bdce81f35e37a0251eba6f9715f843 Mon Sep 17 00:00:00 2001 From: Vitalii Lakatosh Date: Tue, 14 Apr 2026 00:29:25 +0300 Subject: [PATCH 16/33] Add Get paged comments endpoint --- .../GetPagedCommentsEndpoint.cs | 45 +++++++++++++++++++ 1 file changed, 45 insertions(+) create mode 100644 BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Comments/GetPagedComments/GetPagedCommentsEndpoint.cs diff --git a/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Comments/GetPagedComments/GetPagedCommentsEndpoint.cs b/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Comments/GetPagedComments/GetPagedCommentsEndpoint.cs new file mode 100644 index 00000000..0192dd87 --- /dev/null +++ b/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Comments/GetPagedComments/GetPagedCommentsEndpoint.cs @@ -0,0 +1,45 @@ +using Asp.Versioning; +using Blog.Contracts.V1; +using Blog.Contracts.V1.Responses.CommentsResponses; +using Carter; +using Mapster; +using MediatR; +using Microsoft.AspNetCore.Mvc; + +namespace BlogVerticalSliceCQRSMinimalApi.Features.Comments.GetPagedComments; + +public class GetCommentsByFilterEndpoint : ICarterModule +{ + public void AddRoutes(IEndpointRouteBuilder app) + { + var versionSet = app.NewApiVersionSet() + .HasApiVersion(new ApiVersion(1, 0)) + .ReportApiVersions() + .Build(); + + var group = app.MapGroup(ApiRoutes.CommentsController.Comments) + .WithApiVersionSet(versionSet) + .MapToApiVersion(1.0) + .WithTags("Comments"); + + group.MapPost(ApiRoutes.CommentsController.GetCommentsByFilter, + async ([FromBody] GetCommentsByFilterRequest request, + [FromServices] ISender sender) => + { + var command = request.Adapt(); + + var result = await sender.Send(command); + + return result is null + ? Results.NotFound() + : Results.Ok(result); + }) + //.RequireAuthorization() + .WithName("GetPagedComments") + .Produces() + .Produces(400) + .WithSummary("Get Paged Comments") + .WithDescription("Get Paged Comments") + .HasApiVersion(1.0); + } +} From 02063bf16546a4bd2e335823e9038efc7b555bc7 Mon Sep 17 00:00:00 2001 From: Vitalii Lakatosh Date: Wed, 15 Apr 2026 00:30:02 +0300 Subject: [PATCH 17/33] Add Get all users endpoint --- .../GetAllUsers/GetAllUsersEndpoint.cs | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Accounts/GetAllUsers/GetAllUsersEndpoint.cs diff --git a/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Accounts/GetAllUsers/GetAllUsersEndpoint.cs b/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Accounts/GetAllUsers/GetAllUsersEndpoint.cs new file mode 100644 index 00000000..f1a37c98 --- /dev/null +++ b/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Accounts/GetAllUsers/GetAllUsersEndpoint.cs @@ -0,0 +1,29 @@ +using Blog.Contracts.V1; +using Blog.Contracts.V1.Responses.UsersResponses; +using Carter; +using MediatR; +using Microsoft.AspNetCore.Mvc; + +namespace BlogVerticalSliceCQRSMinimalApi.Features.Accounts.GetAllUsers; + +public class GetAllUsersEndpoint : ICarterModule +{ + public void AddRoutes(IEndpointRouteBuilder app) + { + app.MapGet(ApiRoutes.AccountsController.GetAllUsers, async ([FromServices] ISender sender) => + { + var result = await sender.Send(new GetAllUsersQuery()); + + return result == null + ? Results.NotFound() + : Results.Ok(result); + }) + .WithName("GetAllUsers") + .Produces>() + .Produces(StatusCodes.Status400BadRequest) + .Produces(StatusCodes.Status404NotFound) + .WithSummary("Get All Users") + .WithDescription("Get All Users") + .HasApiVersion(1.0); + } +} \ No newline at end of file From 52f3c95f9c5406ff2a1e203db5434c941ce80197 Mon Sep 17 00:00:00 2001 From: Vitalii Lakatosh Date: Wed, 15 Apr 2026 00:30:20 +0300 Subject: [PATCH 18/33] Add Initialize account endpoint --- .../Accounts/Initialize/InitializeEndpoint.cs | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Accounts/Initialize/InitializeEndpoint.cs diff --git a/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Accounts/Initialize/InitializeEndpoint.cs b/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Accounts/Initialize/InitializeEndpoint.cs new file mode 100644 index 00000000..8e3940b8 --- /dev/null +++ b/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Accounts/Initialize/InitializeEndpoint.cs @@ -0,0 +1,32 @@ +using Blog.Contracts.V1; +using Blog.Contracts.V1.Responses.UsersResponses; +using Carter; +using MediatR; +using Microsoft.AspNetCore.Mvc; + +namespace BlogVerticalSliceCQRSMinimalApi.Features.Accounts.Initialize; + +public class GetAllEndpoint : ICarterModule +{ + public void AddRoutes(IEndpointRouteBuilder app) + { + app.MapGet(ApiRoutes.AccountsController.Initialize, async ([FromRoute] string userId, [FromServices] ISender sender) => + { + if (string.IsNullOrEmpty(userId)) + return Results.BadRequest("Something went wrong"); + + var result = await sender.Send(new InitializeQuery(UserId: userId)); + + return result == null + ? Results.NotFound() + : Results.Ok(result); + }) + .WithName("Initialize") + .Produces>() + .Produces(StatusCodes.Status400BadRequest) + .Produces(StatusCodes.Status404NotFound) + .WithSummary("Initialize") + .WithDescription("Initialize") + .HasApiVersion(1.0); + } +} \ No newline at end of file From 8b06e39f8ad607ccd841c8b60a85b211f9bf2b91 Mon Sep 17 00:00:00 2001 From: Vitalii Lakatosh Date: Wed, 15 Apr 2026 00:30:41 +0300 Subject: [PATCH 19/33] Add send confirmation email endpoint --- .../SendConfirmationEmailEndpoint.cs | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Accounts/SendConfirmationEmail/SendConfirmationEmailEndpoint.cs diff --git a/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Accounts/SendConfirmationEmail/SendConfirmationEmailEndpoint.cs b/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Accounts/SendConfirmationEmail/SendConfirmationEmailEndpoint.cs new file mode 100644 index 00000000..49827568 --- /dev/null +++ b/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Accounts/SendConfirmationEmail/SendConfirmationEmailEndpoint.cs @@ -0,0 +1,29 @@ +using Blog.Contracts.V1; +using Carter; +using MediatR; +using Microsoft.AspNetCore.Mvc; + +namespace BlogVerticalSliceCQRSMinimalApi.Features.Accounts.SendConfirmationEmail; + +public class SendConfirmationEmailEndpoint : ICarterModule +{ + public void AddRoutes(IEndpointRouteBuilder app) + { + app.MapGet(ApiRoutes.AccountsController.SendConfirmationEmail, async ([FromServices] HttpContext context, ISender sender) => + { + var email = context.User.Identity?.Name; + + if (string.IsNullOrEmpty(email)) + return Results.BadRequest(); + + var result = await sender.Send(new SendConfirmationEmailQuery(Email: email)); + + return Results.NoContent(); + }) + .WithName("SendConfirmationEmail") + .Produces(StatusCodes.Status204NoContent) + .WithSummary("Send Confirmation Email") + .WithDescription("Send Confirmation Email") + .HasApiVersion(1.0); + } +} \ No newline at end of file From a03ae0fcd5a9b577ebf2d32a2475b361738da91a Mon Sep 17 00:00:00 2001 From: Vitalii Lakatosh Date: Wed, 15 Apr 2026 00:30:58 +0300 Subject: [PATCH 20/33] Add users activity endpoint --- .../UsersActivity/UsersActivityEndpoint.cs | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Accounts/UsersActivity/UsersActivityEndpoint.cs diff --git a/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Accounts/UsersActivity/UsersActivityEndpoint.cs b/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Accounts/UsersActivity/UsersActivityEndpoint.cs new file mode 100644 index 00000000..a1f4fe94 --- /dev/null +++ b/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Accounts/UsersActivity/UsersActivityEndpoint.cs @@ -0,0 +1,29 @@ +using Blog.Contracts.V1; +using Blog.Contracts.V1.Responses.Chart; +using Carter; +using MediatR; +using Microsoft.AspNetCore.Mvc; + +namespace BlogVerticalSliceCQRSMinimalApi.Features.Accounts.UsersActivity; + +public class UsersActivityEndpoint : ICarterModule +{ + public void AddRoutes(IEndpointRouteBuilder app) + { + app.MapGet(ApiRoutes.AccountsController.UsersActivity, async ([FromServices] ISender sender) => + { + var result = await sender.Send(new UsersActivityQuery()); + + return result == null + ? Results.NotFound() + : Results.Ok(result); + }) + .WithName("UsersActivity") + .Produces>() + .Produces(StatusCodes.Status400BadRequest) + .Produces(StatusCodes.Status404NotFound) + .WithSummary("Users Activity") + .WithDescription("Users Activity") + .HasApiVersion(1.0); + } +} \ No newline at end of file From 847b1399f53dc400bf86c15cdf93b276971cf4a6 Mon Sep 17 00:00:00 2001 From: Vitalii Lakatosh Date: Thu, 16 Apr 2026 00:31:27 +0300 Subject: [PATCH 21/33] Add comments activity endpoint --- .../CommentsActivityEndpoint.cs | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Comments/CommentsActivity/CommentsActivityEndpoint.cs diff --git a/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Comments/CommentsActivity/CommentsActivityEndpoint.cs b/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Comments/CommentsActivity/CommentsActivityEndpoint.cs new file mode 100644 index 00000000..207459da --- /dev/null +++ b/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Comments/CommentsActivity/CommentsActivityEndpoint.cs @@ -0,0 +1,29 @@ +using Blog.Contracts.V1; +using Blog.Contracts.V1.Responses.Chart; +using Carter; +using MediatR; +using Microsoft.AspNetCore.Mvc; + +namespace BlogVerticalSliceCQRSMinimalApi.Features.Comments.CommentsActivity; + +public class CommentsActivityEndpoint : ICarterModule +{ + public void AddRoutes(IEndpointRouteBuilder app) + { + app.MapGet(ApiRoutes.AccountsController.Initialize, async ([FromRoute] string userId, [FromServices] ISender sender) => + { + var result = await sender.Send(new CommentsActivityQuery()); + + return result == null + ? Results.NotFound() + : Results.Ok(result); + }) + .WithName("CommentsActivity") + .Produces>() + .Produces(StatusCodes.Status400BadRequest) + .Produces(StatusCodes.Status404NotFound) + .WithSummary("Comments Activity") + .WithDescription("Comments Activity") + .HasApiVersion(1.0); + } +} \ No newline at end of file From f2d322c3f42488527e9ea9cda4ba5b443bb4f513 Mon Sep 17 00:00:00 2001 From: Vitalii Lakatosh Date: Thu, 16 Apr 2026 00:31:49 +0300 Subject: [PATCH 22/33] Add get all comments endpoint --- .../Comments/GetAll/GetAllEndpoint.cs | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Comments/GetAll/GetAllEndpoint.cs diff --git a/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Comments/GetAll/GetAllEndpoint.cs b/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Comments/GetAll/GetAllEndpoint.cs new file mode 100644 index 00000000..77165a67 --- /dev/null +++ b/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Comments/GetAll/GetAllEndpoint.cs @@ -0,0 +1,28 @@ +using Blog.Contracts.V1.Responses.CommentsResponses; +using Carter; +using MediatR; +using Microsoft.AspNetCore.Mvc; + +namespace BlogVerticalSliceCQRSMinimalApi.Features.Comments.GetAll; + +public class GetAllEndpoint : ICarterModule +{ + public void AddRoutes(IEndpointRouteBuilder app) + { + app.MapGet("/comments", async ([FromRoute] string userId, [FromServices] ISender sender) => + { + var result = await sender.Send(new GetAllQuery()); + + return result == null + ? Results.NotFound() + : Results.Ok(result); + }) + .WithName("GetAll") + .Produces>() + .Produces(StatusCodes.Status400BadRequest) + .Produces(StatusCodes.Status404NotFound) + .WithSummary("Get All") + .WithDescription("Get All") + .HasApiVersion(1.0); + } +} \ No newline at end of file From a74f29d50808a359ab5db63629ee4c1badfa14dc Mon Sep 17 00:00:00 2001 From: Vitalii Lakatosh Date: Thu, 16 Apr 2026 00:32:07 +0300 Subject: [PATCH 23/33] Add get comment by id endpoint --- .../GetCommentById/GetCommentByIdEndpoint.cs | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Comments/GetCommentById/GetCommentByIdEndpoint.cs diff --git a/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Comments/GetCommentById/GetCommentByIdEndpoint.cs b/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Comments/GetCommentById/GetCommentByIdEndpoint.cs new file mode 100644 index 00000000..6ae4e112 --- /dev/null +++ b/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Comments/GetCommentById/GetCommentByIdEndpoint.cs @@ -0,0 +1,28 @@ +using Blog.Contracts.V1.Responses.CommentsResponses; +using Carter; +using MediatR; +using Microsoft.AspNetCore.Mvc; + +namespace BlogVerticalSliceCQRSMinimalApi.Features.Comments.GetCommentById; + +public class GetCommentByIdEndpoint : ICarterModule +{ + public void AddRoutes(IEndpointRouteBuilder app) + { + app.MapGet("/comments/{id:int}", async ([FromRoute] int id, [FromServices] ISender sender) => + { + var result = await sender.Send(new GetCommentByIdQuery(Id: id)); + + return result == null + ? Results.NotFound() + : Results.Ok(result); + }) + .WithName("GetCommentById") + .Produces() + .Produces(StatusCodes.Status400BadRequest) + .Produces(StatusCodes.Status404NotFound) + .WithSummary("Get Comment By Id") + .WithDescription("Get Comment By Id") + .HasApiVersion(1.0); + } +} \ No newline at end of file From 7745555bc60034aac27e17121ea2a355c80b85bb Mon Sep 17 00:00:00 2001 From: Vitalii Lakatosh Date: Thu, 16 Apr 2026 00:32:26 +0300 Subject: [PATCH 24/33] Add Get comments by filter endpoint --- .../GetCommentsByFilterEndpoint.cs | 45 +++++++++++++++++++ 1 file changed, 45 insertions(+) create mode 100644 BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Comments/GetCommentsByFilter/GetCommentsByFilterEndpoint.cs diff --git a/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Comments/GetCommentsByFilter/GetCommentsByFilterEndpoint.cs b/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Comments/GetCommentsByFilter/GetCommentsByFilterEndpoint.cs new file mode 100644 index 00000000..3969cf62 --- /dev/null +++ b/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Comments/GetCommentsByFilter/GetCommentsByFilterEndpoint.cs @@ -0,0 +1,45 @@ +using Asp.Versioning; +using Blog.Contracts.V1; +using Blog.Contracts.V1.Responses.CommentsResponses; +using Carter; +using Mapster; +using MediatR; +using Microsoft.AspNetCore.Mvc; + +namespace BlogVerticalSliceCQRSMinimalApi.Features.Comments.GetCommentsByFilter; + +public class GetCommentsByFilterEndpoint : ICarterModule +{ + public void AddRoutes(IEndpointRouteBuilder app) + { + var versionSet = app.NewApiVersionSet() + .HasApiVersion(new ApiVersion(1, 0)) + .ReportApiVersions() + .Build(); + + var group = app.MapGroup(ApiRoutes.CommentsController.Comments) + .WithApiVersionSet(versionSet) + .MapToApiVersion(1.0) + .WithTags("Comments"); + + group.MapPost(ApiRoutes.CommentsController.GetCommentsByFilter, + async ([FromServices] GetCommentsByFilterRequest request, + ISender sender) => + { + var command = request.Adapt(); + + var result = await sender.Send(command); + + return result is null + ? Results.NotFound() + : Results.Ok(result); + }) + //.RequireAuthorization() + .WithName("GetCommentsByFilter") + .Produces() + .Produces(400) + .WithSummary("Get Comments By Filter") + .WithDescription("Get CommentsBy Filter") + .HasApiVersion(1.0); + } +} From bff315eed22bdd9acc98f0b0823d5a7db52eca96 Mon Sep 17 00:00:00 2001 From: Vitalii Lakatosh Date: Thu, 16 Apr 2026 00:32:46 +0300 Subject: [PATCH 25/33] Add get comments by post endpoint --- .../GetCommentsByPostEndpoint.cs | 46 +++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Comments/GetCommentsByPost/GetCommentsByPostEndpoint.cs diff --git a/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Comments/GetCommentsByPost/GetCommentsByPostEndpoint.cs b/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Comments/GetCommentsByPost/GetCommentsByPostEndpoint.cs new file mode 100644 index 00000000..41c66654 --- /dev/null +++ b/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Comments/GetCommentsByPost/GetCommentsByPostEndpoint.cs @@ -0,0 +1,46 @@ +using Asp.Versioning; +using Blog.Contracts.V1; +using Blog.Contracts.V1.Responses.CommentsResponses; +using Carter; +using Mapster; +using MediatR; +using Microsoft.AspNetCore.Mvc; + +namespace BlogVerticalSliceCQRSMinimalApi.Features.Comments.GetCommentsByPost; + +public class GetCommentsByPostEndpoint : ICarterModule +{ + public void AddRoutes(IEndpointRouteBuilder app) + { + var versionSet = app.NewApiVersionSet() + .HasApiVersion(new ApiVersion(1, 0)) + .ReportApiVersions() + .Build(); + + var group = app.MapGroup(ApiRoutes.CommentsController.Comments) + .WithApiVersionSet(versionSet) + .MapToApiVersion(1.0) + .WithTags("Comments"); + + group.MapPost(ApiRoutes.CommentsController.GetCommentsByPost, + async ([FromRoute] int id, [FromBody] GetCommentsByPostRequest request, + [FromServices] ISender sender) => + { + var command = request.Adapt(); + command = command with { PostId = id }; + + var result = await sender.Send(command); + + return result is null + ? Results.NotFound() + : Results.Ok(result); + }) + //.RequireAuthorization() + .WithName("Get Comments By Post") + .Produces() + .Produces(400) + .WithSummary("Get Comments By Post") + .WithDescription("Get Comments By Post") + .HasApiVersion(1.0); + } +} \ No newline at end of file From 56aca40df96a7fa1ea54b097c0d3788eb81619de Mon Sep 17 00:00:00 2001 From: Vitalii Lakatosh Date: Fri, 17 Apr 2026 00:29:29 +0300 Subject: [PATCH 26/33] Fix GetAllQueryHandler Mapper issue --- .../Features/Comments/GetAll/GetAllQueryHandler.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Comments/GetAll/GetAllQueryHandler.cs b/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Comments/GetAll/GetAllQueryHandler.cs index 1779e86f..d7277bb4 100644 --- a/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Comments/GetAll/GetAllQueryHandler.cs +++ b/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Comments/GetAll/GetAllQueryHandler.cs @@ -1,7 +1,7 @@ -using Blog.Contracts.V1.Responses.CommentsResponses; +using AutoMapper; +using Blog.Contracts.V1.Responses.CommentsResponses; using Blog.EntityServices.Interfaces; using BlogVerticalSliceCQRSMinimalApi.CQRSExtensions; -using MapsterMapper; namespace BlogVerticalSliceCQRSMinimalApi.Features.Comments.GetAll; From 4ebb92620062f8ecbc766910a5a2418713fa04fa Mon Sep 17 00:00:00 2001 From: Vitalii Lakatosh Date: Sun, 31 May 2026 14:49:54 +0300 Subject: [PATCH 27/33] Configure carter versioning --- .../CQRSExtensions/CarterExtensions.cs | 19 +++++++++++++++++++ .../StartupConfigures/ConfigureRoutes.cs | 15 +++++++++++---- 2 files changed, 30 insertions(+), 4 deletions(-) create mode 100644 BlogWebApp/BlogVerticalSliceCQRSMinimalApi/CQRSExtensions/CarterExtensions.cs diff --git a/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/CQRSExtensions/CarterExtensions.cs b/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/CQRSExtensions/CarterExtensions.cs new file mode 100644 index 00000000..d1311f5f --- /dev/null +++ b/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/CQRSExtensions/CarterExtensions.cs @@ -0,0 +1,19 @@ +using Asp.Versioning.Builder; +using Carter; + +namespace BlogVerticalSliceCQRSMinimalApi.CQRSExtensions; + +public static class CarterExtensions +{ + public static IEndpointRouteBuilder MapVersionedCarter( + this IEndpointRouteBuilder app, + ApiVersionSet versionSet) + { + var group = app.MapGroup("/api/v{version:apiVersion}") + .WithApiVersionSet(versionSet); + + group.MapCarter(); // 👈 ключ + + return app; + } +} \ No newline at end of file diff --git a/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/StartupConfigures/ConfigureRoutes.cs b/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/StartupConfigures/ConfigureRoutes.cs index ce413081..2f51bd7c 100644 --- a/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/StartupConfigures/ConfigureRoutes.cs +++ b/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/StartupConfigures/ConfigureRoutes.cs @@ -1,12 +1,13 @@ -using Carter; +using Asp.Versioning; namespace BlogVerticalSliceCQRSMinimalApi.StartupConfigures; -using System.IO; -using System.Net; +using CQRSExtensions; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Diagnostics; using Microsoft.AspNetCore.Http; +using System.IO; +using System.Net; /// /// Configure routes. @@ -76,7 +77,13 @@ public static void Configure(WebApplication app) //endpoints.MapHealthChecks("/health"); }); - app.MapCarter(); + + var versionSet = app.NewApiVersionSet() + .HasApiVersion(new ApiVersion(1, 0)) + .ReportApiVersions() + .Build(); + + app.MapVersionedCarter(versionSet); app.MapDefaultEndpoints(); From 9bead9640e69388a90453344f879b35354b0060c Mon Sep 17 00:00:00 2001 From: Vitalii Lakatosh Date: Sun, 31 May 2026 14:50:56 +0300 Subject: [PATCH 28/33] Configure swagger to not have conflicts with carter --- .../StartupConfigureServicesInstallers/SwaggerInstaller.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/StartupConfigureServicesInstallers/SwaggerInstaller.cs b/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/StartupConfigureServicesInstallers/SwaggerInstaller.cs index 1bf7f3ea..f4981bb6 100644 --- a/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/StartupConfigureServicesInstallers/SwaggerInstaller.cs +++ b/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/StartupConfigureServicesInstallers/SwaggerInstaller.cs @@ -35,11 +35,11 @@ public void InstallServices(IServiceCollection services, IConfiguration configur new HeaderApiVersionReader("x-api-version"), new MediaTypeApiVersionReader("x-api-version")); }) - .AddApiExplorer(options => + /*.AddApiExplorer(options => { options.GroupNameFormat = "'v'VVV"; options.SubstituteApiVersionInUrl = true; - }); + })*/; //services.ConfigureOptions(); services.AddSwaggerGen(c => { From 928f67a641dea065b57ff74bdd72a7b0059763ce Mon Sep 17 00:00:00 2001 From: Vitalii Lakatosh Date: Sun, 31 May 2026 14:51:46 +0300 Subject: [PATCH 29/33] Configure Account features --- .../Accounts/GetAllUsers/GetAllUsersEndpoint.cs | 12 ++++++++---- .../Accounts/Initialize/InitializeEndpoint.cs | 16 ++++++++++------ .../Features/Accounts/Login/LoginEndpoint.cs | 11 ++--------- .../Accounts/Register/RegisterEndpoint.cs | 11 ++--------- .../SendConfirmationEmailEndpoint.cs | 12 ++++++++---- .../UsersActivity/UsersActivityEndpoint.cs | 12 ++++++++---- 6 files changed, 38 insertions(+), 36 deletions(-) diff --git a/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Accounts/GetAllUsers/GetAllUsersEndpoint.cs b/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Accounts/GetAllUsers/GetAllUsersEndpoint.cs index f1a37c98..50f847c7 100644 --- a/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Accounts/GetAllUsers/GetAllUsersEndpoint.cs +++ b/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Accounts/GetAllUsers/GetAllUsersEndpoint.cs @@ -1,4 +1,5 @@ -using Blog.Contracts.V1; +using Asp.Versioning; +using Blog.Contracts.V1; using Blog.Contracts.V1.Responses.UsersResponses; using Carter; using MediatR; @@ -10,7 +11,11 @@ public class GetAllUsersEndpoint : ICarterModule { public void AddRoutes(IEndpointRouteBuilder app) { - app.MapGet(ApiRoutes.AccountsController.GetAllUsers, async ([FromServices] ISender sender) => + var group = app.MapGroup("Accounts") + .MapToApiVersion(1.0) + .WithTags("Accounts"); + + group.MapGet(ApiRoutes.AccountsController.GetAllUsers, async ([FromServices] ISender sender) => { var result = await sender.Send(new GetAllUsersQuery()); @@ -23,7 +28,6 @@ public void AddRoutes(IEndpointRouteBuilder app) .Produces(StatusCodes.Status400BadRequest) .Produces(StatusCodes.Status404NotFound) .WithSummary("Get All Users") - .WithDescription("Get All Users") - .HasApiVersion(1.0); + .WithDescription("Get All Users"); } } \ No newline at end of file diff --git a/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Accounts/Initialize/InitializeEndpoint.cs b/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Accounts/Initialize/InitializeEndpoint.cs index 8e3940b8..c54562a0 100644 --- a/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Accounts/Initialize/InitializeEndpoint.cs +++ b/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Accounts/Initialize/InitializeEndpoint.cs @@ -1,16 +1,21 @@ -using Blog.Contracts.V1; +using Asp.Versioning; +using Blog.Contracts.V1; using Blog.Contracts.V1.Responses.UsersResponses; using Carter; using MediatR; using Microsoft.AspNetCore.Mvc; namespace BlogVerticalSliceCQRSMinimalApi.Features.Accounts.Initialize; - +/* public class GetAllEndpoint : ICarterModule { public void AddRoutes(IEndpointRouteBuilder app) { - app.MapGet(ApiRoutes.AccountsController.Initialize, async ([FromRoute] string userId, [FromServices] ISender sender) => + var group = app.MapGroup("Accounts") + .MapToApiVersion(1.0) + .WithTags("Accounts"); + + group.MapGet(ApiRoutes.AccountsController.Initialize, async ([FromRoute] string userId, [FromServices] ISender sender) => { if (string.IsNullOrEmpty(userId)) return Results.BadRequest("Something went wrong"); @@ -26,7 +31,6 @@ public void AddRoutes(IEndpointRouteBuilder app) .Produces(StatusCodes.Status400BadRequest) .Produces(StatusCodes.Status404NotFound) .WithSummary("Initialize") - .WithDescription("Initialize") - .HasApiVersion(1.0); + .WithDescription("Initialize"); } -} \ No newline at end of file +}*/ \ No newline at end of file diff --git a/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Accounts/Login/LoginEndpoint.cs b/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Accounts/Login/LoginEndpoint.cs index 3b72bc0e..c3315912 100644 --- a/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Accounts/Login/LoginEndpoint.cs +++ b/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Accounts/Login/LoginEndpoint.cs @@ -11,13 +11,7 @@ public class LoginEndpoint : ICarterModule { public void AddRoutes(IEndpointRouteBuilder app) { - var versionSet = app.NewApiVersionSet() - .HasApiVersion(new ApiVersion(1, 0)) - .ReportApiVersions() - .Build(); - - var group = app.MapGroup(ApiRoutes.AccountsController.Accounts) - .WithApiVersionSet(versionSet) + var group = app.MapGroup("Accounts") .MapToApiVersion(1.0) .WithTags("Accounts"); @@ -40,7 +34,6 @@ public void AddRoutes(IEndpointRouteBuilder app) .Produces(200) .Produces(400) .WithSummary("Login") - .WithDescription("Login") - .HasApiVersion(1.0); + .WithDescription("Login"); } } \ No newline at end of file diff --git a/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Accounts/Register/RegisterEndpoint.cs b/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Accounts/Register/RegisterEndpoint.cs index 3236e2d7..81f96233 100644 --- a/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Accounts/Register/RegisterEndpoint.cs +++ b/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Accounts/Register/RegisterEndpoint.cs @@ -12,13 +12,7 @@ public class RegisterEndpoint : ICarterModule { public void AddRoutes(IEndpointRouteBuilder app) { - var versionSet = app.NewApiVersionSet() - .HasApiVersion(new ApiVersion(1, 0)) - .ReportApiVersions() - .Build(); - - var group = app.MapGroup(ApiRoutes.AccountsController.Accounts) - .WithApiVersionSet(versionSet) + var group = app.MapGroup("Accounts") .MapToApiVersion(1.0) .WithTags("Accounts"); @@ -48,7 +42,6 @@ public void AddRoutes(IEndpointRouteBuilder app) .Produces(204) .Produces(400) .WithSummary("Register") - .WithDescription("Register") - .HasApiVersion(1.0); + .WithDescription("Register"); } } \ No newline at end of file diff --git a/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Accounts/SendConfirmationEmail/SendConfirmationEmailEndpoint.cs b/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Accounts/SendConfirmationEmail/SendConfirmationEmailEndpoint.cs index 49827568..48e18281 100644 --- a/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Accounts/SendConfirmationEmail/SendConfirmationEmailEndpoint.cs +++ b/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Accounts/SendConfirmationEmail/SendConfirmationEmailEndpoint.cs @@ -1,4 +1,5 @@ -using Blog.Contracts.V1; +using Asp.Versioning; +using Blog.Contracts.V1; using Carter; using MediatR; using Microsoft.AspNetCore.Mvc; @@ -9,7 +10,11 @@ public class SendConfirmationEmailEndpoint : ICarterModule { public void AddRoutes(IEndpointRouteBuilder app) { - app.MapGet(ApiRoutes.AccountsController.SendConfirmationEmail, async ([FromServices] HttpContext context, ISender sender) => + var group = app.MapGroup("Accounts") + .MapToApiVersion(1.0) + .WithTags("Accounts"); + + group.MapGet(ApiRoutes.AccountsController.SendConfirmationEmail, async ([FromServices] HttpContext context, ISender sender) => { var email = context.User.Identity?.Name; @@ -23,7 +28,6 @@ public void AddRoutes(IEndpointRouteBuilder app) .WithName("SendConfirmationEmail") .Produces(StatusCodes.Status204NoContent) .WithSummary("Send Confirmation Email") - .WithDescription("Send Confirmation Email") - .HasApiVersion(1.0); + .WithDescription("Send Confirmation Email"); } } \ No newline at end of file diff --git a/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Accounts/UsersActivity/UsersActivityEndpoint.cs b/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Accounts/UsersActivity/UsersActivityEndpoint.cs index a1f4fe94..cb736233 100644 --- a/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Accounts/UsersActivity/UsersActivityEndpoint.cs +++ b/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Accounts/UsersActivity/UsersActivityEndpoint.cs @@ -1,4 +1,5 @@ -using Blog.Contracts.V1; +using Asp.Versioning; +using Blog.Contracts.V1; using Blog.Contracts.V1.Responses.Chart; using Carter; using MediatR; @@ -10,7 +11,11 @@ public class UsersActivityEndpoint : ICarterModule { public void AddRoutes(IEndpointRouteBuilder app) { - app.MapGet(ApiRoutes.AccountsController.UsersActivity, async ([FromServices] ISender sender) => + var group = app.MapGroup("Accounts") + .MapToApiVersion(1.0) + .WithTags("Accounts"); + + group.MapGet(ApiRoutes.AccountsController.UsersActivity, async ([FromServices] ISender sender) => { var result = await sender.Send(new UsersActivityQuery()); @@ -23,7 +28,6 @@ public void AddRoutes(IEndpointRouteBuilder app) .Produces(StatusCodes.Status400BadRequest) .Produces(StatusCodes.Status404NotFound) .WithSummary("Users Activity") - .WithDescription("Users Activity") - .HasApiVersion(1.0); + .WithDescription("Users Activity"); } } \ No newline at end of file From df8f26281f2ef9843413e3bea7a33055c0840421 Mon Sep 17 00:00:00 2001 From: Vitalii Lakatosh Date: Fri, 17 Apr 2026 14:52:24 +0300 Subject: [PATCH 30/33] Configure Comments features --- .../CommentsActivityEndpoint.cs | 12 ++++++++---- .../CreateComment/CreateCommentEndpoint.cs | 11 ++--------- .../Features/Comments/GetAll/GetAllEndpoint.cs | 17 +++++++++++------ .../GetCommentById/GetCommentByIdEndpoint.cs | 13 +++++++++---- .../GetCommentsByFilterEndpoint.cs | 11 ++--------- .../GetCommentsByPostEndpoint.cs | 11 ++--------- .../GetPagedCommentsEndpoint.cs | 11 ++--------- 7 files changed, 36 insertions(+), 50 deletions(-) diff --git a/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Comments/CommentsActivity/CommentsActivityEndpoint.cs b/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Comments/CommentsActivity/CommentsActivityEndpoint.cs index 207459da..76a482ee 100644 --- a/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Comments/CommentsActivity/CommentsActivityEndpoint.cs +++ b/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Comments/CommentsActivity/CommentsActivityEndpoint.cs @@ -1,4 +1,5 @@ -using Blog.Contracts.V1; +using Asp.Versioning; +using Blog.Contracts.V1; using Blog.Contracts.V1.Responses.Chart; using Carter; using MediatR; @@ -10,7 +11,11 @@ public class CommentsActivityEndpoint : ICarterModule { public void AddRoutes(IEndpointRouteBuilder app) { - app.MapGet(ApiRoutes.AccountsController.Initialize, async ([FromRoute] string userId, [FromServices] ISender sender) => + var group = app.MapGroup("Comments") + .MapToApiVersion(1.0) + .WithTags("Comments"); + + group.MapGet("/comments-activity/{userId}", async ([FromRoute] string userId, [FromServices] ISender sender) => { var result = await sender.Send(new CommentsActivityQuery()); @@ -23,7 +28,6 @@ public void AddRoutes(IEndpointRouteBuilder app) .Produces(StatusCodes.Status400BadRequest) .Produces(StatusCodes.Status404NotFound) .WithSummary("Comments Activity") - .WithDescription("Comments Activity") - .HasApiVersion(1.0); + .WithDescription("Comments Activity"); } } \ No newline at end of file diff --git a/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Comments/CreateComment/CreateCommentEndpoint.cs b/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Comments/CreateComment/CreateCommentEndpoint.cs index b78cfd10..d6126476 100644 --- a/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Comments/CreateComment/CreateCommentEndpoint.cs +++ b/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Comments/CreateComment/CreateCommentEndpoint.cs @@ -12,13 +12,7 @@ public class CreateCommentEndpoint : ICarterModule { public void AddRoutes(IEndpointRouteBuilder app) { - var versionSet = app.NewApiVersionSet() - .HasApiVersion(new ApiVersion(1, 0)) - .ReportApiVersions() - .Build(); - - var group = app.MapGroup(ApiRoutes.CommentsController.Comments) - .WithApiVersionSet(versionSet) + var group = app.MapGroup("Comments") .MapToApiVersion(1.0) .WithTags("Comments"); @@ -45,7 +39,6 @@ public void AddRoutes(IEndpointRouteBuilder app) .Produces>(201) .Produces(400) .WithSummary("Create comment") - .WithDescription("Create comment") - .HasApiVersion(1.0); + .WithDescription("Create comment"); } } diff --git a/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Comments/GetAll/GetAllEndpoint.cs b/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Comments/GetAll/GetAllEndpoint.cs index 77165a67..d8372cd1 100644 --- a/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Comments/GetAll/GetAllEndpoint.cs +++ b/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Comments/GetAll/GetAllEndpoint.cs @@ -1,15 +1,21 @@ -using Blog.Contracts.V1.Responses.CommentsResponses; +using Asp.Versioning; +using Blog.Contracts.V1; +using Blog.Contracts.V1.Responses.CommentsResponses; using Carter; using MediatR; using Microsoft.AspNetCore.Mvc; namespace BlogVerticalSliceCQRSMinimalApi.Features.Comments.GetAll; -public class GetAllEndpoint : ICarterModule +/*public class GetAllEndpoint : ICarterModule { public void AddRoutes(IEndpointRouteBuilder app) { - app.MapGet("/comments", async ([FromRoute] string userId, [FromServices] ISender sender) => + var group = app.MapGroup("/сomments") + .MapToApiVersion(1.0) + .WithTags("Comments"); + + group.MapGet("", async ([FromRoute] string userId, [FromServices] ISender sender) => { var result = await sender.Send(new GetAllQuery()); @@ -22,7 +28,6 @@ public void AddRoutes(IEndpointRouteBuilder app) .Produces(StatusCodes.Status400BadRequest) .Produces(StatusCodes.Status404NotFound) .WithSummary("Get All") - .WithDescription("Get All") - .HasApiVersion(1.0); + .WithDescription("Get All"); } -} \ No newline at end of file +}*/ \ No newline at end of file diff --git a/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Comments/GetCommentById/GetCommentByIdEndpoint.cs b/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Comments/GetCommentById/GetCommentByIdEndpoint.cs index 6ae4e112..f7b47ffe 100644 --- a/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Comments/GetCommentById/GetCommentByIdEndpoint.cs +++ b/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Comments/GetCommentById/GetCommentByIdEndpoint.cs @@ -1,4 +1,6 @@ -using Blog.Contracts.V1.Responses.CommentsResponses; +using Asp.Versioning; +using Blog.Contracts.V1; +using Blog.Contracts.V1.Responses.CommentsResponses; using Carter; using MediatR; using Microsoft.AspNetCore.Mvc; @@ -9,7 +11,11 @@ public class GetCommentByIdEndpoint : ICarterModule { public void AddRoutes(IEndpointRouteBuilder app) { - app.MapGet("/comments/{id:int}", async ([FromRoute] int id, [FromServices] ISender sender) => + var group = app.MapGroup("Comments") + .MapToApiVersion(1.0) + .WithTags("Comments"); + + group.MapGet("{id:int}", async ([FromRoute] int id, [FromServices] ISender sender) => { var result = await sender.Send(new GetCommentByIdQuery(Id: id)); @@ -22,7 +28,6 @@ public void AddRoutes(IEndpointRouteBuilder app) .Produces(StatusCodes.Status400BadRequest) .Produces(StatusCodes.Status404NotFound) .WithSummary("Get Comment By Id") - .WithDescription("Get Comment By Id") - .HasApiVersion(1.0); + .WithDescription("Get Comment By Id"); } } \ No newline at end of file diff --git a/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Comments/GetCommentsByFilter/GetCommentsByFilterEndpoint.cs b/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Comments/GetCommentsByFilter/GetCommentsByFilterEndpoint.cs index 3969cf62..ea735630 100644 --- a/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Comments/GetCommentsByFilter/GetCommentsByFilterEndpoint.cs +++ b/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Comments/GetCommentsByFilter/GetCommentsByFilterEndpoint.cs @@ -12,13 +12,7 @@ public class GetCommentsByFilterEndpoint : ICarterModule { public void AddRoutes(IEndpointRouteBuilder app) { - var versionSet = app.NewApiVersionSet() - .HasApiVersion(new ApiVersion(1, 0)) - .ReportApiVersions() - .Build(); - - var group = app.MapGroup(ApiRoutes.CommentsController.Comments) - .WithApiVersionSet(versionSet) + var group = app.MapGroup("Comments") .MapToApiVersion(1.0) .WithTags("Comments"); @@ -39,7 +33,6 @@ public void AddRoutes(IEndpointRouteBuilder app) .Produces() .Produces(400) .WithSummary("Get Comments By Filter") - .WithDescription("Get CommentsBy Filter") - .HasApiVersion(1.0); + .WithDescription("Get CommentsBy Filter"); } } diff --git a/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Comments/GetCommentsByPost/GetCommentsByPostEndpoint.cs b/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Comments/GetCommentsByPost/GetCommentsByPostEndpoint.cs index 41c66654..bbf53d0e 100644 --- a/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Comments/GetCommentsByPost/GetCommentsByPostEndpoint.cs +++ b/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Comments/GetCommentsByPost/GetCommentsByPostEndpoint.cs @@ -12,13 +12,7 @@ public class GetCommentsByPostEndpoint : ICarterModule { public void AddRoutes(IEndpointRouteBuilder app) { - var versionSet = app.NewApiVersionSet() - .HasApiVersion(new ApiVersion(1, 0)) - .ReportApiVersions() - .Build(); - - var group = app.MapGroup(ApiRoutes.CommentsController.Comments) - .WithApiVersionSet(versionSet) + var group = app.MapGroup("Comments") .MapToApiVersion(1.0) .WithTags("Comments"); @@ -40,7 +34,6 @@ public void AddRoutes(IEndpointRouteBuilder app) .Produces() .Produces(400) .WithSummary("Get Comments By Post") - .WithDescription("Get Comments By Post") - .HasApiVersion(1.0); + .WithDescription("Get Comments By Post"); } } \ No newline at end of file diff --git a/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Comments/GetPagedComments/GetPagedCommentsEndpoint.cs b/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Comments/GetPagedComments/GetPagedCommentsEndpoint.cs index 0192dd87..cbc40746 100644 --- a/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Comments/GetPagedComments/GetPagedCommentsEndpoint.cs +++ b/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Comments/GetPagedComments/GetPagedCommentsEndpoint.cs @@ -12,13 +12,7 @@ public class GetCommentsByFilterEndpoint : ICarterModule { public void AddRoutes(IEndpointRouteBuilder app) { - var versionSet = app.NewApiVersionSet() - .HasApiVersion(new ApiVersion(1, 0)) - .ReportApiVersions() - .Build(); - - var group = app.MapGroup(ApiRoutes.CommentsController.Comments) - .WithApiVersionSet(versionSet) + var group = app.MapGroup("Comments") .MapToApiVersion(1.0) .WithTags("Comments"); @@ -39,7 +33,6 @@ public void AddRoutes(IEndpointRouteBuilder app) .Produces() .Produces(400) .WithSummary("Get Paged Comments") - .WithDescription("Get Paged Comments") - .HasApiVersion(1.0); + .WithDescription("Get Paged Comments"); } } From dcfc78ab66df3ae3397bde590860fc44f2fe9160 Mon Sep 17 00:00:00 2001 From: Vitalii Lakatosh Date: Fri, 17 Apr 2026 14:52:44 +0300 Subject: [PATCH 31/33] Configure HealthCheck features --- .../HealthCheck/Initialize/InitializeEndpoint.cs | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/HealthCheck/Initialize/InitializeEndpoint.cs b/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/HealthCheck/Initialize/InitializeEndpoint.cs index 00c73e34..00c1eff6 100644 --- a/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/HealthCheck/Initialize/InitializeEndpoint.cs +++ b/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/HealthCheck/Initialize/InitializeEndpoint.cs @@ -1,4 +1,5 @@ -using Blog.Contracts.V1; +using Asp.Versioning; +using Blog.Contracts.V1; using Blog.Contracts.V1.Responses.UsersResponses; using Carter; using MediatR; @@ -10,7 +11,11 @@ public class InitializeEndpoint : ICarterModule { public void AddRoutes(IEndpointRouteBuilder app) { - app.MapGet("/health-check", async ([FromServices] ISender sender) => + var group = app.MapGroup("HealthCheck") + .MapToApiVersion(1.0) + .WithTags("HealthCheck"); + + group.MapGet("", async ([FromServices] ISender sender) => { try { @@ -45,7 +50,6 @@ public void AddRoutes(IEndpointRouteBuilder app) .Produces(StatusCodes.Status400BadRequest) .Produces(StatusCodes.Status404NotFound) .WithSummary("Initialize") - .WithDescription("Initialize") - .HasApiVersion(1.0); + .WithDescription("Initialize"); } } \ No newline at end of file From 54c2b1d2ae8baa75e026b745655daf9d46dda839 Mon Sep 17 00:00:00 2001 From: Vitalii Lakatosh Date: Fri, 17 Apr 2026 14:53:04 +0300 Subject: [PATCH 32/33] Configure Messages features --- .../CreateMessage/CreateMessageEndpoint.cs | 17 +++++------------ .../Features/Messages/GetAll/GetAllEndpoint.cs | 13 +++++++++---- .../Messages/GetById/GetByIdEndpoint.cs | 12 ++++++++---- .../GetRecipientMessagesEndpoint.cs | 12 ++++++++---- .../GetSenderMessagesEndpoint.cs | 12 ++++++++---- 5 files changed, 38 insertions(+), 28 deletions(-) diff --git a/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Messages/CreateMessage/CreateMessageEndpoint.cs b/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Messages/CreateMessage/CreateMessageEndpoint.cs index 59ae4400..58088c53 100644 --- a/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Messages/CreateMessage/CreateMessageEndpoint.cs +++ b/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Messages/CreateMessage/CreateMessageEndpoint.cs @@ -12,17 +12,11 @@ public class CreateMessageEndpoint : ICarterModule { public void AddRoutes(IEndpointRouteBuilder app) { - var versionSet = app.NewApiVersionSet() - .HasApiVersion(new ApiVersion(1, 0)) - .ReportApiVersions() - .Build(); + var group = app.MapGroup("Messages") + .MapToApiVersion(1.0) + .WithTags("Messages"); - var group = app.MapGroup(ApiRoutes.MessagesController.Messages) - .WithApiVersionSet(versionSet) - .MapToApiVersion(1.0) - .WithTags("Messages"); - - group.MapPost("/", + group.MapPost("", async ([FromBody] CreateMessageRequest request, [FromServices] ISender sender, [FromServices] HttpContext context) => @@ -45,7 +39,6 @@ public void AddRoutes(IEndpointRouteBuilder app) .Produces>(201) .Produces(400) .WithSummary("Create message") - .WithDescription("Create message") - .HasApiVersion(1.0); + .WithDescription("Create message"); } } diff --git a/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Messages/GetAll/GetAllEndpoint.cs b/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Messages/GetAll/GetAllEndpoint.cs index d9c7c2b6..895b0336 100644 --- a/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Messages/GetAll/GetAllEndpoint.cs +++ b/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Messages/GetAll/GetAllEndpoint.cs @@ -1,4 +1,6 @@ -using Blog.Contracts.V1.Responses; +using Asp.Versioning; +using Blog.Contracts.V1; +using Blog.Contracts.V1.Responses; using Carter; using MediatR; using Microsoft.AspNetCore.Mvc; @@ -9,7 +11,11 @@ public class GetAllEndpoint : ICarterModule { public void AddRoutes(IEndpointRouteBuilder app) { - app.MapGet("/comments", async ([FromServices] ISender sender) => + var group = app.MapGroup("Messages") + .MapToApiVersion(1.0) + .WithTags("Messages"); + + group.MapGet("", async ([FromServices] ISender sender) => { var result = await sender.Send(new GetAllQuery()); @@ -22,7 +28,6 @@ public void AddRoutes(IEndpointRouteBuilder app) .Produces(StatusCodes.Status400BadRequest) .Produces(StatusCodes.Status404NotFound) .WithSummary("Get All") - .WithDescription("Get All") - .HasApiVersion(1.0); + .WithDescription("Get All"); } } \ No newline at end of file diff --git a/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Messages/GetById/GetByIdEndpoint.cs b/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Messages/GetById/GetByIdEndpoint.cs index 252cb506..20157364 100644 --- a/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Messages/GetById/GetByIdEndpoint.cs +++ b/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Messages/GetById/GetByIdEndpoint.cs @@ -1,4 +1,5 @@ -using Blog.Contracts.V1; +using Asp.Versioning; +using Blog.Contracts.V1; using Blog.Contracts.V1.Responses; using Carter; using MediatR; @@ -10,7 +11,11 @@ public class GetByIdEndpoint : ICarterModule { public void AddRoutes(IEndpointRouteBuilder app) { - app.MapGet(ApiRoutes.MessagesController.Show, async ([FromRoute] int id, [FromServices] ISender sender) => + var group = app.MapGroup("Messages") + .MapToApiVersion(1.0) + .WithTags("Messages"); + + group.MapGet(ApiRoutes.MessagesController.Show, async ([FromRoute] int id, [FromServices] ISender sender) => { var result = await sender.Send(new GetByIdQuery(Id: id)); @@ -23,7 +28,6 @@ public void AddRoutes(IEndpointRouteBuilder app) .Produces(StatusCodes.Status400BadRequest) .Produces(StatusCodes.Status404NotFound) .WithSummary("Get By Id") - .WithDescription("Get By Id") - .HasApiVersion(1.0); + .WithDescription("Get By Id"); } } \ No newline at end of file diff --git a/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Messages/GetRecipientMessages/GetRecipientMessagesEndpoint.cs b/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Messages/GetRecipientMessages/GetRecipientMessagesEndpoint.cs index 50689545..19f0a621 100644 --- a/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Messages/GetRecipientMessages/GetRecipientMessagesEndpoint.cs +++ b/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Messages/GetRecipientMessages/GetRecipientMessagesEndpoint.cs @@ -1,4 +1,5 @@ -using Blog.Contracts.V1; +using Asp.Versioning; +using Blog.Contracts.V1; using Blog.Contracts.V1.Responses; using Carter; using MediatR; @@ -10,7 +11,11 @@ public class GetRecipientMessagesEndpoint : ICarterModule { public void AddRoutes(IEndpointRouteBuilder app) { - app.MapGet(ApiRoutes.MessagesController.GetRecipientMessages, async ([FromRoute] string recipientId, [FromServices] ISender sender) => + var group = app.MapGroup("Messages") + .MapToApiVersion(1.0) + .WithTags("Messages"); + + group.MapGet(ApiRoutes.MessagesController.GetRecipientMessages, async ([FromRoute] string recipientId, [FromServices] ISender sender) => { if (string.IsNullOrEmpty(recipientId)) return Results.BadRequest("Something went wrong"); @@ -26,7 +31,6 @@ public void AddRoutes(IEndpointRouteBuilder app) .Produces(StatusCodes.Status400BadRequest) .Produces(StatusCodes.Status404NotFound) .WithSummary("Get Recipient Messages") - .WithDescription("Get Recipient Messages") - .HasApiVersion(1.0); + .WithDescription("Get Recipient Messages"); } } \ No newline at end of file diff --git a/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Messages/GetSenderMessages/GetSenderMessagesEndpoint.cs b/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Messages/GetSenderMessages/GetSenderMessagesEndpoint.cs index 9cabd05d..ce515cba 100644 --- a/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Messages/GetSenderMessages/GetSenderMessagesEndpoint.cs +++ b/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Messages/GetSenderMessages/GetSenderMessagesEndpoint.cs @@ -1,4 +1,5 @@ -using Blog.Contracts.V1; +using Asp.Versioning; +using Blog.Contracts.V1; using Blog.Contracts.V1.Responses; using Carter; using MediatR; @@ -10,7 +11,11 @@ public class GetSenderMessagesEndpoint : ICarterModule { public void AddRoutes(IEndpointRouteBuilder app) { - app.MapGet(ApiRoutes.MessagesController.GetSenderMessages, async ([FromRoute] string senderEmail, [FromServices] ISender sender) => + var group = app.MapGroup("Messages") + .MapToApiVersion(1.0) + .WithTags("Messages"); + + group.MapGet(ApiRoutes.MessagesController.GetSenderMessages, async ([FromRoute] string senderEmail, [FromServices] ISender sender) => { if (string.IsNullOrEmpty(senderEmail)) return Results.BadRequest("Something went wrong"); @@ -26,7 +31,6 @@ public void AddRoutes(IEndpointRouteBuilder app) .Produces(StatusCodes.Status400BadRequest) .Produces(StatusCodes.Status404NotFound) .WithSummary("Get Sender Messages") - .WithDescription("Get Sender Messages") - .HasApiVersion(1.0); + .WithDescription("Get Sender Messages"); } } \ No newline at end of file From 824f6037c4fb134eead92ca712f68f383234910c Mon Sep 17 00:00:00 2001 From: Vitalii Lakatosh Date: Sat, 18 Apr 2026 14:53:31 +0300 Subject: [PATCH 33/33] Configure Posts features --- .../Posts/CreatePost/CreatePostEndpoint.cs | 11 ++--------- .../Posts/GetAllPosts/GetAllPostsEndpoint.cs | 12 ++++++++---- .../Posts/GetPostById/GetPostByIdEndpoint.cs | 12 ++++++++---- .../Features/Posts/GetPosts/GetPostsEndpoint.cs | 15 ++++----------- .../Features/Posts/GetPosts/GetPostsRequest.cs | 2 +- .../Posts/PostsActivity/PostsActivityEndpoint.cs | 16 ++++++++++------ .../Posts/UserPosts/UserPostsEndpoint.cs | 11 ++--------- 7 files changed, 35 insertions(+), 44 deletions(-) diff --git a/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Posts/CreatePost/CreatePostEndpoint.cs b/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Posts/CreatePost/CreatePostEndpoint.cs index c2991471..c4efeff2 100644 --- a/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Posts/CreatePost/CreatePostEndpoint.cs +++ b/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Posts/CreatePost/CreatePostEndpoint.cs @@ -12,13 +12,7 @@ public class GetPostsEndpoint : ICarterModule { public void AddRoutes(IEndpointRouteBuilder app) { - var versionSet = app.NewApiVersionSet() - .HasApiVersion(new ApiVersion(1, 0)) - .ReportApiVersions() - .Build(); - - var group = app.MapGroup(ApiRoutes.PostsController.Posts) - .WithApiVersionSet(versionSet) + var group = app.MapGroup("Posts") .MapToApiVersion(1.0) .WithTags("Posts"); @@ -45,7 +39,6 @@ public void AddRoutes(IEndpointRouteBuilder app) .Produces>(201) .Produces(400) .WithSummary("Create post") - .WithDescription("Create post") - .HasApiVersion(1.0); + .WithDescription("Create post"); } } diff --git a/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Posts/GetAllPosts/GetAllPostsEndpoint.cs b/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Posts/GetAllPosts/GetAllPostsEndpoint.cs index f0ff0040..a08f380d 100644 --- a/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Posts/GetAllPosts/GetAllPostsEndpoint.cs +++ b/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Posts/GetAllPosts/GetAllPostsEndpoint.cs @@ -1,4 +1,5 @@ -using Blog.Contracts.V1; +using Asp.Versioning; +using Blog.Contracts.V1; using Blog.Contracts.V1.Responses.PostsResponses; using Blog.Contracts.V1.Responses.UsersResponses; using Carter; @@ -11,7 +12,11 @@ public class GetAllPostsEndpoint : ICarterModule { public void AddRoutes(IEndpointRouteBuilder app) { - app.MapGet("/posts", async ([FromServices] ISender sender) => + var group = app.MapGroup("Posts") + .MapToApiVersion(1.0) + .WithTags("Posts"); + + group.MapGet("/posts", async ([FromServices] ISender sender) => { var result = await sender.Send(new GetAllPostsQuery()); @@ -24,7 +29,6 @@ public void AddRoutes(IEndpointRouteBuilder app) .Produces(StatusCodes.Status400BadRequest) .Produces(StatusCodes.Status404NotFound) .WithSummary("Get All Posts") - .WithDescription("Get All Posts") - .HasApiVersion(1.0); + .WithDescription("Get All Posts"); } } \ No newline at end of file diff --git a/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Posts/GetPostById/GetPostByIdEndpoint.cs b/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Posts/GetPostById/GetPostByIdEndpoint.cs index e63bf5bb..996e2d13 100644 --- a/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Posts/GetPostById/GetPostByIdEndpoint.cs +++ b/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Posts/GetPostById/GetPostByIdEndpoint.cs @@ -1,4 +1,5 @@ -using Blog.Contracts.V1; +using Asp.Versioning; +using Blog.Contracts.V1; using Blog.Contracts.V1.Responses.PostsResponses; using Blog.Contracts.V1.Responses.UsersResponses; using Carter; @@ -11,7 +12,11 @@ public class GetPostByIdEndpoint : ICarterModule { public void AddRoutes(IEndpointRouteBuilder app) { - app.MapGet(ApiRoutes.PostsController.Show, async ([FromRoute] int id, [FromServices] ISender sender) => + var group = app.MapGroup("Posts") + .MapToApiVersion(1.0) + .WithTags("Posts"); + + group.MapGet(ApiRoutes.PostsController.Show, async ([FromRoute] int id, [FromServices] ISender sender) => { var result = await sender.Send(new GetPostByIdQuery(Id: id)); @@ -24,7 +29,6 @@ public void AddRoutes(IEndpointRouteBuilder app) .Produces(StatusCodes.Status400BadRequest) .Produces(StatusCodes.Status404NotFound) .WithSummary("Get Post By Id") - .WithDescription("Get Post By Id") - .HasApiVersion(1.0); + .WithDescription("Get Post By Id"); } } \ No newline at end of file diff --git a/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Posts/GetPosts/GetPostsEndpoint.cs b/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Posts/GetPosts/GetPostsEndpoint.cs index 1b97357c..07223064 100644 --- a/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Posts/GetPosts/GetPostsEndpoint.cs +++ b/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Posts/GetPosts/GetPostsEndpoint.cs @@ -12,18 +12,12 @@ public class UserPostsEndpoint : ICarterModule { public void AddRoutes(IEndpointRouteBuilder app) { - var versionSet = app.NewApiVersionSet() - .HasApiVersion(new ApiVersion(1, 0)) - .ReportApiVersions() - .Build(); - - var group = app.MapGroup(ApiRoutes.PostsController.Posts) - .WithApiVersionSet(versionSet) + var group = app.MapGroup("Posts") .MapToApiVersion(1.0) .WithTags("Posts"); - group.MapPost(ApiRoutes.PostsController.GetPosts, - async ([FromBody] UserPostsRequest request, + group.MapPost("", + async ([FromBody] GetPostsRequest request, [FromServices] ISender sender) => { var command = request.Adapt(); @@ -39,7 +33,6 @@ public void AddRoutes(IEndpointRouteBuilder app) .Produces() .Produces(StatusCodes.Status400BadRequest) .WithSummary("Get Posts") - .WithDescription("Get Posts") - .HasApiVersion(1.0); + .WithDescription("Get Posts"); } } diff --git a/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Posts/GetPosts/GetPostsRequest.cs b/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Posts/GetPosts/GetPostsRequest.cs index 9a4a388b..b28364b3 100644 --- a/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Posts/GetPosts/GetPostsRequest.cs +++ b/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Posts/GetPosts/GetPostsRequest.cs @@ -1,3 +1,3 @@ namespace BlogVerticalSliceCQRSMinimalApi.Features.Posts.GetPosts; -public class UserPostsRequest(string OrderBy, string SortBy, int? CurrentPage, int? PageSize, string DisplayType, string Tag); \ No newline at end of file +public class GetPostsRequest(string OrderBy, string SortBy, int? CurrentPage, int? PageSize, string DisplayType, string Tag); \ No newline at end of file diff --git a/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Posts/PostsActivity/PostsActivityEndpoint.cs b/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Posts/PostsActivity/PostsActivityEndpoint.cs index 9fa8f45f..aa3d779c 100644 --- a/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Posts/PostsActivity/PostsActivityEndpoint.cs +++ b/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Posts/PostsActivity/PostsActivityEndpoint.cs @@ -1,16 +1,21 @@ -using Blog.Contracts.V1; +using Asp.Versioning; +using Blog.Contracts.V1; using Blog.Contracts.V1.Responses.Chart; using Carter; using MediatR; using Microsoft.AspNetCore.Mvc; namespace BlogVerticalSliceCQRSMinimalApi.Features.Posts.PostsActivity; - +/* public class PostsActivityEndpoint : ICarterModule { public void AddRoutes(IEndpointRouteBuilder app) { - app.MapGet(ApiRoutes.PostsController.PostsActivity, async ([FromServices] ISender sender) => + var group = app.MapGroup("Posts") + .MapToApiVersion(1.0) + .WithTags("Posts"); + + group.MapGet(ApiRoutes.PostsController.PostsActivity, async ([FromServices] ISender sender) => { var result = await sender.Send(new PostsActivityQuery()); @@ -23,7 +28,6 @@ public void AddRoutes(IEndpointRouteBuilder app) .Produces(StatusCodes.Status400BadRequest) .Produces(StatusCodes.Status404NotFound) .WithSummary("Posts Activity") - .WithDescription("Posts Activity") - .HasApiVersion(1.0); + .WithDescription("Posts Activity"); } -} \ No newline at end of file +}*/ \ No newline at end of file diff --git a/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Posts/UserPosts/UserPostsEndpoint.cs b/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Posts/UserPosts/UserPostsEndpoint.cs index 9b77c580..ef1e825b 100644 --- a/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Posts/UserPosts/UserPostsEndpoint.cs +++ b/BlogWebApp/BlogVerticalSliceCQRSMinimalApi/Features/Posts/UserPosts/UserPostsEndpoint.cs @@ -12,13 +12,7 @@ public class UserPostsEndpoint : ICarterModule { public void AddRoutes(IEndpointRouteBuilder app) { - var versionSet = app.NewApiVersionSet() - .HasApiVersion(new ApiVersion(1, 0)) - .ReportApiVersions() - .Build(); - - var group = app.MapGroup(ApiRoutes.PostsController.Posts) - .WithApiVersionSet(versionSet) + var group = app.MapGroup("Posts") .MapToApiVersion(1.0) .WithTags("Posts"); @@ -41,7 +35,6 @@ public void AddRoutes(IEndpointRouteBuilder app) .Produces() .Produces(StatusCodes.Status400BadRequest) .WithSummary("User Posts") - .WithDescription("User Posts") - .HasApiVersion(1.0); + .WithDescription("User Posts"); } }