From 64653f4fcd96958122a3e3ed313be84a63b05d33 Mon Sep 17 00:00:00 2001 From: XShine555 Date: Thu, 28 May 2026 21:53:46 +0200 Subject: [PATCH] validators --- WebApi/Endpoints/PlayListEndpoints.cs | 4 ++- WebApi/Endpoints/TrackEndpoints.cs | 4 ++- WebApi/Endpoints/UserEndpoints.cs | 4 ++- .../Extensions/ServiceCollectionExtensions.cs | 3 ++ WebApi/Filters/ValidationFilter.cs | 28 +++++++++++++++++ .../CreatePlayListRequestValidator.cs | 18 +++++++++++ ...stPlayListPictureUploadRequestValidator.cs | 20 +++++++++++++ .../UpdatePlayListRequestValidator.cs | 18 +++++++++++ .../Tracks/CreateTrackRequestValidator.cs | 20 +++++++++++++ .../RequestTrackUploadUrlsRequestValidator.cs | 30 +++++++++++++++++++ .../Users/CreateUserRequestValidator.cs | 25 ++++++++++++++++ WebApi/WebApi.csproj | 1 + 12 files changed, 172 insertions(+), 3 deletions(-) create mode 100644 WebApi/Filters/ValidationFilter.cs create mode 100644 WebApi/Validators/PlayLists/CreatePlayListRequestValidator.cs create mode 100644 WebApi/Validators/PlayLists/RequestPlayListPictureUploadRequestValidator.cs create mode 100644 WebApi/Validators/PlayLists/UpdatePlayListRequestValidator.cs create mode 100644 WebApi/Validators/Tracks/CreateTrackRequestValidator.cs create mode 100644 WebApi/Validators/Tracks/RequestTrackUploadUrlsRequestValidator.cs create mode 100644 WebApi/Validators/Users/CreateUserRequestValidator.cs diff --git a/WebApi/Endpoints/PlayListEndpoints.cs b/WebApi/Endpoints/PlayListEndpoints.cs index ab440d3..a85560c 100644 --- a/WebApi/Endpoints/PlayListEndpoints.cs +++ b/WebApi/Endpoints/PlayListEndpoints.cs @@ -3,6 +3,7 @@ using Musify.Application.PlayLists.Commands; using Musify.Application.PlayLists.Queries; using WebApi.DataTransferObjects.PlayLists; using WebApi.Extensions; +using WebApi.Filters; namespace WebApi.Endpoints; @@ -11,7 +12,8 @@ public static class PlayListEndpoints public static IEndpointRouteBuilder MapPlayListEndpoints(this IEndpointRouteBuilder app) { var group = app.MapGroup("/playlists") - .WithTags("PlayLists"); + .WithTags("PlayLists") + .AddEndpointFilter(); group.MapGet("/", GetPlayLists) .WithName("GetPlayLists") diff --git a/WebApi/Endpoints/TrackEndpoints.cs b/WebApi/Endpoints/TrackEndpoints.cs index 61171fe..c44e8f5 100644 --- a/WebApi/Endpoints/TrackEndpoints.cs +++ b/WebApi/Endpoints/TrackEndpoints.cs @@ -3,6 +3,7 @@ using Musify.Application.Tracks.Commands; using Musify.Application.Tracks.Queries; using WebApi.DataTransferObjects.Tracks; using WebApi.Extensions; +using WebApi.Filters; namespace WebApi.Endpoints; @@ -11,7 +12,8 @@ public static class TrackEndpoints public static IEndpointRouteBuilder MapTrackEndpoints(this IEndpointRouteBuilder app) { var group = app.MapGroup("/tracks") - .WithTags("Tracks"); + .WithTags("Tracks") + .AddEndpointFilter(); group.MapGet("/", GetTracks) .WithName("GetTracks") diff --git a/WebApi/Endpoints/UserEndpoints.cs b/WebApi/Endpoints/UserEndpoints.cs index 85d8326..d123eab 100644 --- a/WebApi/Endpoints/UserEndpoints.cs +++ b/WebApi/Endpoints/UserEndpoints.cs @@ -3,6 +3,7 @@ using Musify.Application.Users.Commands; using Musify.Application.Users.Queries; using WebApi.DataTransferObjects.Users; using WebApi.Extensions; +using WebApi.Filters; namespace WebApi.Endpoints; @@ -11,7 +12,8 @@ public static class UserEndpoints public static IEndpointRouteBuilder MapUserEndpoints(this IEndpointRouteBuilder app) { var group = app.MapGroup("/users") - .WithTags("Users"); + .WithTags("Users") + .AddEndpointFilter(); group.MapGet("/", GetUsers) .WithName("GetUsers") diff --git a/WebApi/Extensions/ServiceCollectionExtensions.cs b/WebApi/Extensions/ServiceCollectionExtensions.cs index e4fd603..c152a47 100644 --- a/WebApi/Extensions/ServiceCollectionExtensions.cs +++ b/WebApi/Extensions/ServiceCollectionExtensions.cs @@ -1,3 +1,4 @@ +using FluentValidation; using Mediator; using Musify.Application; using Musify.Infrastructure.MassTransit; @@ -6,6 +7,7 @@ using Musify.Infrastructure.Services; using OpenTelemetry.Logs; using OpenTelemetry.Metrics; using OpenTelemetry.Trace; +using WebApi.DataTransferObjects.PlayLists; using WebApi.Options; namespace WebApi.Extensions; @@ -21,6 +23,7 @@ public static class ServiceCollectionExtensions services.AddMassTransitClient(configuration); services.AddMediator(); services.AddOpenApi(); + services.AddValidatorsFromAssemblyContaining(); return services; } diff --git a/WebApi/Filters/ValidationFilter.cs b/WebApi/Filters/ValidationFilter.cs new file mode 100644 index 0000000..2f57d1f --- /dev/null +++ b/WebApi/Filters/ValidationFilter.cs @@ -0,0 +1,28 @@ +using FluentValidation; + +namespace WebApi.Filters; + +public sealed class ValidationFilter : IEndpointFilter +{ + public async ValueTask InvokeAsync(EndpointFilterInvocationContext context, EndpointFilterDelegate next) + { + foreach (var argument in context.Arguments) + { + if (argument is null) + continue; + + var validatorType = typeof(IValidator<>).MakeGenericType(argument.GetType()); + + if (context.HttpContext.RequestServices.GetService(validatorType) is not IValidator validator) + continue; + + var validationContext = new ValidationContext(argument); + var result = await validator.ValidateAsync(validationContext, context.HttpContext.RequestAborted); + + if (!result.IsValid) + return Results.ValidationProblem(result.ToDictionary()); + } + + return await next(context); + } +} diff --git a/WebApi/Validators/PlayLists/CreatePlayListRequestValidator.cs b/WebApi/Validators/PlayLists/CreatePlayListRequestValidator.cs new file mode 100644 index 0000000..83866f1 --- /dev/null +++ b/WebApi/Validators/PlayLists/CreatePlayListRequestValidator.cs @@ -0,0 +1,18 @@ +using FluentValidation; +using WebApi.DataTransferObjects.PlayLists; + +namespace WebApi.Validators.PlayLists; + +public sealed class CreatePlayListRequestValidator : AbstractValidator +{ + public CreatePlayListRequestValidator() + { + RuleFor(x => x.Name) + .NotEmpty() + .MaximumLength(50); + + RuleFor(x => x.Description) + .NotEmpty() + .MaximumLength(256); + } +} diff --git a/WebApi/Validators/PlayLists/RequestPlayListPictureUploadRequestValidator.cs b/WebApi/Validators/PlayLists/RequestPlayListPictureUploadRequestValidator.cs new file mode 100644 index 0000000..4729014 --- /dev/null +++ b/WebApi/Validators/PlayLists/RequestPlayListPictureUploadRequestValidator.cs @@ -0,0 +1,20 @@ +using FluentValidation; +using WebApi.DataTransferObjects.PlayLists; + +namespace WebApi.Validators.PlayLists; + +public sealed class RequestPlayListPictureUploadRequestValidator : AbstractValidator +{ + public RequestPlayListPictureUploadRequestValidator() + { + RuleFor(x => x.FileType) + .NotEmpty(); + + RuleFor(x => x.ContentType) + .NotEmpty(); + + RuleFor(x => x.ExpectedSizeBytes) + .GreaterThan(0) + .When(x => x.ExpectedSizeBytes.HasValue); + } +} diff --git a/WebApi/Validators/PlayLists/UpdatePlayListRequestValidator.cs b/WebApi/Validators/PlayLists/UpdatePlayListRequestValidator.cs new file mode 100644 index 0000000..855023f --- /dev/null +++ b/WebApi/Validators/PlayLists/UpdatePlayListRequestValidator.cs @@ -0,0 +1,18 @@ +using FluentValidation; +using WebApi.DataTransferObjects.PlayLists; + +namespace WebApi.Validators.PlayLists; + +public sealed class UpdatePlayListRequestValidator : AbstractValidator +{ + public UpdatePlayListRequestValidator() + { + RuleFor(x => x.NewName) + .MaximumLength(50) + .When(x => x.NewName is not null); + + RuleFor(x => x.NewDescription) + .MaximumLength(256) + .When(x => x.NewDescription is not null); + } +} diff --git a/WebApi/Validators/Tracks/CreateTrackRequestValidator.cs b/WebApi/Validators/Tracks/CreateTrackRequestValidator.cs new file mode 100644 index 0000000..4e1be9b --- /dev/null +++ b/WebApi/Validators/Tracks/CreateTrackRequestValidator.cs @@ -0,0 +1,20 @@ +using FluentValidation; +using WebApi.DataTransferObjects.Tracks; + +namespace WebApi.Validators.Tracks; + +public sealed class CreateTrackRequestValidator : AbstractValidator +{ + public CreateTrackRequestValidator() + { + RuleFor(x => x.Title) + .NotEmpty() + .MaximumLength(50); + + RuleFor(x => x.PictureIntentId) + .NotEmpty(); + + RuleFor(x => x.AudioIntentId) + .NotEmpty(); + } +} diff --git a/WebApi/Validators/Tracks/RequestTrackUploadUrlsRequestValidator.cs b/WebApi/Validators/Tracks/RequestTrackUploadUrlsRequestValidator.cs new file mode 100644 index 0000000..95c21f6 --- /dev/null +++ b/WebApi/Validators/Tracks/RequestTrackUploadUrlsRequestValidator.cs @@ -0,0 +1,30 @@ +using FluentValidation; +using WebApi.DataTransferObjects.Tracks; + +namespace WebApi.Validators.Tracks; + +public sealed class RequestTrackUploadUrlsRequestValidator : AbstractValidator +{ + public RequestTrackUploadUrlsRequestValidator() + { + RuleFor(x => x.PictureFileType) + .NotEmpty(); + + RuleFor(x => x.PictureContentType) + .NotEmpty(); + + RuleFor(x => x.AudioFileType) + .NotEmpty(); + + RuleFor(x => x.AudioContentType) + .NotEmpty(); + + RuleFor(x => x.ExpectedPictureSizeBytes) + .GreaterThan(0) + .When(x => x.ExpectedPictureSizeBytes.HasValue); + + RuleFor(x => x.ExpectedAudioSizeBytes) + .GreaterThan(0) + .When(x => x.ExpectedAudioSizeBytes.HasValue); + } +} diff --git a/WebApi/Validators/Users/CreateUserRequestValidator.cs b/WebApi/Validators/Users/CreateUserRequestValidator.cs new file mode 100644 index 0000000..c862481 --- /dev/null +++ b/WebApi/Validators/Users/CreateUserRequestValidator.cs @@ -0,0 +1,25 @@ +using FluentValidation; +using WebApi.DataTransferObjects.Users; + +namespace WebApi.Validators.Users; + +public sealed class CreateUserRequestValidator : AbstractValidator +{ + public CreateUserRequestValidator() + { + RuleFor(x => x.Id) + .NotEmpty(); + + RuleFor(x => x.Name) + .NotEmpty() + .MaximumLength(48); + + RuleFor(x => x.FirstName) + .MaximumLength(48) + .When(x => x.FirstName is not null); + + RuleFor(x => x.SecondName) + .MaximumLength(48) + .When(x => x.SecondName is not null); + } +} diff --git a/WebApi/WebApi.csproj b/WebApi/WebApi.csproj index 086f19f..6034122 100644 --- a/WebApi/WebApi.csproj +++ b/WebApi/WebApi.csproj @@ -10,6 +10,7 @@ +