diff --git a/src/BuildingBlocks/BuildingBlocks.csproj b/src/BuildingBlocks/BuildingBlocks.csproj
index 2ce1533..6ef8e41 100644
--- a/src/BuildingBlocks/BuildingBlocks.csproj
+++ b/src/BuildingBlocks/BuildingBlocks.csproj
@@ -44,7 +44,6 @@
all
runtime; build; native; contentfiles; analyzers; buildtransitive
-
diff --git a/src/Services/Booking/src/Booking/Booking/Features/CreatingBook/Commands/V1/CreateBookingEndpoint.cs b/src/Services/Booking/src/Booking/Booking/Features/CreatingBook/Commands/V1/CreateBookingEndpoint.cs
index 4b9d0f2..c005d12 100644
--- a/src/Services/Booking/src/Booking/Booking/Features/CreatingBook/Commands/V1/CreateBookingEndpoint.cs
+++ b/src/Services/Booking/src/Booking/Booking/Features/CreatingBook/Commands/V1/CreateBookingEndpoint.cs
@@ -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()
+ .ProducesProblem(StatusCodes.Status400BadRequest)
.HasApiVersion(1.0);
return builder;
diff --git a/src/Services/Booking/src/Booking/Extensions/Infrastructure/InfrastructureExtensions.cs b/src/Services/Booking/src/Booking/Extensions/Infrastructure/InfrastructureExtensions.cs
index 4734d5e..92de13d 100644
--- a/src/Services/Booking/src/Booking/Extensions/Infrastructure/InfrastructureExtensions.cs
+++ b/src/Services/Booking/src/Booking/Extensions/Infrastructure/InfrastructureExtensions.cs
@@ -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(nameof(AppOptions));
- app.UseProblemDetails();
+ app.UseCustomProblemDetails();
app.UseSerilogRequestLogging(options =>
{
options.EnrichDiagnosticContext = LogEnrichHelper.EnrichFromRequest;
diff --git a/src/Services/Booking/src/Booking/Extensions/Infrastructure/ProblemDetailsExtensions.cs b/src/Services/Booking/src/Booking/Extensions/Infrastructure/ProblemDetailsExtensions.cs
index 9e3aa31..32c2ffb 100644
--- a/src/Services/Booking/src/Booking/Extensions/Infrastructure/ProblemDetailsExtensions.cs
+++ b/src/Services/Booking/src/Booking/Extensions/Infrastructure/ProblemDetailsExtensions.cs
@@ -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();
- return env.IsDevelopment() || env.IsStaging();
- };
- x.Map(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(ex => new ProblemDetailsWithCode
- {
- Title = ex.GetType().Name,
- Status = (int)ex.StatusCode,
- Detail = ex.Message,
- Type = "https://somedomain/input-validation-rules-error",
- });
- x.Map(ex => new ProblemDetailsWithCode
- {
- Title = ex.GetType().Name,
- Status = StatusCodes.Status400BadRequest,
- Detail = ex.Message,
- Type = "https://somedomain/bad-request-error",
- });
- x.Map(ex => new ProblemDetailsWithCode
- {
- Title = ex.GetType().Name,
- Status = StatusCodes.Status404NotFound,
- Detail = ex.Message,
- Type = "https://somedomain/not-found-error",
- });
- x.Map(ex => new ProblemDetailsWithCode
- {
- Title = ex.GetType().Name,
- Status = StatusCodes.Status500InternalServerError,
- Detail = ex.Message,
- Type = "https://somedomain/api-server-error",
- });
- x.Map(ex => new ProblemDetailsWithCode
- {
- Title = ex.GetType().Name,
- Status = StatusCodes.Status400BadRequest,
- Detail = ex.Message,
- Type = "https://somedomain/application-error",
- });
-
- x.Map(ex => new ProblemDetails
- {
- Status = StatusCodes.Status400BadRequest,
- Title = ex.GetType().Name,
- Detail = ex.Status.Detail,
- Type = "https://somedomain/grpc-error"
- });
-
- x.Map(ex => new ProblemDetailsWithCode
- {
- Title = ex.GetType().Name,
- Status = StatusCodes.Status409Conflict,
- Detail = ex.Message,
- Type = "https://somedomain/db-update-concurrency-error"
- });
-
- x.MapToStatusCode(StatusCodes.Status400BadRequest);
-
- x.MapStatusCode = context =>
- {
- return context.Response.StatusCode switch
+ if (context.RequestServices.GetService() 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();
+ 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;
}
}
diff --git a/src/Services/Flight/src/Flight/Aircrafts/Features/CreatingAircraft/V1/CreateAircraftEndpoint.cs b/src/Services/Flight/src/Flight/Aircrafts/Features/CreatingAircraft/V1/CreateAircraftEndpoint.cs
index c4d2fc4..4cb2608 100644
--- a/src/Services/Flight/src/Flight/Aircrafts/Features/CreatingAircraft/V1/CreateAircraftEndpoint.cs
+++ b/src/Services/Flight/src/Flight/Aircrafts/Features/CreatingAircraft/V1/CreateAircraftEndpoint.cs
@@ -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()
+ .ProducesProblem(StatusCodes.Status400BadRequest)
.HasApiVersion(1.0);
return builder;
diff --git a/src/Services/Flight/src/Flight/Airports/Features/CreatingAirport/V1/CreateAirportEndpoint.cs b/src/Services/Flight/src/Flight/Airports/Features/CreatingAirport/V1/CreateAirportEndpoint.cs
index 64308bd..a383539 100644
--- a/src/Services/Flight/src/Flight/Airports/Features/CreatingAirport/V1/CreateAirportEndpoint.cs
+++ b/src/Services/Flight/src/Flight/Airports/Features/CreatingAirport/V1/CreateAirportEndpoint.cs
@@ -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()
+ .ProducesProblem(StatusCodes.Status400BadRequest)
.HasApiVersion(1.0);
return builder;
diff --git a/src/Services/Flight/src/Flight/Extensions/Infrastructure/InfrastructureExtensions.cs b/src/Services/Flight/src/Flight/Extensions/Infrastructure/InfrastructureExtensions.cs
index 33bccff..82558e7 100644
--- a/src/Services/Flight/src/Flight/Extensions/Infrastructure/InfrastructureExtensions.cs
+++ b/src/Services/Flight/src/Flight/Extensions/Infrastructure/InfrastructureExtensions.cs
@@ -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(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(nameof(AppOptions));
- app.UseProblemDetails();
+ app.UseCustomProblemDetails();
app.UseSerilogRequestLogging(options =>
{
options.EnrichDiagnosticContext = LogEnrichHelper.EnrichFromRequest;
diff --git a/src/Services/Flight/src/Flight/Extensions/Infrastructure/ProblemDetailsExtensions.cs b/src/Services/Flight/src/Flight/Extensions/Infrastructure/ProblemDetailsExtensions.cs
index 006dd8b..a6a070d 100644
--- a/src/Services/Flight/src/Flight/Extensions/Infrastructure/ProblemDetailsExtensions.cs
+++ b/src/Services/Flight/src/Flight/Extensions/Infrastructure/ProblemDetailsExtensions.cs
@@ -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();
- return env.IsDevelopment() || env.IsStaging();
- };
- x.Map(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(ex => new ProblemDetailsWithCode
- {
- Title = ex.GetType().Name,
- Status = (int)ex.StatusCode,
- Detail = ex.Message,
- Type = "https://somedomain/input-validation-rules-error"
- });
- x.Map(ex => new ProblemDetailsWithCode
- {
- Title = ex.GetType().Name,
- Status = StatusCodes.Status400BadRequest,
- Detail = ex.Message,
- Type = "https://somedomain/bad-request-error"
- });
- x.Map(ex => new ProblemDetailsWithCode
- {
- Title = ex.GetType().Name,
- Status = StatusCodes.Status404NotFound,
- Detail = ex.Message,
- Type = "https://somedomain/not-found-error"
- });
- x.Map(ex => new ProblemDetailsWithCode
- {
- Title = ex.GetType().Name,
- Status = StatusCodes.Status500InternalServerError,
- Detail = ex.Message,
- Type = "https://somedomain/api-server-error"
- });
- x.Map(ex => new ProblemDetailsWithCode
- {
- Title = ex.GetType().Name,
- Status = StatusCodes.Status400BadRequest,
- Detail = ex.Message,
- Type = "https://somedomain/application-error"
- });
-
- x.Map(ex => new ProblemDetailsWithCode
- {
- Title = ex.GetType().Name,
- Status = StatusCodes.Status409Conflict,
- Detail = ex.Message,
- Type = "https://somedomain/db-update-concurrency-error"
- });
-
- x.MapToStatusCode(StatusCodes.Status400BadRequest);
-
- x.MapStatusCode = context =>
- {
- return context.Response.StatusCode switch
+ if (context.RequestServices.GetService() 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();
+ 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;
}
}
diff --git a/src/Services/Flight/src/Flight/Flights/Features/CreatingFlight/V1/CreateFlightEndpoint.cs b/src/Services/Flight/src/Flight/Flights/Features/CreatingFlight/V1/CreateFlightEndpoint.cs
index 867b677..fe584cc 100644
--- a/src/Services/Flight/src/Flight/Flights/Features/CreatingFlight/V1/CreateFlightEndpoint.cs
+++ b/src/Services/Flight/src/Flight/Flights/Features/CreatingFlight/V1/CreateFlightEndpoint.cs
@@ -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(StatusCodes.Status201Created)
+ .ProducesProblem(StatusCodes.Status400BadRequest)
.HasApiVersion(1.0);
return builder;
diff --git a/src/Services/Flight/src/Flight/Flights/Features/DeletingFlight/V1/DeleteFlightEndpoint.cs b/src/Services/Flight/src/Flight/Flights/Features/DeletingFlight/V1/DeleteFlightEndpoint.cs
index 8f172fa..9588584 100644
--- a/src/Services/Flight/src/Flight/Flights/Features/DeletingFlight/V1/DeleteFlightEndpoint.cs
+++ b/src/Services/Flight/src/Flight/Flights/Features/DeletingFlight/V1/DeleteFlightEndpoint.cs
@@ -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;
diff --git a/src/Services/Flight/src/Flight/Flights/Features/GettingAvailableFlights/V1/GetAvailableFlightsEndpoint.cs b/src/Services/Flight/src/Flight/Flights/Features/GettingAvailableFlights/V1/GetAvailableFlightsEndpoint.cs
index 0744247..72eca9a 100644
--- a/src/Services/Flight/src/Flight/Flights/Features/GettingAvailableFlights/V1/GetAvailableFlightsEndpoint.cs
+++ b/src/Services/Flight/src/Flight/Flights/Features/GettingAvailableFlights/V1/GetAvailableFlightsEndpoint.cs
@@ -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()
+ .ProducesProblem(StatusCodes.Status400BadRequest)
.HasApiVersion(1.0);
return builder;
diff --git a/src/Services/Flight/src/Flight/Flights/Features/GettingFlightById/V1/GetFlightByIdEndpoint.cs b/src/Services/Flight/src/Flight/Flights/Features/GettingFlightById/V1/GetFlightByIdEndpoint.cs
index 8d32c3c..0f09943 100644
--- a/src/Services/Flight/src/Flight/Flights/Features/GettingFlightById/V1/GetFlightByIdEndpoint.cs
+++ b/src/Services/Flight/src/Flight/Flights/Features/GettingFlightById/V1/GetFlightByIdEndpoint.cs
@@ -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()
- .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()
+ .ProducesProblem(StatusCodes.Status400BadRequest)
.HasApiVersion(1.0);
return builder;
diff --git a/src/Services/Flight/src/Flight/Flights/Features/UpdatingFlight/V1/UpdateFlightEndpoint.cs b/src/Services/Flight/src/Flight/Flights/Features/UpdatingFlight/V1/UpdateFlightEndpoint.cs
index 66a8d45..ffc663b 100644
--- a/src/Services/Flight/src/Flight/Flights/Features/UpdatingFlight/V1/UpdateFlightEndpoint.cs
+++ b/src/Services/Flight/src/Flight/Flights/Features/UpdatingFlight/V1/UpdateFlightEndpoint.cs
@@ -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()
.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;
diff --git a/src/Services/Flight/src/Flight/Seats/Features/CreatingSeat/V1/CreateSeatEndpoint.cs b/src/Services/Flight/src/Flight/Seats/Features/CreatingSeat/V1/CreateSeatEndpoint.cs
index 8b693c2..e2192ab 100644
--- a/src/Services/Flight/src/Flight/Seats/Features/CreatingSeat/V1/CreateSeatEndpoint.cs
+++ b/src/Services/Flight/src/Flight/Seats/Features/CreatingSeat/V1/CreateSeatEndpoint.cs
@@ -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()
+ .ProducesProblem(StatusCodes.Status400BadRequest)
.HasApiVersion(1.0);
return builder;
diff --git a/src/Services/Flight/src/Flight/Seats/Features/GettingAvailableSeats/V1/GetAvailableSeatsEndpoint.cs b/src/Services/Flight/src/Flight/Seats/Features/GettingAvailableSeats/V1/GetAvailableSeatsEndpoint.cs
index 5caa219..65c2cab 100644
--- a/src/Services/Flight/src/Flight/Seats/Features/GettingAvailableSeats/V1/GetAvailableSeatsEndpoint.cs
+++ b/src/Services/Flight/src/Flight/Seats/Features/GettingAvailableSeats/V1/GetAvailableSeatsEndpoint.cs
@@ -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()
+ .ProducesProblem(StatusCodes.Status400BadRequest)
.HasApiVersion(1.0);
return builder;
diff --git a/src/Services/Flight/src/Flight/Seats/Features/ReservingSeat/Commands/V1/ReserveSeatEndpoint.cs b/src/Services/Flight/src/Flight/Seats/Features/ReservingSeat/Commands/V1/ReserveSeatEndpoint.cs
index 6eb8fb0..23ece24 100644
--- a/src/Services/Flight/src/Flight/Seats/Features/ReservingSeat/Commands/V1/ReserveSeatEndpoint.cs
+++ b/src/Services/Flight/src/Flight/Seats/Features/ReservingSeat/Commands/V1/ReserveSeatEndpoint.cs
@@ -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()
+ .ProducesProblem(StatusCodes.Status400BadRequest)
.HasApiVersion(1.0);
return builder;
diff --git a/src/Services/Identity/src/Identity/Extensions/Infrastructure/InfrastructureExtensions.cs b/src/Services/Identity/src/Identity/Extensions/Infrastructure/InfrastructureExtensions.cs
index fbb7205..563c523 100644
--- a/src/Services/Identity/src/Identity/Extensions/Infrastructure/InfrastructureExtensions.cs
+++ b/src/Services/Identity/src/Identity/Extensions/Infrastructure/InfrastructureExtensions.cs
@@ -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(env);
app.UseCorrelationId();
app.UseHttpMetrics();
- app.UseProblemDetails();
app.UseCustomHealthCheck();
app.UseIdentityServer();
app.MapMetrics();
diff --git a/src/Services/Identity/src/Identity/Extensions/Infrastructure/ProblemDetailsExtensions.cs b/src/Services/Identity/src/Identity/Extensions/Infrastructure/ProblemDetailsExtensions.cs
index 829252b..c75dc07 100644
--- a/src/Services/Identity/src/Identity/Extensions/Infrastructure/ProblemDetailsExtensions.cs
+++ b/src/Services/Identity/src/Identity/Extensions/Infrastructure/ProblemDetailsExtensions.cs
@@ -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();
- return env.IsDevelopment() || env.IsStaging();
- };
- x.Map(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(ex => new ProblemDetailsWithCode
- {
- Title = ex.GetType().Name,
- Status = (int)ex.StatusCode,
- Detail = ex.Message,
- Type = "https://somedomain/input-validation-rules-error"
- });
- x.Map(ex => new ProblemDetailsWithCode
- {
- Title = ex.GetType().Name,
- Status = StatusCodes.Status400BadRequest,
- Detail = ex.Message,
- Type = "https://somedomain/bad-request-error"
- });
- x.Map(ex => new ProblemDetailsWithCode
- {
- Title = ex.GetType().Name,
- Status = StatusCodes.Status404NotFound,
- Detail = ex.Message,
- Type = "https://somedomain/not-found-error"
- });
- x.Map(ex => new ProblemDetailsWithCode
- {
- Title = ex.GetType().Name,
- Status = StatusCodes.Status500InternalServerError,
- Detail = ex.Message,
- Type = "https://somedomain/api-server-error"
- });
- x.Map(ex => new ProblemDetailsWithCode
- {
- Title = ex.GetType().Name,
- Status = StatusCodes.Status400BadRequest,
- Detail = ex.Message,
- Type = "https://somedomain/application-error"
- });
-
- x.Map(ex => new ProblemDetailsWithCode
- {
- Title = ex.GetType().Name,
- Status = StatusCodes.Status409Conflict,
- Detail = ex.Message,
- Type = "https://somedomain/db-update-concurrency-error"
- });
-
- x.MapToStatusCode(StatusCodes.Status400BadRequest);
-
- x.MapStatusCode = context =>
- {
- return context.Response.StatusCode switch
+ if (context.RequestServices.GetService() 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();
+ 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;
}
}
diff --git a/src/Services/Identity/src/Identity/Identity/Features/RegisteringNewUser/V1/RegisterNewUserEndpoint.cs b/src/Services/Identity/src/Identity/Identity/Features/RegisteringNewUser/V1/RegisterNewUserEndpoint.cs
index 86dd71c..1bfebfa 100644
--- a/src/Services/Identity/src/Identity/Identity/Features/RegisteringNewUser/V1/RegisterNewUserEndpoint.cs
+++ b/src/Services/Identity/src/Identity/Identity/Features/RegisteringNewUser/V1/RegisterNewUserEndpoint.cs
@@ -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()
+ .ProducesProblem(StatusCodes.Status400BadRequest)
.HasApiVersion(1.0);
return builder;
diff --git a/src/Services/Passenger/src/Passenger/Extensions/Infrastructure/InfrastructureExtensions.cs b/src/Services/Passenger/src/Passenger/Extensions/Infrastructure/InfrastructureExtensions.cs
index 8b58126..27faf7a 100644
--- a/src/Services/Passenger/src/Passenger/Extensions/Infrastructure/InfrastructureExtensions.cs
+++ b/src/Services/Passenger/src/Passenger/Extensions/Infrastructure/InfrastructureExtensions.cs
@@ -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(nameof(AppOptions));
- app.UseProblemDetails();
+ app.UseCustomProblemDetails();
app.UseSerilogRequestLogging(options =>
{
options.EnrichDiagnosticContext = LogEnrichHelper.EnrichFromRequest;
diff --git a/src/Services/Passenger/src/Passenger/Extensions/Infrastructure/ProblemDetailsExtensions.cs b/src/Services/Passenger/src/Passenger/Extensions/Infrastructure/ProblemDetailsExtensions.cs
index c785cee..dcad206 100644
--- a/src/Services/Passenger/src/Passenger/Extensions/Infrastructure/ProblemDetailsExtensions.cs
+++ b/src/Services/Passenger/src/Passenger/Extensions/Infrastructure/ProblemDetailsExtensions.cs
@@ -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();
- return env.IsDevelopment() || env.IsStaging();
- };
- x.Map(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(ex => new ProblemDetailsWithCode
- {
- Title = ex.GetType().Name,
- Status = (int)ex.StatusCode,
- Detail = ex.Message,
- Type = "https://somedomain/input-validation-rules-error"
- });
- x.Map(ex => new ProblemDetailsWithCode
- {
- Title = ex.GetType().Name,
- Status = StatusCodes.Status400BadRequest,
- Detail = ex.Message,
- Type = "https://somedomain/bad-request-error"
- });
- x.Map(ex => new ProblemDetailsWithCode
- {
- Title = ex.GetType().Name,
- Status = StatusCodes.Status404NotFound,
- Detail = ex.Message,
- Type = "https://somedomain/not-found-error"
- });
- x.Map(ex => new ProblemDetailsWithCode
- {
- Title = ex.GetType().Name,
- Status = StatusCodes.Status500InternalServerError,
- Detail = ex.Message,
- Type = "https://somedomain/api-server-error"
- });
- x.Map(ex => new ProblemDetailsWithCode
- {
- Title = ex.GetType().Name,
- Status = StatusCodes.Status400BadRequest,
- Detail = ex.Message,
- Type = "https://somedomain/application-error"
- });
-
- x.Map(ex => new ProblemDetailsWithCode
- {
- Title = ex.GetType().Name,
- Status = StatusCodes.Status409Conflict,
- Detail = ex.Message,
- Type = "https://somedomain/db-update-concurrency-error"
- });
-
- x.MapToStatusCode(StatusCodes.Status400BadRequest);
-
- x.MapStatusCode = context =>
- {
- return context.Response.StatusCode switch
+ if (context.RequestServices.GetService() 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();
+ 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;
}
}
diff --git a/src/Services/Passenger/src/Passenger/Passengers/Features/CompletingRegisterPassenger/V1/CompleteRegisterPassengerEndpoint.cs b/src/Services/Passenger/src/Passenger/Passengers/Features/CompletingRegisterPassenger/V1/CompleteRegisterPassengerEndpoint.cs
index 9327000..2c4cdc0 100644
--- a/src/Services/Passenger/src/Passenger/Passengers/Features/CompletingRegisterPassenger/V1/CompleteRegisterPassengerEndpoint.cs
+++ b/src/Services/Passenger/src/Passenger/Passengers/Features/CompletingRegisterPassenger/V1/CompleteRegisterPassengerEndpoint.cs
@@ -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()
+ .ProducesProblem(StatusCodes.Status400BadRequest)
.HasApiVersion(1.0);
return builder;
diff --git a/src/Services/Passenger/src/Passenger/Passengers/Features/GettingPassengerById/Queries/V1/GetPassengerByIdEndpoint.cs b/src/Services/Passenger/src/Passenger/Passengers/Features/GettingPassengerById/Queries/V1/GetPassengerByIdEndpoint.cs
index fe1e62d..c7184cd 100644
--- a/src/Services/Passenger/src/Passenger/Passengers/Features/GettingPassengerById/Queries/V1/GetPassengerByIdEndpoint.cs
+++ b/src/Services/Passenger/src/Passenger/Passengers/Features/GettingPassengerById/Queries/V1/GetPassengerByIdEndpoint.cs
@@ -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()
+ .ProducesProblem(StatusCodes.Status400BadRequest)
.HasApiVersion(1.0);
return builder;