update apis to minimal-api

This commit is contained in:
meysamhadeli 2022-11-16 00:39:05 +03:30
parent 29d9daf544
commit 27a0b74a9f
30 changed files with 652 additions and 322 deletions

View File

@ -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"
}

View File

@ -8,6 +8,10 @@
<ItemGroup>
<PackageReference Include="Ardalis.GuardClauses" Version="4.0.1" />
<PackageReference Include="Asp.Versioning.Abstractions" Version="7.0.0-preview.1" />
<PackageReference Include="Asp.Versioning.Http" Version="7.0.0-preview.1" />
<PackageReference Include="Asp.Versioning.Mvc" Version="7.0.0-preview.1" />
<PackageReference Include="Asp.Versioning.Mvc.ApiExplorer" Version="7.0.0-preview.1" />
<PackageReference Include="AspNetCore.HealthChecks.Elasticsearch" Version="6.0.2" />
<PackageReference Include="AspNetCore.HealthChecks.EventStore" Version="6.0.3" />
<PackageReference Include="AspNetCore.HealthChecks.Rabbitmq" Version="6.0.2" />
@ -22,6 +26,7 @@
<PackageReference Include="FluentValidation" Version="11.3.0" />
<PackageReference Include="FluentValidation.AspNetCore" Version="11.2.2" />
<PackageReference Include="Grpc.Core.Testing" Version="2.46.5" />
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="7.0.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="7.0.0" />
<PackageReference Include="Microsoft.Extensions.DependencyModel" Version="7.0.0" />
<PackageReference Include="Mongo2Go" Version="3.1.3" />
@ -41,7 +46,6 @@
<PackageReference Include="MediatR.Extensions.Microsoft.DependencyInjection" Version="11.0.0" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="7.0.0" />
<PackageReference Include="Microsoft.AspNetCore.Http" Version="2.2.2" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.Versioning.ApiExplorer" Version="5.0.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="7.0.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore.InMemory" Version="7.0.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="7.0.0" />
@ -67,10 +71,10 @@
<PackageReference Include="Serilog.Sinks.Seq" Version="5.2.1" />
<PackageReference Include="Serilog.Sinks.SpectreConsole" Version="0.3.3" />
<PackageReference Include="Serilog.Sinks.XUnit" Version="3.0.3" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.4.0" />
<PackageReference Include="Swashbuckle.AspNetCore.Annotations" Version="6.4.0" />
<PackageReference Include="Swashbuckle.AspNetCore.SwaggerGen" Version="6.4.0" />
<PackageReference Include="Swashbuckle.AspNetCore.SwaggerUI" Version="6.4.0" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.4.0" />
<PackageReference Include="AspNetCore.HealthChecks.UI" Version="6.0.5" />
<PackageReference Include="AspNetCore.HealthChecks.UI.Client" Version="6.0.5" />
<PackageReference Include="AspNetCore.HealthChecks.UI.InMemory.Storage" Version="6.0.5" />

View File

@ -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<SwaggerGenOptions>
{
public class ConfigureSwaggerOptions : IConfigureOptions<SwaggerGenOptions>
private readonly IApiVersionDescriptionProvider provider;
private readonly SwaggerOptions? _options;
/// <summary>
/// Initializes a new instance of the <see cref="ConfigureSwaggerOptions"/> class.
/// </summary>
/// <param name="provider">The <see cref="IApiVersionDescriptionProvider">provider</see> used to generate Swagger documents.</param>
public ConfigureSwaggerOptions(IApiVersionDescriptionProvider provider, IOptions<SwaggerOptions> options)
{
private readonly IApiVersionDescriptionProvider _provider;
private readonly SwaggerOptions _options;
this.provider = provider;
_options = options.Value;
}
public ConfigureSwaggerOptions(IApiVersionDescriptionProvider provider, IOptions<SwaggerOptions> options)
/// <inheritdoc />
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));
}
}
}
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;
}
}

View File

@ -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<SwaggerOptions>().Bind(configuration.GetSection(swaggerSectionName))
.ValidateDataAnnotations();
// https://learn.microsoft.com/en-us/aspnet/core/fundamentals/minimal-apis/openapi
services.AddEndpointsApiExplorer();
services.AddTransient<IConfigureOptions<SwaggerGenOptions>, ConfigureSwaggerOptions>();
services.AddOptions<SwaggerOptions>().Bind(configuration.GetSection(nameof(SwaggerOptions)))
.ValidateDataAnnotations();
services.AddSwaggerGen(
options =>
{
// options.DescribeAllParametersInCamelCase();
options.OperationFilter<SwaggerDefaultValues>();
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<string>()
}
});
//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<TagByApiExplorerSettingsOperationFilter>();
// options.OperationFilter<TagBySwaggerOperationFilter>();
// Enables Swagger annotations (SwaggerOperationAttribute, SwaggerParameterAttribute etc.)
options.EnableAnnotations();
});
return services;
services.Configure<SwaggerGeneratorOptions>(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;

View File

@ -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<ApiVersioningOptions> configurator = null)
public static void AddCustomVersioning(
this IServiceCollection services,
Action<ApiVersioningOptions>? 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
}
}

