feat: Use built-in problem-details .Net 7 instead of Hellang.Middleware.ProblemDetails

This commit is contained in:
Pc 2023-03-30 23:04:24 +03:30
parent 021e218671
commit 7c3e650467
23 changed files with 398 additions and 611 deletions

View File

@ -44,7 +44,6 @@
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Hellang.Middleware.ProblemDetails" Version="6.5.1" />
<PackageReference Include="Humanizer.Core" Version="2.14.1" />
<PackageReference Include="IdGen" Version="3.0.3" />
<PackageReference Include="Mapster" Version="7.3.0" />

View File

@ -1,7 +1,6 @@
namespace Booking.Booking.Features.CreatingBook.Commands.V1;
using BuildingBlocks.Web;
using Hellang.Middleware.ProblemDetails;
using MapsterMapper;
using MediatR;
using Microsoft.AspNetCore.Builder;
@ -18,25 +17,10 @@ public class CreateBookingEndpoint : IMinimalEndpoint
{
builder.MapPost($"{EndpointConfig.BaseApiPath}/booking", CreateBooking)
.RequireAuthorization()
.WithTags("Booking")
.WithName("CreateBooking")
.WithMetadata(new SwaggerOperationAttribute("Create Booking", "Create Booking"))
.WithApiVersionSet(builder.NewApiVersionSet("Booking").Build())
.WithMetadata(
new SwaggerResponseAttribute(
StatusCodes.Status200OK,
"Booking Created",
typeof(CreateBookingResponseDto)))
.WithMetadata(
new SwaggerResponseAttribute(
StatusCodes.Status400BadRequest,
"BadRequest",
typeof(StatusCodeProblemDetails)))
.WithMetadata(
new SwaggerResponseAttribute(
StatusCodes.Status401Unauthorized,
"UnAuthorized",
typeof(StatusCodeProblemDetails)))
.Produces<CreateBookingResponseDto>()
.ProducesProblem(StatusCodes.Status400BadRequest)
.HasApiVersion(1.0);
return builder;

View File

@ -3,7 +3,6 @@ using Booking.Data;
using BuildingBlocks.Core;
using BuildingBlocks.EventStoreDB;
using BuildingBlocks.HealthCheck;
using BuildingBlocks.IdsGenerator;
using BuildingBlocks.Jwt;
using BuildingBlocks.Logging;
using BuildingBlocks.Mapster;
@ -15,7 +14,6 @@ using BuildingBlocks.Swagger;
using BuildingBlocks.Web;
using Figgle;
using FluentValidation;
using Hellang.Middleware.ProblemDetails;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
@ -72,7 +70,7 @@ public static class InfrastructureExtensions
builder.Services.AddCustomVersioning();
builder.Services.AddCustomMediatR();
builder.Services.AddValidatorsFromAssembly(typeof(BookingRoot).Assembly);
builder.Services.AddCustomProblemDetails();
builder.Services.AddProblemDetails();
builder.Services.AddCustomMapster(typeof(BookingRoot).Assembly);
builder.Services.AddCustomHealthCheck();
builder.Services.AddCustomMassTransit(env, typeof(BookingRoot).Assembly);
@ -94,7 +92,7 @@ public static class InfrastructureExtensions
var env = app.Environment;
var appOptions = app.GetOptions<AppOptions>(nameof(AppOptions));
app.UseProblemDetails();
app.UseCustomProblemDetails();
app.UseSerilogRequestLogging(options =>
{
options.EnrichDiagnosticContext = LogEnrichHelper.EnrichFromRequest;

View File

@ -1,107 +1,106 @@
using BuildingBlocks.Exception;
using Grpc.Core;
using Hellang.Middleware.ProblemDetails;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
namespace Booking.Extensions.Infrastructure;
using BuildingBlocks.Exception;
using Grpc.Core;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Diagnostics;
using Microsoft.AspNetCore.Http;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
public static class ProblemDetailsExtensions
{
public static IServiceCollection AddCustomProblemDetails(this IServiceCollection services)
public static WebApplication UseCustomProblemDetails(this WebApplication app)
{
services.AddProblemDetails(x =>
app.UseExceptionHandler(exceptionHandlerApp =>
{
// Control when an exception is included
x.IncludeExceptionDetails = (ctx, _) =>
exceptionHandlerApp.Run(async context =>
{
// Fetch services from HttpContext.RequestServices
var env = ctx.RequestServices.GetRequiredService<IHostEnvironment>();
return env.IsDevelopment() || env.IsStaging();
};
x.Map<ConflictException>(ex => new ProblemDetailsWithCode
{
Title = ex.GetType().Name,
Status = StatusCodes.Status409Conflict,
Detail = ex.Message,
Type = "https://somedomain/application-rule-validation-error",
});
context.Response.ContentType = "application/problem+json";
// Exception will produce and returns from our FluentValidation RequestValidationBehavior
x.Map<ValidationException>(ex => new ProblemDetailsWithCode
{
Title = ex.GetType().Name,
Status = (int)ex.StatusCode,
Detail = ex.Message,
Type = "https://somedomain/input-validation-rules-error",
});
x.Map<BadRequestException>(ex => new ProblemDetailsWithCode
{
Title = ex.GetType().Name,
Status = StatusCodes.Status400BadRequest,
Detail = ex.Message,
Type = "https://somedomain/bad-request-error",
});
x.Map<NotFoundException>(ex => new ProblemDetailsWithCode
{
Title = ex.GetType().Name,
Status = StatusCodes.Status404NotFound,
Detail = ex.Message,
Type = "https://somedomain/not-found-error",
});
x.Map<InternalServerException>(ex => new ProblemDetailsWithCode
{
Title = ex.GetType().Name,
Status = StatusCodes.Status500InternalServerError,
Detail = ex.Message,
Type = "https://somedomain/api-server-error",
});
x.Map<AppException>(ex => new ProblemDetailsWithCode
{
Title = ex.GetType().Name,
Status = StatusCodes.Status400BadRequest,
Detail = ex.Message,
Type = "https://somedomain/application-error",
});
x.Map<RpcException>(ex => new ProblemDetails
{
Status = StatusCodes.Status400BadRequest,
Title = ex.GetType().Name,
Detail = ex.Status.Detail,
Type = "https://somedomain/grpc-error"
});
x.Map<DbUpdateConcurrencyException>(ex => new ProblemDetailsWithCode
{
Title = ex.GetType().Name,
Status = StatusCodes.Status409Conflict,
Detail = ex.Message,
Type = "https://somedomain/db-update-concurrency-error"
});
x.MapToStatusCode<ArgumentNullException>(StatusCodes.Status400BadRequest);
x.MapStatusCode = context =>
{
return context.Response.StatusCode switch
if (context.RequestServices.GetService<IProblemDetailsService>() is { } problemDetailsService)
{
StatusCodes.Status401Unauthorized => new ProblemDetailsWithCode
{
Status = context.Response.StatusCode,
Title = "identity exception",
Detail = "You are not Authorized",
Type = "https://somedomain/identity-error",
},
var exceptionHandlerFeature = context.Features.Get<IExceptionHandlerFeature>();
var exceptionType = exceptionHandlerFeature?.Error;
_ => new StatusCodeProblemDetails(context.Response.StatusCode)
};
};
if (exceptionType is not null)
{
(string Detail, string Type, string Title, int StatusCode) details = exceptionType switch
{
ConflictException =>
(
exceptionType.Message,
exceptionType.GetType().ToString(),
exceptionType.GetType().Name,
context.Response.StatusCode = StatusCodes.Status409Conflict
),
ValidationException validationException =>
(
exceptionType.Message,
exceptionType.GetType().ToString(),
exceptionType.GetType().Name,
context.Response.StatusCode = (int)validationException.StatusCode
),
BadRequestException =>
(
exceptionType.Message,
exceptionType.GetType().ToString(),
exceptionType.GetType().Name,
context.Response.StatusCode = StatusCodes.Status400BadRequest
),
NotFoundException =>
(
exceptionType.Message,
exceptionType.GetType().ToString(),
exceptionType.GetType().Name,
context.Response.StatusCode = StatusCodes.Status404NotFound
),
AppException =>
(
exceptionType.Message,
exceptionType.GetType().ToString(),
exceptionType.GetType().Name,
context.Response.StatusCode = StatusCodes.Status400BadRequest
),
DbUpdateConcurrencyException =>
(
exceptionType.Message,
exceptionType.GetType().ToString(),
exceptionType.GetType().Name,
context.Response.StatusCode = StatusCodes.Status409Conflict
),
RpcException =>
(
exceptionType.Message,
exceptionType.GetType().ToString(),
exceptionType.GetType().Name,
context.Response.StatusCode = StatusCodes.Status400BadRequest
),
_ =>
(
exceptionType.Message,
exceptionType.GetType().ToString(),
exceptionType.GetType().Name,
context.Response.StatusCode = StatusCodes.Status500InternalServerError
)
};
await problemDetailsService.WriteAsync(new ProblemDetailsContext
{
HttpContext = context,
ProblemDetails =
{
Title = details.Title,
Detail = details.Detail,
Type = details.Type,
Status = details.StatusCode
}
});
}
}
});
});
return services;
return app;
}
}

View File

@ -3,8 +3,6 @@ namespace Flight.Aircrafts.Features.CreatingAircraft.V1;
using System.Threading;
using System.Threading.Tasks;
using BuildingBlocks.Web;
using Dtos;
using Hellang.Middleware.ProblemDetails;
using MapsterMapper;
using MediatR;
using Microsoft.AspNetCore.Builder;
@ -21,25 +19,10 @@ public class CreateAircraftEndpoint : IMinimalEndpoint
{
builder.MapPost($"{EndpointConfig.BaseApiPath}/flight/aircraft", CreateAircraft)
.RequireAuthorization()
.WithTags("Flight")
.WithName("CreateAircraft")
.WithMetadata(new SwaggerOperationAttribute("Create Aircraft", "Create Aircraft"))
.WithApiVersionSet(builder.NewApiVersionSet("Flight").Build())
.WithMetadata(
new SwaggerResponseAttribute(
StatusCodes.Status200OK,
"Aircraft Created",
typeof(CreateAircraftResponseDto)))
.WithMetadata(
new SwaggerResponseAttribute(
StatusCodes.Status400BadRequest,
"BadRequest",
typeof(StatusCodeProblemDetails)))
.WithMetadata(
new SwaggerResponseAttribute(
StatusCodes.Status401Unauthorized,
"UnAuthorized",
typeof(StatusCodeProblemDetails)))
.Produces<CreateAircraftResponseDto>()
.ProducesProblem(StatusCodes.Status400BadRequest)
.HasApiVersion(1.0);
return builder;

View File

@ -3,8 +3,6 @@ namespace Flight.Airports.Features.CreatingAirport.V1;
using System.Threading;
using System.Threading.Tasks;
using BuildingBlocks.Web;
using Dtos;
using Hellang.Middleware.ProblemDetails;
using MapsterMapper;
using MediatR;
using Microsoft.AspNetCore.Builder;
@ -21,25 +19,10 @@ public class CreateAirportEndpoint : IMinimalEndpoint
{
builder.MapPost($"{EndpointConfig.BaseApiPath}/flight/airport", CreateAirport)
.RequireAuthorization()
.WithTags("Flight")
.WithName("CreateAirport")
.WithMetadata(new SwaggerOperationAttribute("Create Airport", "Create Airport"))
.WithApiVersionSet(builder.NewApiVersionSet("Flight").Build())
.WithMetadata(
new SwaggerResponseAttribute(
StatusCodes.Status200OK,
"Airport Created",
typeof(CreateAirportResponseDto)))
.WithMetadata(
new SwaggerResponseAttribute(
StatusCodes.Status400BadRequest,
"BadRequest",
typeof(StatusCodeProblemDetails)))
.WithMetadata(
new SwaggerResponseAttribute(
StatusCodes.Status401Unauthorized,
"UnAuthorized",
typeof(StatusCodeProblemDetails)))
.Produces<CreateAirportResponseDto>()
.ProducesProblem(StatusCodes.Status400BadRequest)
.HasApiVersion(1.0);
return builder;

View File

@ -19,7 +19,6 @@ using Flight.Data;
using Flight.Data.Seed;
using Flight.GrpcServer.Services;
using FluentValidation;
using Hellang.Middleware.ProblemDetails;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
@ -51,7 +50,7 @@ public static class InfrastructureExtensions
});
builder.Services.AddCustomMediatR();
builder.Services.AddCustomProblemDetails();
builder.Services.AddProblemDetails();
var appOptions = builder.Services.GetOptions<AppOptions>(nameof(AppOptions));
Console.WriteLine(FiggleFonts.Standard.Render(appOptions.Name));
@ -99,7 +98,7 @@ public static class InfrastructureExtensions
var env = app.Environment;
var appOptions = app.GetOptions<AppOptions>(nameof(AppOptions));
app.UseProblemDetails();
app.UseCustomProblemDetails();
app.UseSerilogRequestLogging(options =>
{
options.EnrichDiagnosticContext = LogEnrichHelper.EnrichFromRequest;

View File

@ -1,98 +1,107 @@
using System;
using BuildingBlocks.Exception;
using Hellang.Middleware.ProblemDetails;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
namespace Flight.Extensions.Infrastructure;
using Grpc.Core;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Diagnostics;
using Microsoft.EntityFrameworkCore;
public static class ProblemDetailsExtensions
{
public static IServiceCollection AddCustomProblemDetails(this IServiceCollection services)
public static WebApplication UseCustomProblemDetails(this WebApplication app)
{
services.AddProblemDetails(x =>
app.UseExceptionHandler(exceptionHandlerApp =>
{
// Control when an exception is included
x.IncludeExceptionDetails = (ctx, _) =>
exceptionHandlerApp.Run(async context =>
{
// Fetch services from HttpContext.RequestServices
var env = ctx.RequestServices.GetRequiredService<IHostEnvironment>();
return env.IsDevelopment() || env.IsStaging();
};
x.Map<ConflictException>(ex => new ProblemDetailsWithCode
{
Title = ex.GetType().Name,
Status = StatusCodes.Status409Conflict,
Detail = ex.Message,
Type = "https://somedomain/application-rule-validation-error"
});
context.Response.ContentType = "application/problem+json";
// Exception will produce and returns from our FluentValidation RequestValidationBehavior
x.Map<ValidationException>(ex => new ProblemDetailsWithCode
{
Title = ex.GetType().Name,
Status = (int)ex.StatusCode,
Detail = ex.Message,
Type = "https://somedomain/input-validation-rules-error"
});
x.Map<BadRequestException>(ex => new ProblemDetailsWithCode
{
Title = ex.GetType().Name,
Status = StatusCodes.Status400BadRequest,
Detail = ex.Message,
Type = "https://somedomain/bad-request-error"
});
x.Map<NotFoundException>(ex => new ProblemDetailsWithCode
{
Title = ex.GetType().Name,
Status = StatusCodes.Status404NotFound,
Detail = ex.Message,
Type = "https://somedomain/not-found-error"
});
x.Map<InternalServerException>(ex => new ProblemDetailsWithCode
{
Title = ex.GetType().Name,
Status = StatusCodes.Status500InternalServerError,
Detail = ex.Message,
Type = "https://somedomain/api-server-error"
});
x.Map<AppException>(ex => new ProblemDetailsWithCode
{
Title = ex.GetType().Name,
Status = StatusCodes.Status400BadRequest,
Detail = ex.Message,
Type = "https://somedomain/application-error"
});
x.Map<DbUpdateConcurrencyException>(ex => new ProblemDetailsWithCode
{
Title = ex.GetType().Name,
Status = StatusCodes.Status409Conflict,
Detail = ex.Message,
Type = "https://somedomain/db-update-concurrency-error"
});
x.MapToStatusCode<ArgumentNullException>(StatusCodes.Status400BadRequest);
x.MapStatusCode = context =>
{
return context.Response.StatusCode switch
if (context.RequestServices.GetService<IProblemDetailsService>() is { } problemDetailsService)
{
StatusCodes.Status401Unauthorized => new ProblemDetailsWithCode
{
Status = context.Response.StatusCode,
Title = "identity exception",
Detail = "You are not Authorized",
Type = "https://somedomain/identity-error"
},
var exceptionHandlerFeature = context.Features.Get<IExceptionHandlerFeature>();
var exceptionType = exceptionHandlerFeature?.Error;
_ => new StatusCodeProblemDetails(context.Response.StatusCode)
};
};
if (exceptionType is not null)
{
(string Detail, string Type, string Title, int StatusCode) details = exceptionType switch
{
ConflictException =>
(
exceptionType.Message,
exceptionType.GetType().ToString(),
exceptionType.GetType().Name,
context.Response.StatusCode = StatusCodes.Status409Conflict
),
ValidationException validationException =>
(
exceptionType.Message,
exceptionType.GetType().ToString(),
exceptionType.GetType().Name,
context.Response.StatusCode = (int)validationException.StatusCode
),
BadRequestException =>
(
exceptionType.Message,
exceptionType.GetType().ToString(),
exceptionType.GetType().Name,
context.Response.StatusCode = StatusCodes.Status400BadRequest
),
NotFoundException =>
(
exceptionType.Message,
exceptionType.GetType().ToString(),
exceptionType.GetType().Name,
context.Response.StatusCode = StatusCodes.Status404NotFound
),
AppException =>
(
exceptionType.Message,
exceptionType.GetType().ToString(),
exceptionType.GetType().Name,
context.Response.StatusCode = StatusCodes.Status400BadRequest
),
DbUpdateConcurrencyException =>
(
exceptionType.Message,
exceptionType.GetType().ToString(),
exceptionType.GetType().Name,
context.Response.StatusCode = StatusCodes.Status409Conflict
),
RpcException =>
(
exceptionType.Message,
exceptionType.GetType().ToString(),
exceptionType.GetType().Name,
context.Response.StatusCode = StatusCodes.Status400BadRequest
),
_ =>
(
exceptionType.Message,
exceptionType.GetType().ToString(),
exceptionType.GetType().Name,
context.Response.StatusCode = StatusCodes.Status500InternalServerError
)
};
await problemDetailsService.WriteAsync(new ProblemDetailsContext
{
HttpContext = context,
ProblemDetails =
{
Title = details.Title,
Detail = details.Detail,
Type = details.Type,
Status = details.StatusCode
}
});
}
}
});
});
return services;
return app;
}
}

View File

@ -4,7 +4,6 @@ using System;
using System.Threading;
using System.Threading.Tasks;
using BuildingBlocks.Web;
using Hellang.Middleware.ProblemDetails;
using MapsterMapper;
using MediatR;
using Microsoft.AspNetCore.Builder;
@ -24,25 +23,10 @@ public class CreateFlightEndpoint : IMinimalEndpoint
{
builder.MapPost($"{EndpointConfig.BaseApiPath}/flight", CreateFlight)
.RequireAuthorization()
.WithTags("Flight")
.WithName("CreateFlight")
.WithMetadata(new SwaggerOperationAttribute("Create Flight", "Create Flight"))
.WithApiVersionSet(builder.NewApiVersionSet("Flight").Build())
.WithMetadata(
new SwaggerResponseAttribute(
StatusCodes.Status201Created,
"Flight Created",
typeof(CreateFlightResponseDto)))
.WithMetadata(
new SwaggerResponseAttribute(
StatusCodes.Status400BadRequest,
"BadRequest",
typeof(StatusCodeProblemDetails)))
.WithMetadata(
new SwaggerResponseAttribute(
StatusCodes.Status401Unauthorized,
"UnAuthorized",
typeof(StatusCodeProblemDetails)))
.Produces<CreateFlightResponseDto>(StatusCodes.Status201Created)
.ProducesProblem(StatusCodes.Status400BadRequest)
.HasApiVersion(1.0);
return builder;

View File

@ -3,8 +3,6 @@
using System.Threading;
using System.Threading.Tasks;
using BuildingBlocks.Web;
using Flight.Flights.Dtos;
using Hellang.Middleware.ProblemDetails;
using MediatR;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
@ -17,24 +15,10 @@ public class DeleteFlightEndpoint : IMinimalEndpoint
{
builder.MapDelete($"{EndpointConfig.BaseApiPath}/flight/{{id}}", DeleteFlight)
.RequireAuthorization()
.WithTags("Flight")
.WithName("DeleteFlight")
.WithMetadata(new SwaggerOperationAttribute("Delete Flight", "Delete Flight"))
.WithApiVersionSet(builder.NewApiVersionSet("Flight").Build())
.WithMetadata(
new SwaggerResponseAttribute(
StatusCodes.Status204NoContent,
"Flight Deleted"))
.WithMetadata(
new SwaggerResponseAttribute(
StatusCodes.Status400BadRequest,
"BadRequest",
typeof(StatusCodeProblemDetails)))
.WithMetadata(
new SwaggerResponseAttribute(
StatusCodes.Status401Unauthorized,
"UnAuthorized",
typeof(StatusCodeProblemDetails)))
.Produces(StatusCodes.Status204NoContent)
.ProducesProblem(StatusCodes.Status400BadRequest)
.HasApiVersion(1.0);
return builder;

View File

@ -5,7 +5,6 @@ using System.Threading;
using System.Threading.Tasks;
using BuildingBlocks.Web;
using Dtos;
using Hellang.Middleware.ProblemDetails;
using MediatR;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
@ -20,25 +19,10 @@ public class GetAvailableFlightsEndpoint : IMinimalEndpoint
{
builder.MapGet($"{EndpointConfig.BaseApiPath}/flight/get-available-flights", GetAvailableFlights)
.RequireAuthorization()
.WithTags("Flight")
.WithName("GetAvailableFlights")
.WithMetadata(new SwaggerOperationAttribute("Get Available Flights", "Get Available Flights"))
.WithApiVersionSet(builder.NewApiVersionSet("Flight").Build())
.WithMetadata(
new SwaggerResponseAttribute(
StatusCodes.Status200OK,
"GetAvailableFlights",
typeof(GetAvailableFlightsResult)))
.WithMetadata(
new SwaggerResponseAttribute(
StatusCodes.Status400BadRequest,
"BadRequest",
typeof(StatusCodeProblemDetails)))
.WithMetadata(
new SwaggerResponseAttribute(
StatusCodes.Status401Unauthorized,
"UnAuthorized",
typeof(StatusCodeProblemDetails)))
.Produces<GetAvailableFlightsResponseDto>()
.ProducesProblem(StatusCodes.Status400BadRequest)
.HasApiVersion(1.0);
return builder;

View File

@ -4,7 +4,6 @@ using System.Threading;
using System.Threading.Tasks;
using BuildingBlocks.Web;
using Dtos;
using Hellang.Middleware.ProblemDetails;
using MediatR;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
@ -19,28 +18,10 @@ public class GetFlightByIdEndpoint : IMinimalEndpoint
{
builder.MapGet($"{EndpointConfig.BaseApiPath}/flight/{{id}}", GetById)
.RequireAuthorization()
.WithTags("Flight")
.WithName("GetFlightById")
.WithMetadata(new SwaggerOperationAttribute("Get Flight By Id", "Get Flight By Id"))
.WithApiVersionSet(builder.NewApiVersionSet("Flight").Build())
.Produces<FlightDto>()
.Produces(StatusCodes.Status200OK)
.Produces(StatusCodes.Status400BadRequest)
.WithMetadata(
new SwaggerResponseAttribute(
StatusCodes.Status200OK,
"GetFlightById",
typeof(GetFlightByIdResponseDto)))
.WithMetadata(
new SwaggerResponseAttribute(
StatusCodes.Status400BadRequest,
"BadRequest",
typeof(StatusCodeProblemDetails)))
.WithMetadata(
new SwaggerResponseAttribute(
StatusCodes.Status401Unauthorized,
"UnAuthorized",
typeof(StatusCodeProblemDetails)))
.Produces<GetFlightByIdResponseDto>()
.ProducesProblem(StatusCodes.Status400BadRequest)
.HasApiVersion(1.0);
return builder;

View File

@ -4,8 +4,6 @@ using System;
using System.Threading;
using System.Threading.Tasks;
using BuildingBlocks.Web;
using Dtos;
using Hellang.Middleware.ProblemDetails;
using MapsterMapper;
using MediatR;
using Microsoft.AspNetCore.Builder;
@ -22,27 +20,10 @@ public class UpdateFlightEndpoint : IMinimalEndpoint
{
builder.MapPut($"{EndpointConfig.BaseApiPath}/flight", UpdateFlight)
.RequireAuthorization()
.WithTags("Flight")
.WithName("UpdateFlight")
.WithMetadata(new SwaggerOperationAttribute("Update Flight", "Update Flight"))
.WithApiVersionSet(builder.NewApiVersionSet("Flight").Build())
.Produces<FlightDto>()
.Produces(StatusCodes.Status204NoContent)
.Produces(StatusCodes.Status400BadRequest)
.WithMetadata(
new SwaggerResponseAttribute(
StatusCodes.Status204NoContent,
"Flight Updated"))
.WithMetadata(
new SwaggerResponseAttribute(
StatusCodes.Status400BadRequest,
"BadRequest",
typeof(StatusCodeProblemDetails)))
.WithMetadata(
new SwaggerResponseAttribute(
StatusCodes.Status401Unauthorized,
"UnAuthorized",
typeof(StatusCodeProblemDetails)))
.ProducesProblem(StatusCodes.Status400BadRequest)
.HasApiVersion(1.0);
return builder;

View File

@ -3,8 +3,6 @@ namespace Flight.Seats.Features.CreatingSeat.V1;
using System.Threading;
using System.Threading.Tasks;
using BuildingBlocks.Web;
using Flight.Seats.Dtos;
using Hellang.Middleware.ProblemDetails;
using MapsterMapper;
using MediatR;
using Microsoft.AspNetCore.Builder;
@ -21,25 +19,10 @@ public class CreateSeatEndpoint : IMinimalEndpoint
{
builder.MapPost($"{EndpointConfig.BaseApiPath}/flight/seat", CreateSeat)
.RequireAuthorization()
.WithTags("Flight")
.WithName("CreateSeat")
.WithMetadata(new SwaggerOperationAttribute("Create Seat", "Create Seat"))
.WithApiVersionSet(builder.NewApiVersionSet("Flight").Build())
.WithMetadata(
new SwaggerResponseAttribute(
StatusCodes.Status200OK,
"Seat Created",
typeof(CreateSeatResponseDto)))
.WithMetadata(
new SwaggerResponseAttribute(
StatusCodes.Status400BadRequest,
"BadRequest",
typeof(StatusCodeProblemDetails)))
.WithMetadata(
new SwaggerResponseAttribute(
StatusCodes.Status401Unauthorized,
"UnAuthorized",
typeof(StatusCodeProblemDetails)))
.Produces<CreateSeatResponseDto>()
.ProducesProblem(StatusCodes.Status400BadRequest)
.HasApiVersion(1.0);
return builder;

View File

@ -4,8 +4,7 @@ using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using BuildingBlocks.Web;
using Flight.Seats.Dtos;
using Hellang.Middleware.ProblemDetails;
using Dtos;
using MediatR;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
@ -20,25 +19,10 @@ public class GetAvailableSeatsEndpoint : IMinimalEndpoint
{
builder.MapGet($"{EndpointConfig.BaseApiPath}/flight/get-available-seats/{{id}}", GetAvailableSeats)
.RequireAuthorization()
.WithTags("Flight")
.WithName("GetAvailableSeats")
.WithMetadata(new SwaggerOperationAttribute("Get Available Seats", "Get Available Seats"))
.WithApiVersionSet(builder.NewApiVersionSet("Flight").Build())
.WithMetadata(
new SwaggerResponseAttribute(
StatusCodes.Status200OK,
"GetAvailableSeats",
typeof(GetAvailableSeatsResponseDto)))
.WithMetadata(
new SwaggerResponseAttribute(
StatusCodes.Status400BadRequest,
"BadRequest",
typeof(StatusCodeProblemDetails)))
.WithMetadata(
new SwaggerResponseAttribute(
StatusCodes.Status401Unauthorized,
"UnAuthorized",
typeof(StatusCodeProblemDetails)))
.Produces<GetAvailableSeatsResponseDto>()
.ProducesProblem(StatusCodes.Status400BadRequest)
.HasApiVersion(1.0);
return builder;

View File

@ -3,8 +3,6 @@ namespace Flight.Seats.Features.ReservingSeat.Commands.V1;
using System.Threading;
using System.Threading.Tasks;
using BuildingBlocks.Web;
using Flight.Seats.Dtos;
using Hellang.Middleware.ProblemDetails;
using MapsterMapper;
using MediatR;
using Microsoft.AspNetCore.Builder;
@ -21,25 +19,10 @@ public class ReserveSeatEndpoint : IMinimalEndpoint
{
builder.MapPost($"{EndpointConfig.BaseApiPath}/flight/reserve-seat", ReserveSeat)
.RequireAuthorization()
.WithTags("Flight")
.WithName("ReserveSeat")
.WithMetadata(new SwaggerOperationAttribute("Reserve Seat", "Reserve Seat"))
.WithApiVersionSet(builder.NewApiVersionSet("Flight").Build())
.WithMetadata(
new SwaggerResponseAttribute(
StatusCodes.Status200OK,
"ReserveSeat",
typeof(ReserveSeatResponseDto)))
.WithMetadata(
new SwaggerResponseAttribute(
StatusCodes.Status400BadRequest,
"BadRequest",
typeof(StatusCodeProblemDetails)))
.WithMetadata(
new SwaggerResponseAttribute(
StatusCodes.Status401Unauthorized,
"UnAuthorized",
typeof(StatusCodeProblemDetails)))
.Produces<ReserveSeatResponseDto>()
.ProducesProblem(StatusCodes.Status400BadRequest)
.HasApiVersion(1.0);
return builder;

View File

@ -3,7 +3,6 @@ using System.Threading.RateLimiting;
using BuildingBlocks.Core;
using BuildingBlocks.EFCore;
using BuildingBlocks.HealthCheck;
using BuildingBlocks.IdsGenerator;
using BuildingBlocks.Logging;
using BuildingBlocks.Mapster;
using BuildingBlocks.MassTransit;
@ -13,7 +12,6 @@ using BuildingBlocks.Swagger;
using BuildingBlocks.Web;
using Figgle;
using FluentValidation;
using Hellang.Middleware.ProblemDetails;
using Identity.Data;
using Identity.Data.Seed;
using Microsoft.AspNetCore.Builder;
@ -72,7 +70,7 @@ public static class InfrastructureExtensions
builder.Services.AddCustomVersioning();
builder.Services.AddCustomMediatR();
builder.Services.AddValidatorsFromAssembly(typeof(IdentityRoot).Assembly);
builder.Services.AddCustomProblemDetails();
builder.Services.AddProblemDetails();
builder.Services.AddCustomMapster(typeof(IdentityRoot).Assembly);
builder.Services.AddCustomHealthCheck();
@ -98,7 +96,7 @@ public static class InfrastructureExtensions
app.UseForwardedHeaders();
app.UseProblemDetails();
app.UseCustomProblemDetails();
app.UseSerilogRequestLogging(options =>
{
options.EnrichDiagnosticContext = LogEnrichHelper.EnrichFromRequest;
@ -107,7 +105,6 @@ public static class InfrastructureExtensions
app.UseMigration<IdentityContext>(env);
app.UseCorrelationId();
app.UseHttpMetrics();
app.UseProblemDetails();
app.UseCustomHealthCheck();
app.UseIdentityServer();
app.MapMetrics();

View File

@ -1,98 +1,106 @@
using System;
using BuildingBlocks.Exception;
using Hellang.Middleware.ProblemDetails;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
namespace Identity.Extensions.Infrastructure;
using BuildingBlocks.Exception;
using Grpc.Core;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Diagnostics;
using Microsoft.AspNetCore.Http;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
public static class ProblemDetailsExtensions
{
public static IServiceCollection AddCustomProblemDetails(this IServiceCollection services)
public static WebApplication UseCustomProblemDetails(this WebApplication app)
{
services.AddProblemDetails(x =>
app.UseExceptionHandler(exceptionHandlerApp =>
{
// Control when an exception is included
x.IncludeExceptionDetails = (ctx, _) =>
exceptionHandlerApp.Run(async context =>
{
// Fetch services from HttpContext.RequestServices
var env = ctx.RequestServices.GetRequiredService<IHostEnvironment>();
return env.IsDevelopment() || env.IsStaging();
};
x.Map<ConflictException>(ex => new ProblemDetailsWithCode
{
Title = ex.GetType().Name,
Status = StatusCodes.Status409Conflict,
Detail = ex.Message,
Type = "https://somedomain/application-rule-validation-error"
});
context.Response.ContentType = "application/problem+json";
// Exception will produce and returns from our FluentValidation RequestValidationBehavior
x.Map<ValidationException>(ex => new ProblemDetailsWithCode
{
Title = ex.GetType().Name,
Status = (int)ex.StatusCode,
Detail = ex.Message,
Type = "https://somedomain/input-validation-rules-error"
});
x.Map<BadRequestException>(ex => new ProblemDetailsWithCode
{
Title = ex.GetType().Name,
Status = StatusCodes.Status400BadRequest,
Detail = ex.Message,
Type = "https://somedomain/bad-request-error"
});
x.Map<NotFoundException>(ex => new ProblemDetailsWithCode
{
Title = ex.GetType().Name,
Status = StatusCodes.Status404NotFound,
Detail = ex.Message,
Type = "https://somedomain/not-found-error"
});
x.Map<InternalServerException>(ex => new ProblemDetailsWithCode
{
Title = ex.GetType().Name,
Status = StatusCodes.Status500InternalServerError,
Detail = ex.Message,
Type = "https://somedomain/api-server-error"
});
x.Map<AppException>(ex => new ProblemDetailsWithCode
{
Title = ex.GetType().Name,
Status = StatusCodes.Status400BadRequest,
Detail = ex.Message,
Type = "https://somedomain/application-error"
});
x.Map<DbUpdateConcurrencyException>(ex => new ProblemDetailsWithCode
{
Title = ex.GetType().Name,
Status = StatusCodes.Status409Conflict,
Detail = ex.Message,
Type = "https://somedomain/db-update-concurrency-error"
});
x.MapToStatusCode<ArgumentNullException>(StatusCodes.Status400BadRequest);
x.MapStatusCode = context =>
{
return context.Response.StatusCode switch
if (context.RequestServices.GetService<IProblemDetailsService>() is { } problemDetailsService)
{
StatusCodes.Status401Unauthorized => new ProblemDetailsWithCode
{
Status = context.Response.StatusCode,
Title = "identity exception",
Detail = "You are not Authorized",
Type = "https://somedomain/identity-error"
},
var exceptionHandlerFeature = context.Features.Get<IExceptionHandlerFeature>();
var exceptionType = exceptionHandlerFeature?.Error;
_ => new StatusCodeProblemDetails(context.Response.StatusCode)
};
};
if (exceptionType is not null)
{
(string Detail, string Type, string Title, int StatusCode) details = exceptionType switch
{
ConflictException =>
(
exceptionType.Message,
exceptionType.GetType().ToString(),
exceptionType.GetType().Name,
context.Response.StatusCode = StatusCodes.Status409Conflict
),
ValidationException validationException =>
(
exceptionType.Message,
exceptionType.GetType().ToString(),
exceptionType.GetType().Name,
context.Response.StatusCode = (int)validationException.StatusCode
),
BadRequestException =>
(
exceptionType.Message,
exceptionType.GetType().ToString(),
exceptionType.GetType().Name,
context.Response.StatusCode = StatusCodes.Status400BadRequest
),
NotFoundException =>
(
exceptionType.Message,
exceptionType.GetType().ToString(),
exceptionType.GetType().Name,
context.Response.StatusCode = StatusCodes.Status404NotFound
),
AppException =>
(
exceptionType.Message,
exceptionType.GetType().ToString(),
exceptionType.GetType().Name,
context.Response.StatusCode = StatusCodes.Status400BadRequest
),
DbUpdateConcurrencyException =>
(
exceptionType.Message,
exceptionType.GetType().ToString(),
exceptionType.GetType().Name,
context.Response.StatusCode = StatusCodes.Status409Conflict
),
RpcException =>
(
exceptionType.Message,
exceptionType.GetType().ToString(),
exceptionType.GetType().Name,
context.Response.StatusCode = StatusCodes.Status400BadRequest
),
_ =>
(
exceptionType.Message,
exceptionType.GetType().ToString(),
exceptionType.GetType().Name,
context.Response.StatusCode = StatusCodes.Status500InternalServerError
)
};
await problemDetailsService.WriteAsync(new ProblemDetailsContext
{
HttpContext = context,
ProblemDetails =
{
Title = details.Title,
Detail = details.Detail,
Type = details.Type,
Status = details.StatusCode
}
});
}
}
});
});
return services;
return app;
}
}

View File

@ -3,7 +3,6 @@ namespace Identity.Identity.Features.RegisteringNewUser.V1;
using System.Threading;
using System.Threading.Tasks;
using BuildingBlocks.Web;
using Hellang.Middleware.ProblemDetails;
using MapsterMapper;
using MediatR;
using Microsoft.AspNetCore.Builder;
@ -21,20 +20,10 @@ public class RegisterNewUserEndpoint : IMinimalEndpoint
public IEndpointRouteBuilder MapEndpoint(IEndpointRouteBuilder builder)
{
builder.MapPost($"{EndpointConfig.BaseApiPath}/identity/register-user", RegisterNewUser)
.WithTags("Identity")
.WithName("RegisterUser")
.WithMetadata(new SwaggerOperationAttribute("Register User", "Register User"))
.WithApiVersionSet(builder.NewApiVersionSet("Identity").Build())
.WithMetadata(
new SwaggerResponseAttribute(
StatusCodes.Status200OK,
"User Registered",
typeof(RegisterNewUserResponseDto)))
.WithMetadata(
new SwaggerResponseAttribute(
StatusCodes.Status400BadRequest,
"BadRequest",
typeof(StatusCodeProblemDetails)))
.Produces<RegisterNewUserResponseDto>()
.ProducesProblem(StatusCodes.Status400BadRequest)
.HasApiVersion(1.0);
return builder;

View File

@ -3,7 +3,6 @@ using BuildingBlocks.Core;
using BuildingBlocks.EFCore;
using BuildingBlocks.Exception;
using BuildingBlocks.HealthCheck;
using BuildingBlocks.IdsGenerator;
using BuildingBlocks.Jwt;
using BuildingBlocks.Logging;
using BuildingBlocks.Mapster;
@ -15,7 +14,6 @@ using BuildingBlocks.Swagger;
using BuildingBlocks.Web;
using Figgle;
using FluentValidation;
using Hellang.Middleware.ProblemDetails;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
@ -73,7 +71,7 @@ public static class InfrastructureExtensions
builder.Services.AddCustomVersioning();
builder.Services.AddCustomMediatR();
builder.Services.AddValidatorsFromAssembly(typeof(PassengerRoot).Assembly);
builder.Services.AddCustomProblemDetails();
builder.Services.AddProblemDetails();
builder.Services.AddCustomMapster(typeof(PassengerRoot).Assembly);
builder.Services.AddHttpContextAccessor();
builder.Services.AddCustomHealthCheck();
@ -93,7 +91,7 @@ public static class InfrastructureExtensions
var env = app.Environment;
var appOptions = app.GetOptions<AppOptions>(nameof(AppOptions));
app.UseProblemDetails();
app.UseCustomProblemDetails();
app.UseSerilogRequestLogging(options =>
{
options.EnrichDiagnosticContext = LogEnrichHelper.EnrichFromRequest;

View File

@ -1,97 +1,106 @@
using BuildingBlocks.Exception;
using Hellang.Middleware.ProblemDetails;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
namespace Passenger.Extensions.Infrastructure;
using BuildingBlocks.Exception;
using Grpc.Core;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Diagnostics;
using Microsoft.AspNetCore.Http;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
public static class ProblemDetailsExtensions
{
public static IServiceCollection AddCustomProblemDetails(this IServiceCollection services)
public static WebApplication UseCustomProblemDetails(this WebApplication app)
{
services.AddProblemDetails(x =>
app.UseExceptionHandler(exceptionHandlerApp =>
{
// Control when an exception is included
x.IncludeExceptionDetails = (ctx, _) =>
exceptionHandlerApp.Run(async context =>
{
// Fetch services from HttpContext.RequestServices
var env = ctx.RequestServices.GetRequiredService<IHostEnvironment>();
return env.IsDevelopment() || env.IsStaging();
};
x.Map<ConflictException>(ex => new ProblemDetailsWithCode
{
Title = ex.GetType().Name,
Status = StatusCodes.Status409Conflict,
Detail = ex.Message,
Type = "https://somedomain/application-rule-validation-error"
});
context.Response.ContentType = "application/problem+json";
// Exception will produce and returns from our FluentValidation RequestValidationBehavior
x.Map<ValidationException>(ex => new ProblemDetailsWithCode
{
Title = ex.GetType().Name,
Status = (int)ex.StatusCode,
Detail = ex.Message,
Type = "https://somedomain/input-validation-rules-error"
});
x.Map<BadRequestException>(ex => new ProblemDetailsWithCode
{
Title = ex.GetType().Name,
Status = StatusCodes.Status400BadRequest,
Detail = ex.Message,
Type = "https://somedomain/bad-request-error"
});
x.Map<NotFoundException>(ex => new ProblemDetailsWithCode
{
Title = ex.GetType().Name,
Status = StatusCodes.Status404NotFound,
Detail = ex.Message,
Type = "https://somedomain/not-found-error"
});
x.Map<InternalServerException>(ex => new ProblemDetailsWithCode
{
Title = ex.GetType().Name,
Status = StatusCodes.Status500InternalServerError,
Detail = ex.Message,
Type = "https://somedomain/api-server-error"
});
x.Map<AppException>(ex => new ProblemDetailsWithCode
{
Title = ex.GetType().Name,
Status = StatusCodes.Status400BadRequest,
Detail = ex.Message,
Type = "https://somedomain/application-error"
});
x.Map<DbUpdateConcurrencyException>(ex => new ProblemDetailsWithCode
{
Title = ex.GetType().Name,
Status = StatusCodes.Status409Conflict,
Detail = ex.Message,
Type = "https://somedomain/db-update-concurrency-error"
});
x.MapToStatusCode<ArgumentNullException>(StatusCodes.Status400BadRequest);
x.MapStatusCode = context =>
{
return context.Response.StatusCode switch
if (context.RequestServices.GetService<IProblemDetailsService>() is { } problemDetailsService)
{
StatusCodes.Status401Unauthorized => new ProblemDetailsWithCode
{
Status = context.Response.StatusCode,
Title = "identity exception",
Detail = "You are not Authorized",
Type = "https://somedomain/identity-error"
},
var exceptionHandlerFeature = context.Features.Get<IExceptionHandlerFeature>();
var exceptionType = exceptionHandlerFeature?.Error;
_ => new StatusCodeProblemDetails(context.Response.StatusCode)
};
};
if (exceptionType is not null)
{
(string Detail, string Type, string Title, int StatusCode) details = exceptionType switch
{
ConflictException =>
(
exceptionType.Message,
exceptionType.GetType().ToString(),
exceptionType.GetType().Name,
context.Response.StatusCode = StatusCodes.Status409Conflict
),
ValidationException validationException =>
(
exceptionType.Message,
exceptionType.GetType().ToString(),
exceptionType.GetType().Name,
context.Response.StatusCode = (int)validationException.StatusCode
),
BadRequestException =>
(
exceptionType.Message,
exceptionType.GetType().ToString(),
exceptionType.GetType().Name,
context.Response.StatusCode = StatusCodes.Status400BadRequest
),
NotFoundException =>
(
exceptionType.Message,
exceptionType.GetType().ToString(),
exceptionType.GetType().Name,
context.Response.StatusCode = StatusCodes.Status404NotFound
),
AppException =>
(
exceptionType.Message,
exceptionType.GetType().ToString(),
exceptionType.GetType().Name,
context.Response.StatusCode = StatusCodes.Status400BadRequest
),
DbUpdateConcurrencyException =>
(
exceptionType.Message,
exceptionType.GetType().ToString(),
exceptionType.GetType().Name,
context.Response.StatusCode = StatusCodes.Status409Conflict
),
RpcException =>
(
exceptionType.Message,
exceptionType.GetType().ToString(),
exceptionType.GetType().Name,
context.Response.StatusCode = StatusCodes.Status400BadRequest
),
_ =>
(
exceptionType.Message,
exceptionType.GetType().ToString(),
exceptionType.GetType().Name,
context.Response.StatusCode = StatusCodes.Status500InternalServerError
)
};
await problemDetailsService.WriteAsync(new ProblemDetailsContext
{
HttpContext = context,
ProblemDetails =
{
Title = details.Title,
Detail = details.Detail,
Type = details.Type,
Status = details.StatusCode
}
});
}
}
});
});
return services;
return app;
}
}

View File

@ -1,7 +1,6 @@
namespace Passenger.Passengers.Features.CompletingRegisterPassenger.V1;
using BuildingBlocks.Web;
using Hellang.Middleware.ProblemDetails;
using MapsterMapper;
using MediatR;
using Microsoft.AspNetCore.Builder;
@ -19,25 +18,10 @@ public class CompleteRegisterPassengerEndpoint : IMinimalEndpoint
{
builder.MapPost($"{EndpointConfig.BaseApiPath}/passenger/complete-registration", CompleteRegisterPassenger)
.RequireAuthorization()
.WithTags("Passenger")
.WithName("CompleteRegisterPassenger")
.WithMetadata(new SwaggerOperationAttribute("Complete Register Passenger", "Complete Register Passenger"))
.WithApiVersionSet(builder.NewApiVersionSet("Passenger").Build())
.WithMetadata(
new SwaggerResponseAttribute(
StatusCodes.Status200OK,
"Register Passenger Completed",
typeof(CompleteRegisterPassengerResponseDto)))
.WithMetadata(
new SwaggerResponseAttribute(
StatusCodes.Status400BadRequest,
"BadRequest",
typeof(StatusCodeProblemDetails)))
.WithMetadata(
new SwaggerResponseAttribute(
StatusCodes.Status401Unauthorized,
"UnAuthorized",
typeof(StatusCodeProblemDetails)))
.Produces<CompleteRegisterPassengerResponseDto>()
.ProducesProblem(StatusCodes.Status400BadRequest)
.HasApiVersion(1.0);
return builder;

View File

@ -1,12 +1,11 @@
namespace Passenger.Passengers.Features.GettingPassengerById.Queries.V1;
using BuildingBlocks.Web;
using Hellang.Middleware.ProblemDetails;
using MediatR;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Routing;
using Passenger.Passengers.Dtos;
using Dtos;
using Swashbuckle.AspNetCore.Annotations;
public record GetPassengerByIdResponseDto(PassengerDto PassengerDto);
@ -17,25 +16,10 @@ public class GetPassengerByIdEndpoint : IMinimalEndpoint
{
builder.MapGet($"{EndpointConfig.BaseApiPath}/passenger/{{id}}", GetById)
.RequireAuthorization()
.WithTags("Passenger")
.WithName("GetPassengerById")
.WithMetadata(new SwaggerOperationAttribute("Get Passenger By Id", "Get Passenger By Id"))
.WithApiVersionSet(builder.NewApiVersionSet("Passenger").Build())
.WithMetadata(
new SwaggerResponseAttribute(
StatusCodes.Status200OK,
"GetPassengerById",
typeof(GetPassengerByIdResponseDto)))
.WithMetadata(
new SwaggerResponseAttribute(
StatusCodes.Status400BadRequest,
"BadRequest",
typeof(StatusCodeProblemDetails)))
.WithMetadata(
new SwaggerResponseAttribute(
StatusCodes.Status401Unauthorized,
"UnAuthorized",
typeof(StatusCodeProblemDetails)))
.Produces<GetPassengerByIdResponseDto>()
.ProducesProblem(StatusCodes.Status400BadRequest)
.HasApiVersion(1.0);
return builder;