From 27a0b74a9f813ccbaf3e55c32c34227d33fe2ff6 Mon Sep 17 00:00:00 2001 From: meysamhadeli Date: Wed, 16 Nov 2022 00:39:05 +0330 Subject: [PATCH] update apis to minimal-api --- booking.rest | 30 ++--- src/BuildingBlocks/BuildingBlocks.csproj | 8 +- .../Swagger/ConfigureSwaggerOptions.cs | 116 ++++++++++++------ .../Swagger/ServiceCollectionExtensions.cs | 76 ++++++------ .../Web/ApiVersioningExtensions.cs | 62 ++++++---- src/BuildingBlocks/Web/BaseController.cs | 3 +- src/BuildingBlocks/Web/EndpointConfig.cs | 9 ++ src/BuildingBlocks/Web/IMinimalEndpoint.cs | 8 ++ .../Web/MinimalApiExtensions.cs | 43 +++++++ .../Booking/src/Booking.Api/Program.cs | 9 +- .../Endpoints/V1/CreateBookingEndpoint.cs | 35 ++++-- src/Services/Flight/src/Flight.Api/Program.cs | 11 +- .../Endpoints/V1/CreateAircraftEndpoint.cs | 36 ++++-- .../Endpoints/V1/CreateAirportEndpoint.cs | 36 ++++-- .../Flight/Flights/Dtos/FlightResponseDto.cs | 2 +- .../Endpoints/V1/CreateFlightEndpoint.cs | 36 ++++-- .../Endpoints/V1/DeleteFlightEndpoint.cs | 37 ++++-- .../V1/GetAvailableFlightsEndpoint.cs | 39 +++--- .../Endpoints/V1/GetFlightByIdEndpoint.cs | 66 +++++++--- .../Endpoints/V1/UpdateFlightEndpoint.cs | 38 +++--- .../src/Flight/Seats/Dtos/SeatResponseDto.cs | 4 +- .../Endpoints/V1/CreateSeatEndpoint.cs | 62 ++++++++-- .../Endpoints/V1/GetAvailableSeatsEndpoint.cs | 41 ++++--- .../Endpoints/V1/ReserveSeatEndpoint.cs | 38 +++--- .../Identity/src/Identity.Api/Program.cs | 9 +- .../Endpoints/V1/RegisterNewUserEndpoint.cs | 37 +++--- .../Passenger/src/Passenger.Api/Program.cs | 9 +- .../Passengers/Dtos/PassengerResponseDto.cs | 4 +- .../V1/CompleteRegisterPassengerEndpoint.cs | 35 ++++-- .../Endpoints/V1/GetPassengerByIdEndpoint.cs | 35 ++++-- 30 files changed, 652 insertions(+), 322 deletions(-) create mode 100644 src/BuildingBlocks/Web/EndpointConfig.cs create mode 100644 src/BuildingBlocks/Web/IMinimalEndpoint.cs create mode 100644 src/BuildingBlocks/Web/MinimalApiExtensions.cs diff --git a/booking.rest b/booking.rest index 291dfa7..f4ca175 100644 --- a/booking.rest +++ b/booking.rest @@ -33,19 +33,19 @@ grant_type=password ### # @name Register_New_User -POST {{api-gateway}}/identity/register-user +POST {{api-gateway}}/api/v1/identity/register-user accept: application/json Content-Type: application/json authorization: bearer {{Authenticate.response.body.access_token}} { - "firstName": "John", - "lastName": "Do", - "username": "admin", - "passportNumber": "12900000000", - "email": "admin@admin.com", - "password": "Admin@12345", - "confirmPassword": "Admin@12345" + "firstName": "4John", + "lastName": "4Do", + "username": "4admin", + "passportNumber": "412900000000", + "email": "4admin@admin.com", + "password": "4Admin@12345", + "confirmPassword": "4Admin@12345" } ### @@ -64,7 +64,7 @@ Content-Type: application/json authorization: bearer {{Authenticate.response.body.access_token}} { - "seatNumber": "12H9", + "seatNumber": "1255", "type": 1, "class": 1, "flightId": 1 @@ -81,7 +81,7 @@ authorization: bearer {{Authenticate.response.body.access_token}} { "flightId": 1, - "seatNumber": "12H9" + "seatNumber": "1255" } ### @@ -161,14 +161,10 @@ authorization: bearer {{Authenticate.response.body.access_token}} ### # @name Delete_Flights -DELETE {{api-gateway}}/api/v1/flight +DELETE {{api-gateway}}/api/v1/flight/{{flightid}} accept: application/json Content-Type: application/json authorization: bearer {{Authenticate.response.body.access_token}} - -{ - "id": 1 -} ### @@ -219,7 +215,7 @@ Content-Type: application/json authorization: bearer {{Authenticate.response.body.access_token}} { - "passportNumber": "12900000000", + "passportNumber": "412900000000", "passengerType": 1, "age": 30 } @@ -251,7 +247,7 @@ Content-Type: application/json authorization: bearer {{Authenticate.response.body.access_token}} { - "passengerId": 7201620062109696, + "passengerId": 7225627535474688, "flightId": 1, "description": "I want to fly to iran" } diff --git a/src/BuildingBlocks/BuildingBlocks.csproj b/src/BuildingBlocks/BuildingBlocks.csproj index 9f78129..ba56da6 100644 --- a/src/BuildingBlocks/BuildingBlocks.csproj +++ b/src/BuildingBlocks/BuildingBlocks.csproj @@ -8,6 +8,10 @@ + + + + @@ -22,6 +26,7 @@ + @@ -41,7 +46,6 @@ - @@ -67,10 +71,10 @@ + - diff --git a/src/BuildingBlocks/Swagger/ConfigureSwaggerOptions.cs b/src/BuildingBlocks/Swagger/ConfigureSwaggerOptions.cs index 8480f20..ce67f17 100644 --- a/src/BuildingBlocks/Swagger/ConfigureSwaggerOptions.cs +++ b/src/BuildingBlocks/Swagger/ConfigureSwaggerOptions.cs @@ -1,48 +1,90 @@ -using System; -using Microsoft.AspNetCore.Mvc.ApiExplorer; +using System.Text; +using Asp.Versioning; +using Asp.Versioning.ApiExplorer; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Options; using Microsoft.OpenApi.Models; using Swashbuckle.AspNetCore.SwaggerGen; -namespace BuildingBlocks.Swagger +namespace BuildingBlocks.Swagger; + +public class ConfigureSwaggerOptions : IConfigureOptions { - public class ConfigureSwaggerOptions : IConfigureOptions + private readonly IApiVersionDescriptionProvider provider; + private readonly SwaggerOptions? _options; + + /// + /// Initializes a new instance of the class. + /// + /// The provider used to generate Swagger documents. + public ConfigureSwaggerOptions(IApiVersionDescriptionProvider provider, IOptions options) { - private readonly IApiVersionDescriptionProvider _provider; - private readonly SwaggerOptions _options; + this.provider = provider; + _options = options.Value; + } - public ConfigureSwaggerOptions(IApiVersionDescriptionProvider provider, IOptions options) + /// + public void Configure(SwaggerGenOptions options) + { + // add a swagger document for each discovered API version + // note: you might choose to skip or document deprecated API versions differently + foreach (var description in provider.ApiVersionDescriptions) { - _provider = provider; - _options = options.Value; - } - - public void Configure(SwaggerGenOptions options) - { - foreach (var description in _provider.ApiVersionDescriptions) - { - options.SwaggerDoc(description.GroupName, CreateInfoForApiVersion(description)); - } - } - - private OpenApiInfo CreateInfoForApiVersion(ApiVersionDescription description) - { - var info = new OpenApiInfo - { - Title = _options.Title ?? "APIs", - Version =_options.Version ?? description.ApiVersion.ToString(), - Description = "An application with Swagger, Swashbuckle, and API versioning.", - Contact = new OpenApiContact { Name = "", Email = "" }, - License = new OpenApiLicense { Name = "MIT", Url = new Uri("https://opensource.org/licenses/MIT") } - }; - - if (description.IsDeprecated) - { - info.Description += " This API version has been deprecated."; - } - - return info; + options.SwaggerDoc(description.GroupName, CreateInfoForApiVersion(description)); } } -} \ No newline at end of file + + private OpenApiInfo CreateInfoForApiVersion(ApiVersionDescription description) + { + var text = new StringBuilder("An example application with OpenAPI, Swashbuckle, and API versioning."); + var info = new OpenApiInfo + { + Version = description.ApiVersion.ToString(), + Title = _options?.Title ?? "APIs", + Description = "An application with Swagger, Swashbuckle, and API versioning.", + Contact = new OpenApiContact {Name = "", Email = ""}, + License = new OpenApiLicense {Name = "MIT", Url = new Uri("https://opensource.org/licenses/MIT")} + }; + + if (description.IsDeprecated) + { + text.Append("This API version has been deprecated."); + } + + if (description.SunsetPolicy is SunsetPolicy policy) + { + if (policy.Date is DateTimeOffset when) + { + text.Append(" The API will be sunset on ") + .Append(when.Date.ToShortDateString()) + .Append('.'); + } + + if (policy.HasLinks) + { + text.AppendLine(); + + for (var i = 0; i < policy.Links.Count; i++) + { + var link = policy.Links[i]; + + if (link.Type == "text/html") + { + text.AppendLine(); + + if (link.Title.HasValue) + { + text.Append(link.Title.Value).Append(": "); + } + + text.Append(link.LinkTarget.OriginalString); + } + } + } + } + + info.Description = text.ToString(); + + return info; + } +} diff --git a/src/BuildingBlocks/Swagger/ServiceCollectionExtensions.cs b/src/BuildingBlocks/Swagger/ServiceCollectionExtensions.cs index 1b47a3e..3ef5193 100644 --- a/src/BuildingBlocks/Swagger/ServiceCollectionExtensions.cs +++ b/src/BuildingBlocks/Swagger/ServiceCollectionExtensions.cs @@ -1,46 +1,36 @@ using System.Reflection; using Microsoft.AspNetCore.Builder; -using Microsoft.AspNetCore.Mvc.ApiExplorer; -using Microsoft.AspNetCore.Mvc.Controllers; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Options; -using Microsoft.Extensions.PlatformAbstractions; using Microsoft.OpenApi.Models; using Swashbuckle.AspNetCore.SwaggerGen; namespace BuildingBlocks.Swagger; -//https://github.com/domaindrivendev/Swashbuckle.AspNetCore/blob/master/README.md public static class ServiceCollectionExtensions { public const string HeaderName = "X-Api-Key"; + public const string HeaderVersion = "api-version"; + // https://github.com/domaindrivendev/Swashbuckle.AspNetCore/blob/master/README.md + // https://github.com/dotnet/aspnet-api-versioning/tree/88323136a97a59fcee24517a514c1a445530c7e2/examples/AspNetCore/WebApi/MinimalOpenApiExample public static IServiceCollection AddCustomSwagger(this IServiceCollection services, IConfiguration configuration, - Assembly assembly, string swaggerSectionName = "SwaggerOptions") + Assembly assembly) { - services.AddVersionedApiExplorer(options => - { - // add the versioned api explorer, which also adds IApiVersionDescriptionProvider service - // note: the specified format code will format the version as "'v'major[.minor][-status]" - options.GroupNameFormat = "'v'VVV"; - - // note: this option is only necessary when versioning by url segment. the SubstitutionFormat - // can also be used to control the format of the API version in route templates - options.SubstituteApiVersionInUrl = true; - }); - - services.AddOptions().Bind(configuration.GetSection(swaggerSectionName)) - .ValidateDataAnnotations(); + // https://learn.microsoft.com/en-us/aspnet/core/fundamentals/minimal-apis/openapi + services.AddEndpointsApiExplorer(); services.AddTransient, ConfigureSwaggerOptions>(); + services.AddOptions().Bind(configuration.GetSection(nameof(SwaggerOptions))) + .ValidateDataAnnotations(); services.AddSwaggerGen( options => { - // options.DescribeAllParametersInCamelCase(); options.OperationFilter(); + var xmlFile = XmlCommentsFilePath(assembly); if (File.Exists(xmlFile)) options.IncludeXmlComments(xmlFile); @@ -55,7 +45,8 @@ public static class ServiceCollectionExtensions Scheme = "Bearer" }); - options.AddSecurityDefinition(HeaderName, + options.AddSecurityDefinition( + HeaderName, new OpenApiSecurityScheme { Description = "Api key needed to access the endpoints. X-Api-Key: My_API_Key", @@ -82,49 +73,52 @@ public static class ServiceCollectionExtensions Name = HeaderName, Type = SecuritySchemeType.ApiKey, In = ParameterLocation.Header, - Reference = new OpenApiReference {Type = ReferenceType.SecurityScheme, Id = HeaderName} + Reference = new OpenApiReference + { + Type = ReferenceType.SecurityScheme, Id = HeaderName + } }, - new string[] { } + Array.Empty() } }); - //https://rimdev.io/swagger-grouping-with-controller-name-fallback-using-swashbuckle-aspnetcore/ - options.TagActionsBy(api => - { - if (api.GroupName != null) return new[] {api.GroupName}; + options.ResolveConflictingActions(apiDescriptions => apiDescriptions.First()); - if (api.ActionDescriptor is ControllerActionDescriptor controllerActionDescriptor) - return new[] {controllerActionDescriptor.ControllerName}; - - throw new InvalidOperationException("Unable to determine tag for endpoint."); - }); - - options.DocInclusionPredicate((name, api) => true); + ////https://github.com/domaindrivendev/Swashbuckle.AspNetCore/issues/467 + // options.OperationFilter(); + // options.OperationFilter(); + // Enables Swagger annotations (SwaggerOperationAttribute, SwaggerParameterAttribute etc.) options.EnableAnnotations(); }); - - return services; + services.Configure(o => o.InferSecuritySchemes = true); static string XmlCommentsFilePath(Assembly assembly) { - var basePath = PlatformServices.Default.Application.ApplicationBasePath; + var basePath = Path.GetDirectoryName(assembly.Location); var fileName = assembly.GetName().Name + ".xml"; return Path.Combine(basePath, fileName); } + + return services; } - public static IApplicationBuilder UseCustomSwagger(this IApplicationBuilder app, - IApiVersionDescriptionProvider provider) + public static IApplicationBuilder UseCustomSwagger(this WebApplication app) { app.UseSwagger(); app.UseSwaggerUI( options => { - foreach (var description in provider.ApiVersionDescriptions) - options.SwaggerEndpoint($"/swagger/{description.GroupName}/swagger.json", - description.GroupName.ToUpperInvariant()); + var descriptions = app.DescribeApiVersions(); + + // build a swagger endpoint for each discovered API version + foreach (var description in descriptions) + { + var url = $"/swagger/{description.GroupName}/swagger.json"; + var name = description.GroupName.ToUpperInvariant(); + options.SwaggerEndpoint(url, name); + } }); return app; diff --git a/src/BuildingBlocks/Web/ApiVersioningExtensions.cs b/src/BuildingBlocks/Web/ApiVersioningExtensions.cs index a893b44..7449c8e 100644 --- a/src/BuildingBlocks/Web/ApiVersioningExtensions.cs +++ b/src/BuildingBlocks/Web/ApiVersioningExtensions.cs @@ -1,34 +1,54 @@ -using Microsoft.AspNetCore.Mvc; -using Microsoft.AspNetCore.Mvc.Versioning; +using Asp.Versioning; using Microsoft.Extensions.DependencyInjection; namespace BuildingBlocks.Web; public static class ApiVersioningExtensions { - public static void AddCustomVersioning(this IServiceCollection services, - Action configurator = null) + public static void AddCustomVersioning( + this IServiceCollection services, + Action? configurator = null) { - //https://www.meziantou.net/versioning-an-asp-net-core-api.htm - //https://exceptionnotfound.net/overview-of-api-versioning-in-asp-net-core-3-0/ + // https://www.meziantou.net/versioning-an-asp-net-core-api.htm + // https://dotnetthoughts.net/aspnetcore-api-versioning-with-net-6-minimal-apis/ + // https://im5tu.io/article/2022/10/asp.net-core-versioning-minimal-apis/ + // https://www.youtube.com/watch?v=YRJGKyzjFlY + // https://www.nuget.org/packages/Asp.Versioning.Http + + // Support versioning in minimal apis with (Asp.Versioning.Http) dll services.AddApiVersioning(options => - { - // Add the headers "api-supported-versions" and "api-deprecated-versions" - // This is better for discoverability - options.ReportApiVersions = true; + { + // Add the headers "api-supported-versions" and "api-deprecated-versions" + // This is better for discoverability + options.ReportApiVersions = true; - // AssumeDefaultVersionWhenUnspecified should only be enabled when supporting legacy services that did not previously - // support API versioning. Forcing existing clients to specify an explicit API version for an - // existing service introduces a breaking change. Conceptually, clients in this situation are - // bound to some API version of a service, but they don't know what it is and never explicit request it. - options.AssumeDefaultVersionWhenUnspecified = true; - options.DefaultApiVersion = new ApiVersion(1, 0); + // AssumeDefaultVersionWhenUnspecified should only be enabled when supporting legacy services that did not previously + // support API versioning. Forcing existing clients to specify an explicit API version for an + // existing service introduces a breaking change. Conceptually, clients in this situation are + // bound to some API version of a service, but they don't know what it is and never explicit request it. + options.AssumeDefaultVersionWhenUnspecified = true; + options.DefaultApiVersion = new ApiVersion(1, 0); - // // Defines how an API version is read from the current HTTP request - options.ApiVersionReader = ApiVersionReader.Combine(new HeaderApiVersionReader("api-version"), - new UrlSegmentApiVersionReader()); + // Defines how an API version is read from the current HTTP request + options.ApiVersionReader = ApiVersionReader.Combine( + new HeaderApiVersionReader("api-version"), + new UrlSegmentApiVersionReader()); - configurator?.Invoke(options); - }); + configurator?.Invoke(options); + }) + .AddApiExplorer( + options => + { + // add the versioned api explorer, which also adds IApiVersionDescriptionProvider service + // note: the specified format code will format the version as "'v'major[.minor][-status]" + options.GroupNameFormat = "'v'VVV"; + + // note: this option is only necessary when versioning by url segment. the SubstitutionFormat + // can also be used to control the format of the API version in route templates + options.SubstituteApiVersionInUrl = true; + }) + + // Support versioning in mvc with with (Asp.Versioning.Mvc.ApiExplorer) dll + .AddMvc(); // https://www.nuget.org/packages/Asp.Versioning.Mvc.ApiExplorer } } diff --git a/src/BuildingBlocks/Web/BaseController.cs b/src/BuildingBlocks/Web/BaseController.cs index bbbaadc..ec70ecf 100644 --- a/src/BuildingBlocks/Web/BaseController.cs +++ b/src/BuildingBlocks/Web/BaseController.cs @@ -1,4 +1,5 @@ -using AutoMapper; +using Asp.Versioning; +using AutoMapper; using MediatR; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.DependencyInjection; diff --git a/src/BuildingBlocks/Web/EndpointConfig.cs b/src/BuildingBlocks/Web/EndpointConfig.cs new file mode 100644 index 0000000..43afbc7 --- /dev/null +++ b/src/BuildingBlocks/Web/EndpointConfig.cs @@ -0,0 +1,9 @@ +using Asp.Versioning.Builder; + +namespace BuildingBlocks.Web; + +public class EndpointConfig +{ + public const string BaseApiPath = "api/v{version:apiVersion}"; + public static ApiVersionSet VersionSet { get; private set; } = default!; +} diff --git a/src/BuildingBlocks/Web/IMinimalEndpoint.cs b/src/BuildingBlocks/Web/IMinimalEndpoint.cs new file mode 100644 index 0000000..7b443c5 --- /dev/null +++ b/src/BuildingBlocks/Web/IMinimalEndpoint.cs @@ -0,0 +1,8 @@ +using Microsoft.AspNetCore.Routing; + +namespace BuildingBlocks.Web; + +public interface IMinimalEndpoint +{ + IEndpointRouteBuilder MapEndpoint(IEndpointRouteBuilder builder); +} diff --git a/src/BuildingBlocks/Web/MinimalApiExtensions.cs b/src/BuildingBlocks/Web/MinimalApiExtensions.cs new file mode 100644 index 0000000..bd0ab64 --- /dev/null +++ b/src/BuildingBlocks/Web/MinimalApiExtensions.cs @@ -0,0 +1,43 @@ +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Routing; +using Microsoft.Extensions.DependencyInjection; +using Scrutor; + +namespace BuildingBlocks.Web; + +public static class MinimalApiExtensions +{ + + public static IServiceCollection AddMinimalEndpoints( + this WebApplicationBuilder applicationBuilder, + ServiceLifetime lifetime = ServiceLifetime.Scoped) + { + applicationBuilder.Services.Scan(scan => scan + .FromAssemblies(AppDomain.CurrentDomain.GetAssemblies()) + .AddClasses(classes => classes.AssignableTo(typeof(IMinimalEndpoint))) + .UsingRegistrationStrategy(RegistrationStrategy.Append) + .As() + .WithLifetime(lifetime)); + + return applicationBuilder.Services; + } + + /// + /// Map Minimal Endpoints + /// + /// builder. + /// IEndpointRouteBuilder. + public static IEndpointRouteBuilder MapMinimalEndpoints(this IEndpointRouteBuilder builder) + { + var scope = builder.ServiceProvider.CreateScope(); + + var endpoints = scope.ServiceProvider.GetServices(); + + foreach (var endpoint in endpoints) + { + endpoint.MapEndpoint(builder); + } + + return builder; + } +} diff --git a/src/Services/Booking/src/Booking.Api/Program.cs b/src/Services/Booking/src/Booking.Api/Program.cs index 9931863..9f40e32 100644 --- a/src/Services/Booking/src/Booking.Api/Program.cs +++ b/src/Services/Booking/src/Booking.Api/Program.cs @@ -34,7 +34,6 @@ builder.Services.AddMongoDbContext(configuration); builder.AddCustomSerilog(env); builder.Services.AddCore(); builder.Services.AddJwt(); -builder.Services.AddControllers(); builder.Services.AddHttpContextAccessor(); builder.Services.AddCustomSwagger(configuration, typeof(BookingRoot).Assembly); builder.Services.AddCustomVersioning(); @@ -55,12 +54,13 @@ builder.Services.AddEventStore(configuration, typeof(BookingRoot).Assembly) builder.Services.AddGrpcClients(); +builder.AddMinimalEndpoints(); + var app = builder.Build(); if (app.Environment.IsDevelopment()) { - var provider = app.Services.GetService(); - app.UseCustomSwagger(provider); + app.UseCustomSwagger(); } app.UseSerilogRequestLogging(); @@ -73,9 +73,10 @@ app.UseAuthorization(); app.UseProblemDetails(); app.UseCustomHealthCheck(); +app.MapMinimalEndpoints(); + app.UseEndpoints(endpoints => { - endpoints.MapControllers(); endpoints.MapMetrics(); }); diff --git a/src/Services/Booking/src/Booking/Booking/Features/CreateBooking/Endpoints/V1/CreateBookingEndpoint.cs b/src/Services/Booking/src/Booking/Booking/Features/CreateBooking/Endpoints/V1/CreateBookingEndpoint.cs index af7d105..130b9af 100644 --- a/src/Services/Booking/src/Booking/Booking/Features/CreateBooking/Endpoints/V1/CreateBookingEndpoint.cs +++ b/src/Services/Booking/src/Booking/Booking/Features/CreateBooking/Endpoints/V1/CreateBookingEndpoint.cs @@ -1,25 +1,36 @@ using Booking.Booking.Features.CreateBooking.Commands.V1; using BuildingBlocks.Web; +using MediatR; using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Routing; using Swashbuckle.AspNetCore.Annotations; namespace Booking.Booking.Features.CreateBooking.Endpoints.V1; - -[Route(BaseApiPath + "/booking")] -public class CreateBookingEndpoint : BaseController +public class CreateBookingEndpoint : IMinimalEndpoint { - [HttpPost] - [Authorize] - [ProducesResponseType(StatusCodes.Status201Created)] - [ProducesResponseType(StatusCodes.Status400BadRequest)] - [SwaggerOperation(Summary = "Create new Reservation", Description = "Create new Reservation")] - public async Task CreateReservation([FromBody] CreateBookingCommand command, - CancellationToken cancellationToken) + public IEndpointRouteBuilder MapEndpoint(IEndpointRouteBuilder endpoints) { - var result = await Mediator.Send(command, cancellationToken); + endpoints.MapPost($"{EndpointConfig.BaseApiPath}/booking", CreateBooking) + .RequireAuthorization() + .WithTags("Booking") + .WithName("Create Booking") + .WithMetadata(new SwaggerOperationAttribute("Create Booking", "Create Booking")) + .WithApiVersionSet(endpoints.NewApiVersionSet("Booking").Build()) + .Produces() + .Produces(StatusCodes.Status201Created) + .Produces(StatusCodes.Status400BadRequest) + .HasApiVersion(1.0); - return Ok(result); + return endpoints; + } + + private async Task CreateBooking(CreateBookingCommand command, IMediator mediator, CancellationToken cancellationToken) + { + var result = await mediator.Send(command, cancellationToken); + + return Results.Ok(result); } } diff --git a/src/Services/Flight/src/Flight.Api/Program.cs b/src/Services/Flight/src/Flight.Api/Program.cs index 81c943e..6f11429 100644 --- a/src/Services/Flight/src/Flight.Api/Program.cs +++ b/src/Services/Flight/src/Flight.Api/Program.cs @@ -18,6 +18,7 @@ using Flight; using Flight.Data; using Flight.Data.Seed; using Flight.Extensions; +using Flight.Flights.Features.CreateFlight.Endpoints.V1; using Flight.GrpcServer.Services; using FluentValidation; using Hellang.Middleware.ProblemDetails; @@ -41,7 +42,6 @@ builder.Services.AddPersistMessage(configuration); builder.AddCustomSerilog(env); builder.Services.AddCore(); builder.Services.AddJwt(); -builder.Services.AddControllers(); builder.Services.AddCustomSwagger(configuration, typeof(FlightRoot).Assembly); builder.Services.AddCustomVersioning(); builder.Services.AddCustomMediatR(); @@ -65,12 +65,13 @@ builder.Services.AddCachingRequest(new List {typeof(FlightRoot).Assemb builder.Services.AddEasyCaching(options => { options.UseInMemory(configuration, "mem"); }); +builder.AddMinimalEndpoints(); + var app = builder.Build(); if (app.Environment.IsDevelopment()) { - var provider = app.Services.GetService(); - app.UseCustomSwagger(provider); + app.UseCustomSwagger(); } app.UseSerilogRequestLogging(); @@ -84,9 +85,11 @@ app.UseCustomHealthCheck(); app.UseAuthentication(); app.UseAuthorization(); + +app.MapMinimalEndpoints(); + app.UseEndpoints(endpoints => { - endpoints.MapControllers(); endpoints.MapMetrics(); endpoints.MapGrpcService(); }); diff --git a/src/Services/Flight/src/Flight/Aircrafts/Features/CreateAircraft/Endpoints/V1/CreateAircraftEndpoint.cs b/src/Services/Flight/src/Flight/Aircrafts/Features/CreateAircraft/Endpoints/V1/CreateAircraftEndpoint.cs index 4682311..02efcb8 100644 --- a/src/Services/Flight/src/Flight/Aircrafts/Features/CreateAircraft/Endpoints/V1/CreateAircraftEndpoint.cs +++ b/src/Services/Flight/src/Flight/Aircrafts/Features/CreateAircraft/Endpoints/V1/CreateAircraftEndpoint.cs @@ -1,24 +1,36 @@ using System.Threading; using System.Threading.Tasks; using BuildingBlocks.Web; +using Flight.Aircrafts.Dtos; using Flight.Aircrafts.Features.CreateAircraft.Commands.V1; +using MediatR; +using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Routing; using Swashbuckle.AspNetCore.Annotations; -namespace Flight.Aircrafts.Features.CreateAircraft.Endpoints.V1; - -[Route(BaseApiPath + "/flight/aircraft")] -public class CreateAircraftEndpoint : BaseController +public class CreateAircraftEndpoint : IMinimalEndpoint { - [HttpPost] - [ProducesResponseType(StatusCodes.Status201Created)] - [ProducesResponseType(StatusCodes.Status400BadRequest)] - [SwaggerOperation(Summary = "Create new aircraft", Description = "Create new aircraft")] - public async Task Create([FromBody] CreateAircraftCommand command, CancellationToken cancellationToken) + public IEndpointRouteBuilder MapEndpoint(IEndpointRouteBuilder endpoints) { - var result = await Mediator.Send(command, cancellationToken); + endpoints.MapPost($"{EndpointConfig.BaseApiPath}/flight/aircraft", CreateAircraft) + .RequireAuthorization() + .WithTags("Flight") + .WithName("Create Aircraft") + .WithMetadata(new SwaggerOperationAttribute("Create Aircraft", "Create Aircraft")) + .WithApiVersionSet(endpoints.NewApiVersionSet("Flight").Build()) + .Produces() + .Produces(StatusCodes.Status201Created) + .Produces(StatusCodes.Status400BadRequest) + .HasApiVersion(1.0); - return Ok(result); + return endpoints; + } + + private async Task CreateAircraft(CreateAircraftCommand command, IMediator mediator, CancellationToken cancellationToken) + { + var result = await mediator.Send(command, cancellationToken); + + return Results.Ok(result); } } diff --git a/src/Services/Flight/src/Flight/Airports/Features/CreateAirport/Endpoints/V1/CreateAirportEndpoint.cs b/src/Services/Flight/src/Flight/Airports/Features/CreateAirport/Endpoints/V1/CreateAirportEndpoint.cs index 0d37781..9bd67d9 100644 --- a/src/Services/Flight/src/Flight/Airports/Features/CreateAirport/Endpoints/V1/CreateAirportEndpoint.cs +++ b/src/Services/Flight/src/Flight/Airports/Features/CreateAirport/Endpoints/V1/CreateAirportEndpoint.cs @@ -1,24 +1,36 @@ using System.Threading; using System.Threading.Tasks; using BuildingBlocks.Web; +using Flight.Airports.Dtos; using Flight.Airports.Features.CreateAirport.Commands.V1; +using MediatR; +using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Routing; using Swashbuckle.AspNetCore.Annotations; -namespace Flight.Airports.Features.CreateAirport.Endpoints.V1; - -[Route(BaseApiPath + "/flight/airport")] -public class CreateAirportEndpoint : BaseController +public class CreateAirportEndpoint : IMinimalEndpoint { - [HttpPost] - [ProducesResponseType(StatusCodes.Status201Created)] - [ProducesResponseType(StatusCodes.Status400BadRequest)] - [SwaggerOperation(Summary = "Create new airport", Description = "Create new airport")] - public async Task Create([FromBody] CreateAirportCommand command, CancellationToken cancellationToken) + public IEndpointRouteBuilder MapEndpoint(IEndpointRouteBuilder endpoints) { - var result = await Mediator.Send(command, cancellationToken); + endpoints.MapPost($"{EndpointConfig.BaseApiPath}/flight/airport", CreateAirport) + .RequireAuthorization() + .WithTags("Flight") + .WithName("Create Airport") + .WithMetadata(new SwaggerOperationAttribute("Create Airport", "Create Airport")) + .WithApiVersionSet(endpoints.NewApiVersionSet("Flight").Build()) + .Produces() + .Produces(StatusCodes.Status201Created) + .Produces(StatusCodes.Status400BadRequest) + .HasApiVersion(1.0); - return Ok(result); + return endpoints; + } + + private async Task CreateAirport(CreateAirportCommand command, IMediator mediator, CancellationToken cancellationToken) + { + var result = await mediator.Send(command, cancellationToken); + + return Results.Ok(result); } } diff --git a/src/Services/Flight/src/Flight/Flights/Dtos/FlightResponseDto.cs b/src/Services/Flight/src/Flight/Flights/Dtos/FlightResponseDto.cs index f57bc79..a707d1d 100644 --- a/src/Services/Flight/src/Flight/Flights/Dtos/FlightResponseDto.cs +++ b/src/Services/Flight/src/Flight/Flights/Dtos/FlightResponseDto.cs @@ -14,6 +14,6 @@ public record FlightResponseDto public long ArriveAirportId { get; init; } public decimal DurationMinutes { get; init; } public DateTime FlightDate { get; init; } - public FlightStatus Status { get; init; } + public Enums.FlightStatus Status { get; init; } public decimal Price { get; init; } } diff --git a/src/Services/Flight/src/Flight/Flights/Features/CreateFlight/Endpoints/V1/CreateFlightEndpoint.cs b/src/Services/Flight/src/Flight/Flights/Features/CreateFlight/Endpoints/V1/CreateFlightEndpoint.cs index 2c2df68..0e64592 100644 --- a/src/Services/Flight/src/Flight/Flights/Features/CreateFlight/Endpoints/V1/CreateFlightEndpoint.cs +++ b/src/Services/Flight/src/Flight/Flights/Features/CreateFlight/Endpoints/V1/CreateFlightEndpoint.cs @@ -1,26 +1,38 @@ using System.Threading; using System.Threading.Tasks; using BuildingBlocks.Web; +using Flight.Flights.Dtos; using Flight.Flights.Features.CreateFlight.Commands.V1; -using Microsoft.AspNetCore.Authorization; +using MediatR; +using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Routing; using Swashbuckle.AspNetCore.Annotations; namespace Flight.Flights.Features.CreateFlight.Endpoints.V1; -[Route(BaseApiPath + "/flight")] -public class CreateFlightEndpoint : BaseController +public class CreateFlightEndpoint : IMinimalEndpoint { - [Authorize] - [HttpPost] - [ProducesResponseType(StatusCodes.Status201Created)] - [ProducesResponseType(StatusCodes.Status400BadRequest)] - [SwaggerOperation(Summary = "Create new flight", Description = "Create new flight")] - public async Task Create([FromBody] CreateFlightCommand command, CancellationToken cancellationToken) + public IEndpointRouteBuilder MapEndpoint(IEndpointRouteBuilder endpoints) { - var result = await Mediator.Send(command, cancellationToken); + endpoints.MapPost($"{EndpointConfig.BaseApiPath}/flight", CreateFlight) + .RequireAuthorization() + .WithTags("Flight") + .WithName("Create Flight") + .WithMetadata(new SwaggerOperationAttribute("Create Flight", "Create Flight")) + .WithApiVersionSet(endpoints.NewApiVersionSet("Flight").Build()) + .Produces() + .Produces(StatusCodes.Status201Created) + .Produces(StatusCodes.Status400BadRequest) + .HasApiVersion(1.0); - return Ok(result); + return endpoints; + } + + private async Task CreateFlight(CreateFlightCommand command, IMediator mediator, CancellationToken cancellationToken) + { + var result = await mediator.Send(command, cancellationToken); + + return Results.Ok(result); } } diff --git a/src/Services/Flight/src/Flight/Flights/Features/DeleteFlight/Endpoints/V1/DeleteFlightEndpoint.cs b/src/Services/Flight/src/Flight/Flights/Features/DeleteFlight/Endpoints/V1/DeleteFlightEndpoint.cs index d862eab..e92bdd4 100644 --- a/src/Services/Flight/src/Flight/Flights/Features/DeleteFlight/Endpoints/V1/DeleteFlightEndpoint.cs +++ b/src/Services/Flight/src/Flight/Flights/Features/DeleteFlight/Endpoints/V1/DeleteFlightEndpoint.cs @@ -1,27 +1,38 @@ using System.Threading; using System.Threading.Tasks; using BuildingBlocks.Web; +using Flight.Flights.Dtos; using Flight.Flights.Features.DeleteFlight.Commands.V1; -using Microsoft.AspNetCore.Authorization; +using MediatR; +using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Routing; using Swashbuckle.AspNetCore.Annotations; namespace Flight.Flights.Features.DeleteFlight.Endpoints.V1; -[Route(BaseApiPath + "/flight")] -public class DeleteFlightEndpoint : BaseController +public class DeleteFlightEndpoint : IMinimalEndpoint { - [Authorize] - [HttpDelete] - [ProducesResponseType(StatusCodes.Status201Created)] - [ProducesResponseType(StatusCodes.Status400BadRequest)] - [SwaggerOperation(Summary = "Delete flight", Description = "Delete flight")] - public async Task Update(DeleteFlightCommand command, CancellationToken cancellationToken) + public IEndpointRouteBuilder MapEndpoint(IEndpointRouteBuilder endpoints) { - var result = await Mediator.Send(command, cancellationToken); + endpoints.MapDelete($"{EndpointConfig.BaseApiPath}/flight/{{id}}", DeleteFlight) + .RequireAuthorization() + .WithTags("Flight") + .WithName("Delete Flight") + .WithMetadata(new SwaggerOperationAttribute("Delete Flight", "Delete Flight")) + .WithApiVersionSet(endpoints.NewApiVersionSet("Flight").Build()) + .Produces() + .Produces(StatusCodes.Status201Created) + .Produces(StatusCodes.Status400BadRequest) + .HasApiVersion(1.0); - return Ok(result); + return endpoints; + } + + private async Task DeleteFlight(long id, IMediator mediator, CancellationToken cancellationToken) + { + var result = await mediator.Send(new DeleteFlightCommand(id), cancellationToken); + + return Results.Ok(result); } } - diff --git a/src/Services/Flight/src/Flight/Flights/Features/GetAvailableFlights/Endpoints/V1/GetAvailableFlightsEndpoint.cs b/src/Services/Flight/src/Flight/Flights/Features/GetAvailableFlights/Endpoints/V1/GetAvailableFlightsEndpoint.cs index e0c7bd8..e4effb6 100644 --- a/src/Services/Flight/src/Flight/Flights/Features/GetAvailableFlights/Endpoints/V1/GetAvailableFlightsEndpoint.cs +++ b/src/Services/Flight/src/Flight/Flights/Features/GetAvailableFlights/Endpoints/V1/GetAvailableFlightsEndpoint.cs @@ -1,26 +1,37 @@ +using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; using BuildingBlocks.Web; +using Flight.Flights.Dtos; using Flight.Flights.Features.GetAvailableFlights.Queries.V1; -using Microsoft.AspNetCore.Authorization; +using MediatR; +using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Routing; using Swashbuckle.AspNetCore.Annotations; -namespace Flight.Flights.Features.GetAvailableFlights.Endpoints.V1; - -[Route(BaseApiPath + "/flight/get-available-flights")] -public class GetAvailableFlightsEndpoint : BaseController +public class GetAvailableFlightsEndpoint : IMinimalEndpoint { - [Authorize] - [HttpGet] - [ProducesResponseType(StatusCodes.Status200OK)] - [ProducesResponseType(StatusCodes.Status400BadRequest)] - [SwaggerOperation(Summary = "Get available flights", Description = "Get available flights")] - public async Task GetAvailableFlights([FromRoute] GetAvailableFlightsQuery query, CancellationToken cancellationToken) + public IEndpointRouteBuilder MapEndpoint(IEndpointRouteBuilder endpoints) { - var result = await Mediator.Send(query, cancellationToken); + endpoints.MapGet($"{EndpointConfig.BaseApiPath}/flight/get-available-flights", GetAvailableFlights) + .RequireAuthorization() + .WithTags("Flight") + .WithName("Get Available Flights") + .WithMetadata(new SwaggerOperationAttribute("Get Available Flights", "Get Available Flights")) + .WithApiVersionSet(endpoints.NewApiVersionSet("Flight").Build()) + .Produces>() + .Produces(StatusCodes.Status200OK) + .Produces(StatusCodes.Status400BadRequest) + .HasApiVersion(1.0); - return Ok(result); + return endpoints; + } + + private async Task GetAvailableFlights(IMediator mediator, CancellationToken cancellationToken) + { + var result = await mediator.Send(new GetAvailableFlightsQuery(), cancellationToken); + + return Results.Ok(result); } } diff --git a/src/Services/Flight/src/Flight/Flights/Features/GetFlightById/Endpoints/V1/GetFlightByIdEndpoint.cs b/src/Services/Flight/src/Flight/Flights/Features/GetFlightById/Endpoints/V1/GetFlightByIdEndpoint.cs index e089df1..7469739 100644 --- a/src/Services/Flight/src/Flight/Flights/Features/GetFlightById/Endpoints/V1/GetFlightByIdEndpoint.cs +++ b/src/Services/Flight/src/Flight/Flights/Features/GetFlightById/Endpoints/V1/GetFlightByIdEndpoint.cs @@ -1,25 +1,63 @@ +// using System.Threading; +// using System.Threading.Tasks; +// using BuildingBlocks.Web; +// using Flight.Flights.Features.GetFlightById.Queries.V1; +// using Microsoft.AspNetCore.Authorization; +// using Microsoft.AspNetCore.Http; +// using Microsoft.AspNetCore.Mvc; +// using Swashbuckle.AspNetCore.Annotations; +// +// namespace Flight.Flights.Features.GetFlightById.Endpoints.V1; +// +// [Route(BaseApiPath + "/flight")] +// public class GetFlightByIdEndpoint : BaseController +// { +// [Authorize] +// [HttpGet("{id}")] +// [ProducesResponseType(StatusCodes.Status200OK)] +// [ProducesResponseType(StatusCodes.Status400BadRequest)] +// [SwaggerOperation(Summary = "Get flight by id", Description = "Get flight by id")] +// public async Task GetById([FromRoute] GetFlightByIdQuery query, CancellationToken cancellationToken) +// { +// var result = await Mediator.Send(query, cancellationToken); +// return Ok(result); +// } +// } + +using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; using BuildingBlocks.Web; +using Flight.Flights.Dtos; using Flight.Flights.Features.GetFlightById.Queries.V1; -using Microsoft.AspNetCore.Authorization; +using MediatR; +using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Routing; using Swashbuckle.AspNetCore.Annotations; -namespace Flight.Flights.Features.GetFlightById.Endpoints.V1; - -[Route(BaseApiPath + "/flight")] -public class GetFlightByIdEndpoint : BaseController +public class GetFlightByIdEndpoint : IMinimalEndpoint { - [Authorize] - [HttpGet("{id}")] - [ProducesResponseType(StatusCodes.Status200OK)] - [ProducesResponseType(StatusCodes.Status400BadRequest)] - [SwaggerOperation(Summary = "Get flight by id", Description = "Get flight by id")] - public async Task GetById([FromRoute] GetFlightByIdQuery query, CancellationToken cancellationToken) + public IEndpointRouteBuilder MapEndpoint(IEndpointRouteBuilder endpoints) { - var result = await Mediator.Send(query, cancellationToken); - return Ok(result); + endpoints.MapGet($"{EndpointConfig.BaseApiPath}/flight/{{id}}", GetById) + .RequireAuthorization() + .WithTags("Flight") + .WithName("Get Flight By Id") + .WithMetadata(new SwaggerOperationAttribute("Get Flight By Id", "Get Flight By Id")) + .WithApiVersionSet(endpoints.NewApiVersionSet("Flight").Build()) + .Produces() + .Produces(StatusCodes.Status200OK) + .Produces(StatusCodes.Status400BadRequest) + .HasApiVersion(1.0); + + return endpoints; + } + + private async Task GetById(long id, IMediator mediator, CancellationToken cancellationToken) + { + var result = await mediator.Send(new GetFlightByIdQuery(id), cancellationToken); + + return Results.Ok(result); } } diff --git a/src/Services/Flight/src/Flight/Flights/Features/UpdateFlight/Endpoints/V1/UpdateFlightEndpoint.cs b/src/Services/Flight/src/Flight/Flights/Features/UpdateFlight/Endpoints/V1/UpdateFlightEndpoint.cs index a01603b..c90a3c7 100644 --- a/src/Services/Flight/src/Flight/Flights/Features/UpdateFlight/Endpoints/V1/UpdateFlightEndpoint.cs +++ b/src/Services/Flight/src/Flight/Flights/Features/UpdateFlight/Endpoints/V1/UpdateFlightEndpoint.cs @@ -1,26 +1,36 @@ using System.Threading; using System.Threading.Tasks; using BuildingBlocks.Web; +using Flight.Flights.Dtos; using Flight.Flights.Features.UpdateFlight.Commands.V1; -using Microsoft.AspNetCore.Authorization; +using MediatR; +using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Routing; using Swashbuckle.AspNetCore.Annotations; -namespace Flight.Flights.Features.UpdateFlight.Endpoints.V1; - -[Route(BaseApiPath + "/flight")] -public class UpdateFlightEndpoint : BaseController +public class UpdateFlightEndpoint : IMinimalEndpoint { - [Authorize] - [HttpPut] - [ProducesResponseType(StatusCodes.Status201Created)] - [ProducesResponseType(StatusCodes.Status400BadRequest)] - [SwaggerOperation(Summary = "Update flight", Description = "Update flight")] - public async Task Update(UpdateFlightCommand command, CancellationToken cancellationToken) + public IEndpointRouteBuilder MapEndpoint(IEndpointRouteBuilder endpoints) { - var result = await Mediator.Send(command, cancellationToken); + endpoints.MapPut($"{EndpointConfig.BaseApiPath}/flight", UpdateFlight) + .RequireAuthorization() + .WithTags("Flight") + .WithName("Update Flight") + .WithMetadata(new SwaggerOperationAttribute("Update Flight", "Update Flight")) + .WithApiVersionSet(endpoints.NewApiVersionSet("Flight").Build()) + .Produces() + .Produces(StatusCodes.Status201Created) + .Produces(StatusCodes.Status400BadRequest) + .HasApiVersion(1.0); - return Ok(result); + return endpoints; + } + + private async Task UpdateFlight(UpdateFlightCommand command, IMediator mediator, CancellationToken cancellationToken) + { + var result = await mediator.Send(command, cancellationToken); + + return Results.Ok(result); } } diff --git a/src/Services/Flight/src/Flight/Seats/Dtos/SeatResponseDto.cs b/src/Services/Flight/src/Flight/Seats/Dtos/SeatResponseDto.cs index 8b1603b..bdfb1e3 100644 --- a/src/Services/Flight/src/Flight/Seats/Dtos/SeatResponseDto.cs +++ b/src/Services/Flight/src/Flight/Seats/Dtos/SeatResponseDto.cs @@ -6,7 +6,7 @@ public record SeatResponseDto { public long Id { get; set; } public string SeatNumber { get; init; } - public SeatType Type { get; init; } - public SeatClass Class { get; init; } + public Enums.SeatType Type { get; init; } + public Enums.SeatClass Class { get; init; } public long FlightId { get; init; } } diff --git a/src/Services/Flight/src/Flight/Seats/Features/CreateSeat/Endpoints/V1/CreateSeatEndpoint.cs b/src/Services/Flight/src/Flight/Seats/Features/CreateSeat/Endpoints/V1/CreateSeatEndpoint.cs index 3cec678..2dec31a 100644 --- a/src/Services/Flight/src/Flight/Seats/Features/CreateSeat/Endpoints/V1/CreateSeatEndpoint.cs +++ b/src/Services/Flight/src/Flight/Seats/Features/CreateSeat/Endpoints/V1/CreateSeatEndpoint.cs @@ -1,24 +1,62 @@ +// using System.Threading; +// using System.Threading.Tasks; +// using BuildingBlocks.Web; +// using Flight.Seats.Features.CreateSeat.Commands.V1; +// using Microsoft.AspNetCore.Http; +// using Microsoft.AspNetCore.Mvc; +// using Swashbuckle.AspNetCore.Annotations; +// +// namespace Flight.Seats.Features.CreateSeat.Endpoints.V1; +// +// [Route(BaseApiPath + "/flight/seat")] +// public class CreateSeatEndpoint : BaseController +// { +// [HttpPost] +// [ProducesResponseType(StatusCodes.Status201Created)] +// [ProducesResponseType(StatusCodes.Status400BadRequest)] +// [SwaggerOperation(Summary = "Create new seat", Description = "Create new seat")] +// public async Task Create(CreateSeatCommand command, CancellationToken cancellationToken) +// { +// var result = await Mediator.Send(command, cancellationToken); +// +// return Ok(result); +// } +// } + + using System.Threading; using System.Threading.Tasks; using BuildingBlocks.Web; +using Flight.Seats.Dtos; using Flight.Seats.Features.CreateSeat.Commands.V1; +using MediatR; +using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Routing; using Swashbuckle.AspNetCore.Annotations; -namespace Flight.Seats.Features.CreateSeat.Endpoints.V1; - -[Route(BaseApiPath + "/flight/seat")] -public class CreateSeatEndpoint : BaseController +public class CreateSeatEndpoint : IMinimalEndpoint { - [HttpPost] - [ProducesResponseType(StatusCodes.Status201Created)] - [ProducesResponseType(StatusCodes.Status400BadRequest)] - [SwaggerOperation(Summary = "Create new seat", Description = "Create new seat")] - public async Task Create(CreateSeatCommand command, CancellationToken cancellationToken) + public IEndpointRouteBuilder MapEndpoint(IEndpointRouteBuilder endpoints) { - var result = await Mediator.Send(command, cancellationToken); + endpoints.MapPost($"{EndpointConfig.BaseApiPath}/flight/seat", CreateSeat) + .RequireAuthorization() + .WithTags("Flight") + .WithName("Create Seat") + .WithMetadata(new SwaggerOperationAttribute("Create Seat", "Create Seat")) + .WithApiVersionSet(endpoints.NewApiVersionSet("Flight").Build()) + .Produces() + .Produces(StatusCodes.Status201Created) + .Produces(StatusCodes.Status400BadRequest) + .HasApiVersion(1.0); - return Ok(result); + return endpoints; + } + + private async Task CreateSeat(CreateSeatCommand command, IMediator mediator, CancellationToken cancellationToken) + { + var result = await mediator.Send(command, cancellationToken); + + return Results.Ok(result); } } diff --git a/src/Services/Flight/src/Flight/Seats/Features/GetAvailableSeats/Endpoints/V1/GetAvailableSeatsEndpoint.cs b/src/Services/Flight/src/Flight/Seats/Features/GetAvailableSeats/Endpoints/V1/GetAvailableSeatsEndpoint.cs index c1fe0eb..170cb9f 100644 --- a/src/Services/Flight/src/Flight/Seats/Features/GetAvailableSeats/Endpoints/V1/GetAvailableSeatsEndpoint.cs +++ b/src/Services/Flight/src/Flight/Seats/Features/GetAvailableSeats/Endpoints/V1/GetAvailableSeatsEndpoint.cs @@ -1,27 +1,38 @@ +using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; using BuildingBlocks.Web; +using Flight.Flights.Dtos; +using Flight.Seats.Dtos; using Flight.Seats.Features.GetAvailableSeats.Queries.V1; -using Microsoft.AspNetCore.Authorization; +using MediatR; +using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Routing; using Swashbuckle.AspNetCore.Annotations; -namespace Flight.Seats.Features.GetAvailableSeats.Endpoints.V1; - -[Route(BaseApiPath + "/flight/get-available-seats")] -public class GetAvailableSeatsEndpoint : BaseController +public class GetAvailableSeatsEndpoint : IMinimalEndpoint { - [Authorize] - [HttpGet("{flightId}")] - [ProducesResponseType(StatusCodes.Status200OK)] - [ProducesResponseType(StatusCodes.Status400BadRequest)] - [SwaggerOperation(Summary = "Get available seats", Description = "Get available seats")] - public async Task GetAvailableSeats([FromRoute] GetAvailableSeatsQuery query, - CancellationToken cancellationToken) + public IEndpointRouteBuilder MapEndpoint(IEndpointRouteBuilder endpoints) { - var result = await Mediator.Send(query, cancellationToken); + endpoints.MapGet($"{EndpointConfig.BaseApiPath}/flight/get-available-seats/{{id}}", GetAvailableSeats) + .RequireAuthorization() + .WithTags("Flight") + .WithName("Get Available Seats") + .WithMetadata(new SwaggerOperationAttribute("Get Available Seats", "Get Available Seats")) + .WithApiVersionSet(endpoints.NewApiVersionSet("Flight").Build()) + .Produces>() + .Produces(StatusCodes.Status200OK) + .Produces(StatusCodes.Status400BadRequest) + .HasApiVersion(1.0); - return Ok(result); + return endpoints; + } + + private async Task GetAvailableSeats(long id, IMediator mediator, CancellationToken cancellationToken) + { + var result = await mediator.Send(new GetAvailableSeatsQuery(id), cancellationToken); + + return Results.Ok(result); } } diff --git a/src/Services/Flight/src/Flight/Seats/Features/ReserveSeat/Endpoints/V1/ReserveSeatEndpoint.cs b/src/Services/Flight/src/Flight/Seats/Features/ReserveSeat/Endpoints/V1/ReserveSeatEndpoint.cs index cf71023..a81d693 100644 --- a/src/Services/Flight/src/Flight/Seats/Features/ReserveSeat/Endpoints/V1/ReserveSeatEndpoint.cs +++ b/src/Services/Flight/src/Flight/Seats/Features/ReserveSeat/Endpoints/V1/ReserveSeatEndpoint.cs @@ -1,26 +1,36 @@ using System.Threading; using System.Threading.Tasks; using BuildingBlocks.Web; +using Flight.Seats.Dtos; using Flight.Seats.Features.ReserveSeat.Commands.V1; -using Microsoft.AspNetCore.Authorization; +using MediatR; +using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Routing; using Swashbuckle.AspNetCore.Annotations; -namespace Flight.Seats.Features.ReserveSeat.Endpoints.V1; - -[Route(BaseApiPath + "/flight/reserve-seat")] -public class ReserveSeatEndpoint : BaseController +public class ReserveSeatEndpoint : IMinimalEndpoint { - [Authorize] - [HttpPost] - [ProducesResponseType(StatusCodes.Status201Created)] - [ProducesResponseType(StatusCodes.Status400BadRequest)] - [SwaggerOperation(Summary = "Reserve seat", Description = "Reserve seat")] - public async Task ReserveSeat([FromBody] ReserveSeatCommand command, CancellationToken cancellationToken) + public IEndpointRouteBuilder MapEndpoint(IEndpointRouteBuilder endpoints) { - var result = await Mediator.Send(command, cancellationToken); + endpoints.MapPost($"{EndpointConfig.BaseApiPath}/flight/reserve-seat", ReserveSeat) + .RequireAuthorization() + .WithTags("Flight") + .WithName("Reserve Seat") + .WithMetadata(new SwaggerOperationAttribute("Reserve Seat", "Reserve Seat")) + .WithApiVersionSet(endpoints.NewApiVersionSet("Flight").Build()) + .Produces() + .Produces(StatusCodes.Status201Created) + .Produces(StatusCodes.Status400BadRequest) + .HasApiVersion(1.0); - return Ok(result); + return endpoints; + } + + private async Task ReserveSeat(ReserveSeatCommand command, IMediator mediator, CancellationToken cancellationToken) + { + var result = await mediator.Send(command, cancellationToken); + + return Results.Ok(result); } } diff --git a/src/Services/Identity/src/Identity.Api/Program.cs b/src/Services/Identity/src/Identity.Api/Program.cs index b7b5a7d..f8cbf97 100644 --- a/src/Services/Identity/src/Identity.Api/Program.cs +++ b/src/Services/Identity/src/Identity.Api/Program.cs @@ -30,8 +30,8 @@ builder.Services.AddPersistMessage(configuration); builder.Services.AddCustomDbContext(configuration); builder.Services.AddScoped(); builder.Services.AddCore(); -builder.AddCustomSerilog(env); builder.Services.AddControllers(); +builder.AddCustomSerilog(env); builder.Services.AddCustomSwagger(configuration, typeof(IdentityRoot).Assembly); builder.Services.AddCustomVersioning(); builder.Services.AddCustomMediatR(); @@ -47,12 +47,13 @@ SnowFlakIdGenerator.Configure(4); builder.Services.AddIdentityServer(env); +builder.AddMinimalEndpoints(); + var app = builder.Build(); if (app.Environment.IsDevelopment()) { - var provider = app.Services.GetService(); - app.UseCustomSwagger(provider); + app.UseCustomSwagger(); } app.UseSerilogRequestLogging(); @@ -67,6 +68,8 @@ app.UseAuthentication(); app.UseAuthorization(); app.UseIdentityServer(); +app.MapMinimalEndpoints(); + app.UseEndpoints(endpoints => { endpoints.MapControllers(); diff --git a/src/Services/Identity/src/Identity/Identity/Features/RegisterNewUser/Endpoints/V1/RegisterNewUserEndpoint.cs b/src/Services/Identity/src/Identity/Identity/Features/RegisterNewUser/Endpoints/V1/RegisterNewUserEndpoint.cs index f808f5f..419a4ca 100644 --- a/src/Services/Identity/src/Identity/Identity/Features/RegisterNewUser/Endpoints/V1/RegisterNewUserEndpoint.cs +++ b/src/Services/Identity/src/Identity/Identity/Features/RegisterNewUser/Endpoints/V1/RegisterNewUserEndpoint.cs @@ -1,34 +1,39 @@ using System.Threading; using System.Threading.Tasks; +using BuildingBlocks.Web; +using Identity.Identity.Dtos; using Identity.Identity.Features.RegisterNewUser.Commands.V1; using MediatR; +using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Routing; using Swashbuckle.AspNetCore.Annotations; namespace Identity.Identity.Features.RegisterNewUser.Endpoints.V1; -[Route("identity/register-user")] -[ApiController] -public class LoginEndpoint : ControllerBase +public class RegisterNewUserEndpoint : IMinimalEndpoint { - private readonly IMediator _mediator; - - public LoginEndpoint(IMediator mediator) + public IEndpointRouteBuilder MapEndpoint(IEndpointRouteBuilder endpoints) { - _mediator = mediator; + endpoints.MapPost($"{EndpointConfig.BaseApiPath}/identity/register-user", RegisterNewUser) + .RequireAuthorization() + .WithTags("Identity") + .WithName("Register User") + .WithMetadata(new SwaggerOperationAttribute("Register User", "Register User")) + .WithApiVersionSet(endpoints.NewApiVersionSet("Identity").Build()) + .Produces() + .Produces(StatusCodes.Status201Created) + .Produces(StatusCodes.Status400BadRequest) + .HasApiVersion(1.0); + + return endpoints; } - // [Authorize] - [HttpPost] - [ProducesResponseType(StatusCodes.Status201Created)] - [ProducesResponseType(StatusCodes.Status400BadRequest)] - [SwaggerOperation(Summary = "Register new user", Description = "Register new user")] - public async Task RegisterNewUser([FromBody] RegisterNewUserCommand command, - CancellationToken cancellationToken) + private async Task RegisterNewUser(RegisterNewUserCommand command, IMediator mediator, CancellationToken cancellationToken) { - var result = await _mediator.Send(command, cancellationToken); + var result = await mediator.Send(command, cancellationToken); - return Ok(result); + return Results.Ok(result); } } diff --git a/src/Services/Passenger/src/Passenger.Api/Program.cs b/src/Services/Passenger/src/Passenger.Api/Program.cs index 6f2d550..e4abcb5 100644 --- a/src/Services/Passenger/src/Passenger.Api/Program.cs +++ b/src/Services/Passenger/src/Passenger.Api/Program.cs @@ -36,7 +36,6 @@ builder.Services.AddPersistMessage(configuration); builder.AddCustomSerilog(env); builder.Services.AddCore(); builder.Services.AddJwt(); -builder.Services.AddControllers(); builder.Services.AddCustomSwagger(configuration, typeof(PassengerRoot).Assembly); builder.Services.AddCustomVersioning(); builder.Services.AddCustomMediatR(); @@ -54,12 +53,13 @@ builder.Services.AddGrpc(options => SnowFlakIdGenerator.Configure(2); +builder.AddMinimalEndpoints(); + var app = builder.Build(); if (app.Environment.IsDevelopment()) { - var provider = app.Services.GetService(); - app.UseCustomSwagger(provider); + app.UseCustomSwagger(); } app.UseSerilogRequestLogging(); @@ -73,9 +73,10 @@ app.UseAuthentication(); app.UseAuthorization(); app.UseCustomHealthCheck(); +app.MapMinimalEndpoints(); + app.UseEndpoints(endpoints => { - endpoints.MapControllers(); endpoints.MapMetrics(); endpoints.MapGrpcService(); }); diff --git a/src/Services/Passenger/src/Passenger/Passengers/Dtos/PassengerResponseDto.cs b/src/Services/Passenger/src/Passenger/Passengers/Dtos/PassengerResponseDto.cs index 4c3826c..df22ffc 100644 --- a/src/Services/Passenger/src/Passenger/Passengers/Dtos/PassengerResponseDto.cs +++ b/src/Services/Passenger/src/Passenger/Passengers/Dtos/PassengerResponseDto.cs @@ -1,5 +1,3 @@ -using Passenger.Passengers.Models; - namespace Passenger.Passengers.Dtos; public record PassengerResponseDto @@ -7,6 +5,6 @@ public record PassengerResponseDto public long Id { get; init; } public string Name { get; init; } public string PassportNumber { get; init; } - public PassengerType PassengerType { get; init; } + public Enums.PassengerType PassengerType { get; init; } public int Age { get; init; } } diff --git a/src/Services/Passenger/src/Passenger/Passengers/Features/CompleteRegisterPassenger/Endpoints/V1/CompleteRegisterPassengerEndpoint.cs b/src/Services/Passenger/src/Passenger/Passengers/Features/CompleteRegisterPassenger/Endpoints/V1/CompleteRegisterPassengerEndpoint.cs index 4b80150..8d314a2 100644 --- a/src/Services/Passenger/src/Passenger/Passengers/Features/CompleteRegisterPassenger/Endpoints/V1/CompleteRegisterPassengerEndpoint.cs +++ b/src/Services/Passenger/src/Passenger/Passengers/Features/CompleteRegisterPassenger/Endpoints/V1/CompleteRegisterPassengerEndpoint.cs @@ -1,25 +1,38 @@ using BuildingBlocks.Web; +using MediatR; using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Routing; +using Passenger.Passengers.Dtos; using Passenger.Passengers.Features.CompleteRegisterPassenger.Commands.V1; using Swashbuckle.AspNetCore.Annotations; namespace Passenger.Passengers.Features.CompleteRegisterPassenger.Endpoints.V1; -[Route(BaseApiPath + "/passenger/complete-registration")] -public class CompleteRegisterPassengerEndpoint : BaseController +public class CompleteRegisterPassengerEndpoint : IMinimalEndpoint { - [Authorize] - [HttpPost] - [ProducesResponseType(StatusCodes.Status201Created)] - [ProducesResponseType(StatusCodes.Status400BadRequest)] - [SwaggerOperation(Summary = "Complete Register Passenger", Description = "Complete Register Passenger")] - public async Task CompleteRegisterPassenger([FromBody] CompleteRegisterPassengerCommand command, - CancellationToken cancellationToken) + public IEndpointRouteBuilder MapEndpoint(IEndpointRouteBuilder endpoints) { - var result = await Mediator.Send(command, cancellationToken); + endpoints.MapPost($"{EndpointConfig.BaseApiPath}/passenger/complete-registration", CompleteRegisterPassenger) + .RequireAuthorization() + .WithTags("Passenger") + .WithName("Complete Register Passenger") + .WithMetadata(new SwaggerOperationAttribute("Complete Register Passenger", "Complete Register Passenger")) + .WithApiVersionSet(endpoints.NewApiVersionSet("Passenger").Build()) + .Produces() + .Produces(StatusCodes.Status201Created) + .Produces(StatusCodes.Status400BadRequest) + .HasApiVersion(1.0); - return Ok(result); + return endpoints; + } + + private async Task CompleteRegisterPassenger(CompleteRegisterPassengerCommand command, IMediator mediator, CancellationToken cancellationToken) + { + var result = await mediator.Send(command, cancellationToken); + + return Results.Ok(result); } } diff --git a/src/Services/Passenger/src/Passenger/Passengers/Features/GetPassengerById/Endpoints/V1/GetPassengerByIdEndpoint.cs b/src/Services/Passenger/src/Passenger/Passengers/Features/GetPassengerById/Endpoints/V1/GetPassengerByIdEndpoint.cs index 60caaf1..208269f 100644 --- a/src/Services/Passenger/src/Passenger/Passengers/Features/GetPassengerById/Endpoints/V1/GetPassengerByIdEndpoint.cs +++ b/src/Services/Passenger/src/Passenger/Passengers/Features/GetPassengerById/Endpoints/V1/GetPassengerByIdEndpoint.cs @@ -1,24 +1,37 @@ using BuildingBlocks.Web; +using MediatR; using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Routing; +using Passenger.Passengers.Dtos; using Passenger.Passengers.Features.GetPassengerById.Queries.V1; using Swashbuckle.AspNetCore.Annotations; namespace Passenger.Passengers.Features.GetPassengerById.Endpoints.V1; - -[Route(BaseApiPath + "/passenger")] -public class GetPassengerByIdEndpoint : BaseController +public class GetPassengerByIdEndpoint : IMinimalEndpoint { - [HttpGet("{id}")] - [Authorize] - [ProducesResponseType(StatusCodes.Status200OK)] - [ProducesResponseType(StatusCodes.Status400BadRequest)] - [SwaggerOperation(Summary = "Get passenger by id", Description = "Get passenger by id")] - public async Task GetById([FromRoute] GetPassengerQueryById query, CancellationToken cancellationToken) + public IEndpointRouteBuilder MapEndpoint(IEndpointRouteBuilder endpoints) { - var result = await Mediator.Send(query, cancellationToken); + endpoints.MapGet($"{EndpointConfig.BaseApiPath}/passenger/{{id}}", GetById) + .RequireAuthorization() + .WithTags("Passenger") + .WithName("Get Passenger By Id") + .WithMetadata(new SwaggerOperationAttribute("Get Passenger By Id", "Get Passenger By Id")) + .WithApiVersionSet(endpoints.NewApiVersionSet("Passenger").Build()) + .Produces() + .Produces(StatusCodes.Status200OK) + .Produces(StatusCodes.Status400BadRequest) + .HasApiVersion(1.0); - return Ok(result); + return endpoints; + } + + private async Task GetById(long id, IMediator mediator, CancellationToken cancellationToken) + { + var result = await mediator.Send(new GetPassengerQueryById(id), cancellationToken); + + return Results.Ok(result); } }