View File

@ -1,4 +1,5 @@
using AutoMapper;
using Asp.Versioning;
using AutoMapper;
using MediatR;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.DependencyInjection;

View File

@ -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!;
}

View File

@ -0,0 +1,8 @@
using Microsoft.AspNetCore.Routing;
namespace BuildingBlocks.Web;
public interface IMinimalEndpoint
{
IEndpointRouteBuilder MapEndpoint(IEndpointRouteBuilder builder);
}

View File

@ -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<IMinimalEndpoint>()
.WithLifetime(lifetime));
return applicationBuilder.Services;
}
/// <summary>
/// Map Minimal Endpoints
/// </summary>
/// <name>builder.</name>
/// <returns>IEndpointRouteBuilder.</returns>
public static IEndpointRouteBuilder MapMinimalEndpoints(this IEndpointRouteBuilder builder)
{
var scope = builder.ServiceProvider.CreateScope();
var endpoints = scope.ServiceProvider.GetServices<IMinimalEndpoint>();
foreach (var endpoint in endpoints)
{
endpoint.MapEndpoint(builder);
}
return builder;
}
}

View File

@ -34,7 +34,6 @@ builder.Services.AddMongoDbContext<BookingReadDbContext>(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<IApiVersionDescriptionProvider>();
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();
});

View File

@ -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<ActionResult> 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<ulong>()
.Produces(StatusCodes.Status201Created)
.Produces(StatusCodes.Status400BadRequest)
.HasApiVersion(1.0);
return Ok(result);
return endpoints;
}
private async Task<IResult> CreateBooking(CreateBookingCommand command, IMediator mediator, CancellationToken cancellationToken)
{
var result = await mediator.Send(command, cancellationToken);
return Results.Ok(result);
}
}

View File

@ -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<Assembly> {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<IApiVersionDescriptionProvider>();
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<FlightGrpcServices>();
});

View File

@ -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<ActionResult> 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<AircraftResponseDto>()
.Produces(StatusCodes.Status201Created)
.Produces(StatusCodes.Status400BadRequest)
.HasApiVersion(1.0);
return Ok(result);
return endpoints;
}
private async Task<IResult> CreateAircraft(CreateAircraftCommand command, IMediator mediator, CancellationToken cancellationToken)
{
var result = await mediator.Send(command, cancellationToken);
return Results.Ok(result);
}
}

View File

@ -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<ActionResult> 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<AirportResponseDto>()
.Produces(StatusCodes.Status201Created)
.Produces(StatusCodes.Status400BadRequest)
.HasApiVersion(1.0);
return Ok(result);
return endpoints;
}
private async Task<IResult> CreateAirport(CreateAirportCommand command, IMediator mediator, CancellationToken cancellationToken)
{
var result = await mediator.Send(command, cancellationToken);
return Results.Ok(result);
}
}

View File

@ -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; }
}

View File

@ -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<ActionResult> 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<FlightResponseDto>()
.Produces(StatusCodes.Status201Created)
.Produces(StatusCodes.Status400BadRequest)
.HasApiVersion(1.0);
return Ok(result);
return endpoints;
}
private async Task<IResult> CreateFlight(CreateFlightCommand command, IMediator mediator, CancellationToken cancellationToken)
{
var result = await mediator.Send(command, cancellationToken);
return Results.Ok(result);
}
}

View File

@ -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<ActionResult> 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<FlightResponseDto>()
.Produces(StatusCodes.Status201Created)
.Produces(StatusCodes.Status400BadRequest)
.HasApiVersion(1.0);
return Ok(result);
return endpoints;
}
private async Task<IResult> DeleteFlight(long id, IMediator mediator, CancellationToken cancellationToken)
{
var result = await mediator.Send(new DeleteFlightCommand(id), cancellationToken);
return Results.Ok(result);
}
}

View File

@ -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<ActionResult> 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<IEnumerable<FlightResponseDto>>()
.Produces(StatusCodes.Status200OK)
.Produces(StatusCodes.Status400BadRequest)
.HasApiVersion(1.0);
return Ok(result);
return endpoints;
}
private async Task<IResult> GetAvailableFlights(IMediator mediator, CancellationToken cancellationToken)
{
var result = await mediator.Send(new GetAvailableFlightsQuery(), cancellationToken);
return Results.Ok(result);
}
}

