mirror of
https://github.com/collinbarrett/FilterLists.git
synced 2026-03-11 09:04:27 +00:00
feat(dir): ✨ validate list details query id
This commit is contained in:
parent
5775cc3274
commit
0ad50629d5
8 changed files with 77 additions and 1 deletions
|
|
@ -28,6 +28,7 @@
|
|||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Hellang.Middleware.ProblemDetails" Version="6.2.0" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="6.0.0">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,29 @@
|
|||
using FluentValidation;
|
||||
using Hellang.Middleware.ProblemDetails;
|
||||
|
||||
namespace FilterLists.Directory.Api;
|
||||
|
||||
internal static class ProblemDetailsConfigurationExtensions
|
||||
{
|
||||
public static void ConfigureProblemDetails(this ProblemDetailsOptions options)
|
||||
{
|
||||
options.MapFluentValidationException();
|
||||
options.MapToStatusCode<NotImplementedException>(StatusCodes.Status501NotImplemented);
|
||||
options.MapToStatusCode<HttpRequestException>(StatusCodes.Status503ServiceUnavailable);
|
||||
options.MapToStatusCode<Exception>(StatusCodes.Status500InternalServerError);
|
||||
}
|
||||
|
||||
private static void MapFluentValidationException(this ProblemDetailsOptions options)
|
||||
{
|
||||
options.Map<ValidationException>((ctx, ex) =>
|
||||
{
|
||||
var factory = ctx.RequestServices.GetRequiredService<ProblemDetailsFactory>();
|
||||
var errors = ex.Errors
|
||||
.GroupBy(f => f.PropertyName)
|
||||
.ToDictionary(
|
||||
g => g.Key,
|
||||
g => g.Select(f => f.ErrorMessage).ToArray());
|
||||
return factory.CreateValidationProblemDetails(ctx, errors);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -3,13 +3,17 @@
|
|||
using FilterLists.Directory.Application;
|
||||
using FilterLists.Directory.Infrastructure.Persistence;
|
||||
using FilterLists.SharedKernel.Logging;
|
||||
using Hellang.Middleware.ProblemDetails;
|
||||
using Hellang.Middleware.ProblemDetails.Mvc;
|
||||
|
||||
var builder = WebApplication.CreateBuilder(args);
|
||||
|
||||
builder.Host.ConfigureApplication();
|
||||
builder.Services.AddMemoryCache();
|
||||
builder.Services.AddProblemDetails(ProblemDetailsConfigurationExtensions.ConfigureProblemDetails);
|
||||
builder.Services.Configure<RouteOptions>(options => options.LowercaseUrls = true);
|
||||
builder.Services.AddControllers()
|
||||
.AddProblemDetailsConventions()
|
||||
.AddJsonOptions(o => o.JsonSerializerOptions.DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull);
|
||||
builder.Services.AddEndpointsApiExplorer();
|
||||
builder.Services.AddSwaggerGen();
|
||||
|
|
@ -19,6 +23,7 @@
|
|||
|
||||
app.UseApplication();
|
||||
app.UseExceptionHandler(app.Environment.IsDevelopment() ? "/error-local-development" : "/error");
|
||||
app.UseProblemDetails();
|
||||
app.UseSwagger();
|
||||
app.MapControllers();
|
||||
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
namespace FilterLists.Directory.Api;
|
||||
|
||||
internal static class SwaggerExtensions
|
||||
internal static class SwaggerConfigurationExtensions
|
||||
{
|
||||
public static void AddSwaggerGen(this IServiceCollection services)
|
||||
{
|
||||
|
|
@ -1,4 +1,5 @@
|
|||
using FilterLists.Directory.Infrastructure;
|
||||
using FluentValidation;
|
||||
using MediatR;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
|
|
@ -17,6 +18,8 @@ public static IHostBuilder ConfigureApplication(this IHostBuilder hostBuilder)
|
|||
public static void AddApplication(this IServiceCollection services, IConfiguration configuration)
|
||||
{
|
||||
services.AddMediatR(typeof(ConfigurationExtensions).Assembly);
|
||||
services.AddTransient(typeof(IPipelineBehavior<,>), typeof(ValidatorPipelineBehavior<,>));
|
||||
services.AddValidatorsFromAssembly(typeof(ConfigurationExtensions).Assembly, includeInternalTypes: true);
|
||||
services.AddAutoMapper(typeof(ConfigurationExtensions).Assembly);
|
||||
services.AddInfrastructure(configuration);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@
|
|||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="AutoMapper.Extensions.Microsoft.DependencyInjection" Version="8.1.1" />
|
||||
<PackageReference Include="FluentValidation.DependencyInjectionExtensions" Version="10.3.4" />
|
||||
<PackageReference Include="MediatR.Extensions.Microsoft.DependencyInjection" Version="9.0.0" />
|
||||
</ItemGroup>
|
||||
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
using FilterLists.Directory.Api.Contracts.Models;
|
||||
using FilterLists.Directory.Infrastructure.Persistence.Queries.Context;
|
||||
using FilterLists.Directory.Infrastructure.Persistence.Queries.Entities;
|
||||
using FluentValidation;
|
||||
using MediatR;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
|
|
@ -12,6 +13,15 @@ public static class GetListDetails
|
|||
{
|
||||
public record Query(int Id) : IRequest<ListDetailsVm?>;
|
||||
|
||||
internal class Validator : AbstractValidator<Query>
|
||||
{
|
||||
public Validator()
|
||||
{
|
||||
RuleFor(q => q.Id)
|
||||
.GreaterThanOrEqualTo(0);
|
||||
}
|
||||
}
|
||||
|
||||
internal class Handler : IRequestHandler<Query, ListDetailsVm?>
|
||||
{
|
||||
private readonly IQueryContext _context;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,27 @@
|
|||
using FluentValidation;
|
||||
using MediatR;
|
||||
|
||||
namespace FilterLists.Directory.Application;
|
||||
|
||||
internal class ValidatorPipelineBehavior<TRequest, TResponse> : IPipelineBehavior<TRequest, TResponse>
|
||||
where TRequest : notnull
|
||||
{
|
||||
private readonly IEnumerable<IValidator<TRequest>> _validators;
|
||||
|
||||
public ValidatorPipelineBehavior(IEnumerable<IValidator<TRequest>> validators)
|
||||
{
|
||||
_validators = validators;
|
||||
}
|
||||
|
||||
public Task<TResponse> Handle(TRequest request,
|
||||
CancellationToken cancellationToken,
|
||||
RequestHandlerDelegate<TResponse> next)
|
||||
{
|
||||
foreach (var validator in _validators)
|
||||
{
|
||||
validator.ValidateAndThrow(request);
|
||||
}
|
||||
|
||||
return next();
|
||||
}
|
||||
}
|
||||
Loading…
Reference in a new issue