View File

@ -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<ActionResult> 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<ActionResult> 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<FlightResponseDto>()
.Produces(StatusCodes.Status200OK)
.Produces(StatusCodes.Status400BadRequest)
.HasApiVersion(1.0);
return endpoints;
}
private async Task<IResult> GetById(long id, IMediator mediator, CancellationToken cancellationToken)
{
var result = await mediator.Send(new GetFlightByIdQuery(id), cancellationToken);
return Results.Ok(result);
}
}

View File

@ -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<ActionResult> 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<FlightResponseDto>()
.Produces(StatusCodes.Status201Created)
.Produces(StatusCodes.Status400BadRequest)
.HasApiVersion(1.0);
return Ok(result);
return endpoints;
}
private async Task<IResult> UpdateFlight(UpdateFlightCommand command, IMediator mediator, CancellationToken cancellationToken)
{
var result = await mediator.Send(command, cancellationToken);
return Results.Ok(result);
}
}

View File

@ -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; }
}

View File

@ -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<ActionResult> 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<ActionResult> 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<SeatResponseDto>()
.Produces(StatusCodes.Status201Created)
.Produces(StatusCodes.Status400BadRequest)
.HasApiVersion(1.0);
return Ok(result);
return endpoints;
}
private async Task<IResult> CreateSeat(CreateSeatCommand command, IMediator mediator, CancellationToken cancellationToken)
{
var result = await mediator.Send(command, cancellationToken);
return Results.Ok(result);
}
}

View File

@ -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<ActionResult> 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<IEnumerable<SeatResponseDto>>()
.Produces(StatusCodes.Status200OK)
.Produces(StatusCodes.Status400BadRequest)
.HasApiVersion(1.0);
return Ok(result);
return endpoints;
}
private async Task<IResult> GetAvailableSeats(long id, IMediator mediator, CancellationToken cancellationToken)
{
var result = await mediator.Send(new GetAvailableSeatsQuery(id), cancellationToken);
return Results.Ok(result);
}
}

View File

@ -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<ActionResult> 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<SeatResponseDto>()
.Produces(StatusCodes.Status201Created)
.Produces(StatusCodes.Status400BadRequest)
.HasApiVersion(1.0);
return Ok(result);
return endpoints;
}
private async Task<IResult> ReserveSeat(ReserveSeatCommand command, IMediator mediator, CancellationToken cancellationToken)
{
var result = await mediator.Send(command, cancellationToken);
return Results.Ok(result);
}
}

View File

@ -30,8 +30,8 @@ builder.Services.AddPersistMessage(configuration);
builder.Services.AddCustomDbContext<IdentityContext>(configuration);
builder.Services.AddScoped<IDataSeeder, IdentityDataSeeder>();
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<IApiVersionDescriptionProvider>();
app.UseCustomSwagger(provider);
app.UseCustomSwagger();
}
app.UseSerilogRequestLogging();
@ -67,6 +68,8 @@ app.UseAuthentication();
app.UseAuthorization();
app.UseIdentityServer();
app.MapMinimalEndpoints();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();

View File

@ -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<RegisterNewUserResponseDto>()
.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<ActionResult> RegisterNewUser([FromBody] RegisterNewUserCommand command,
CancellationToken cancellationToken)
private async Task<IResult> 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);
}
}

View File

@ -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<IApiVersionDescriptionProvider>();
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<PassengerGrpcServices>();
});

View File

@ -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; }
}

View File

@ -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<ActionResult> 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<PassengerResponseDto>()
.Produces(StatusCodes.Status201Created)
.Produces(StatusCodes.Status400BadRequest)
.HasApiVersion(1.0);
return Ok(result);
return endpoints;
}
private async Task<IResult> CompleteRegisterPassenger(CompleteRegisterPassengerCommand command, IMediator mediator, CancellationToken cancellationToken)
{
var result = await mediator.Send(command, cancellationToken);
return Results.Ok(result);
}
}

View File

@ -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<ActionResult> 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<PassengerResponseDto>()
.Produces(StatusCodes.Status200OK)
.Produces(StatusCodes.Status400BadRequest)
.HasApiVersion(1.0);
return Ok(result);
return endpoints;
}
private async Task<IResult> GetById(long id, IMediator mediator, CancellationToken cancellationToken)
{
var result = await mediator.Send(new GetPassengerQueryById(id), cancellationToken);
return Results.Ok(result);
}
}