Add fluent validation
This commit is contained in:
parent
d81f8eb46f
commit
ad6e0d2015
9 changed files with 118 additions and 22 deletions
|
@ -1,7 +1,9 @@
|
||||||
|
using System.Runtime.Intrinsics.X86;
|
||||||
using GitHubActionsDemo.Api.Models;
|
using GitHubActionsDemo.Api.Models;
|
||||||
using GitHubActionsDemo.Api.Mappers;
|
using GitHubActionsDemo.Api.Mappers;
|
||||||
using GitHubActionsDemo.Service;
|
using GitHubActionsDemo.Service;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using FluentValidation;
|
||||||
|
|
||||||
namespace GitHubActionsDemo.Api.Controllers;
|
namespace GitHubActionsDemo.Api.Controllers;
|
||||||
|
|
||||||
|
@ -10,42 +12,59 @@ namespace GitHubActionsDemo.Api.Controllers;
|
||||||
public class AuthorsController : BaseController
|
public class AuthorsController : BaseController
|
||||||
{
|
{
|
||||||
private readonly ILibraryService _libraryService;
|
private readonly ILibraryService _libraryService;
|
||||||
|
private readonly IValidator<AuthorRequest> _authorValidator;
|
||||||
|
private readonly IValidator<PageParameters> _pageValidator;
|
||||||
|
|
||||||
public AuthorsController(
|
public AuthorsController(
|
||||||
ILibraryService libraryService
|
ILibraryService libraryService,
|
||||||
|
IValidator<AuthorRequest> authorValidator,
|
||||||
|
IValidator<PageParameters> pageValidator
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
_libraryService = libraryService ?? throw new ArgumentNullException(nameof(libraryService));
|
_libraryService = libraryService ?? throw new ArgumentNullException(nameof(libraryService));
|
||||||
|
_authorValidator = authorValidator ?? throw new ArgumentNullException(nameof(authorValidator));
|
||||||
|
_pageValidator = pageValidator ?? throw new ArgumentNullException(nameof(pageValidator));
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpPost]
|
[HttpPost]
|
||||||
public async Task<IActionResult> AddAuthorAsync([FromBody] AuthorRequest authorRequest)
|
public async Task<IResult> AddAuthorAsync([FromBody] AuthorRequest authorRequest)
|
||||||
{
|
{
|
||||||
|
var validationResult = await _authorValidator.ValidateAsync(authorRequest);
|
||||||
|
|
||||||
|
if (!validationResult.IsValid)
|
||||||
|
return Results.ValidationProblem(validationResult.ToDictionary());
|
||||||
|
|
||||||
|
|
||||||
var result = await _libraryService.AddAuthorAsync(authorRequest.Map());
|
var result = await _libraryService.AddAuthorAsync(authorRequest.Map());
|
||||||
return result.Match(
|
return result.Match(
|
||||||
success => Ok(success.Value.Map()),
|
success => Results.Ok(success.Value.Map()),
|
||||||
error => InternalError()
|
error => InternalError()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpGet("{authorId}")]
|
[HttpGet("{authorId}")]
|
||||||
public async Task<IActionResult> GetAuthorAsync(int authorId)
|
public async Task<IResult> GetAuthorAsync(int authorId)
|
||||||
{
|
{
|
||||||
var result = await _libraryService.GetAuthorAsync(authorId);
|
var result = await _libraryService.GetAuthorAsync(authorId);
|
||||||
return result.Match(
|
return result.Match(
|
||||||
success => Ok(success.Value.Map()),
|
success => Results.Ok(success.Value.Map()),
|
||||||
notfound => NotFound(),
|
notfound => Results.NotFound(),
|
||||||
error => InternalError()
|
error => InternalError()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpGet]
|
[HttpGet]
|
||||||
public async Task<IActionResult> GetAuthorsAsync([FromQuery(Name = "page")] int page = 1, [FromQuery(Name = "pageSize")] int pageSize = 10)
|
public async Task<IResult> GetAuthorsAsync([FromQuery] PageParameters parameters)
|
||||||
{
|
{
|
||||||
var result = await _libraryService.GetAuthorsAsync(page, pageSize);
|
var validationResult = await _pageValidator.ValidateAsync(parameters);
|
||||||
|
|
||||||
|
if (!validationResult.IsValid)
|
||||||
|
return Results.ValidationProblem(validationResult.ToDictionary());
|
||||||
|
|
||||||
|
var result = await _libraryService.GetAuthorsAsync(parameters.Page, parameters.PageSize);
|
||||||
|
|
||||||
return result.Match(
|
return result.Match(
|
||||||
success => PagedResult(page, pageSize, success.Value.Select(x => x.Map()).ToList()),
|
success => PagedResult(parameters.Page, parameters.PageSize, success.Value.Select(x => x.Map()).ToList()),
|
||||||
error => InternalError()
|
error => InternalError()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,13 +7,13 @@ namespace GitHubActionsDemo.Api.Controllers;
|
||||||
|
|
||||||
public class BaseController : ControllerBase
|
public class BaseController : ControllerBase
|
||||||
{
|
{
|
||||||
public IActionResult InternalError()
|
public IResult InternalError()
|
||||||
{
|
{
|
||||||
return new StatusCodeResult((int)HttpStatusCode.InternalServerError);
|
return Results.StatusCode((int)HttpStatusCode.InternalServerError);
|
||||||
}
|
}
|
||||||
|
|
||||||
public IActionResult PagedResult<T>(int page, int pageSize, T result) where T : IList
|
public IResult PagedResult<T>(int page, int pageSize, T result) where T : IList
|
||||||
{
|
{
|
||||||
return Ok(new PagedResponse<T>(page, pageSize, result));
|
return Results.Ok(new PagedResponse<T>(page, pageSize, result));
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -2,6 +2,7 @@ using GitHubActionsDemo.Api.Models;
|
||||||
using GitHubActionsDemo.Api.Mappers;
|
using GitHubActionsDemo.Api.Mappers;
|
||||||
using GitHubActionsDemo.Service;
|
using GitHubActionsDemo.Service;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using FluentValidation;
|
||||||
|
|
||||||
namespace GitHubActionsDemo.Api.Controllers;
|
namespace GitHubActionsDemo.Api.Controllers;
|
||||||
|
|
||||||
|
@ -10,42 +11,58 @@ namespace GitHubActionsDemo.Api.Controllers;
|
||||||
public class BooksController : BaseController
|
public class BooksController : BaseController
|
||||||
{
|
{
|
||||||
private readonly ILibraryService _libraryService;
|
private readonly ILibraryService _libraryService;
|
||||||
|
private readonly IValidator<BookRequest> _bookValidator;
|
||||||
|
private readonly IValidator<PageParameters> _pageValidator;
|
||||||
|
|
||||||
public BooksController(
|
public BooksController(
|
||||||
ILibraryService libraryService
|
ILibraryService libraryService,
|
||||||
|
IValidator<BookRequest> bookValidator,
|
||||||
|
IValidator<PageParameters> pageValidator
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
_libraryService = libraryService ?? throw new ArgumentNullException(nameof(libraryService));
|
_libraryService = libraryService ?? throw new ArgumentNullException(nameof(libraryService));
|
||||||
|
_bookValidator = bookValidator ?? throw new ArgumentNullException(nameof(bookValidator));
|
||||||
|
_pageValidator = pageValidator ?? throw new ArgumentNullException(nameof(pageValidator));
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpGet]
|
[HttpGet]
|
||||||
public async Task<IActionResult> GetBooksAsync([FromQuery(Name = "page")] int page = 1, [FromQuery(Name = "pageSize")] int pageSize = 10)
|
public async Task<IResult> GetBooksAsync([FromQuery] PageParameters parameters)
|
||||||
{
|
{
|
||||||
var result = await _libraryService.GetBooksAsync(page, pageSize);
|
var validationResult = await _pageValidator.ValidateAsync(parameters);
|
||||||
|
|
||||||
|
if (!validationResult.IsValid)
|
||||||
|
return Results.ValidationProblem(validationResult.ToDictionary());
|
||||||
|
|
||||||
|
var result = await _libraryService.GetBooksAsync(parameters.Page, parameters.PageSize);
|
||||||
|
|
||||||
return result.Match(
|
return result.Match(
|
||||||
success => PagedResult(page, pageSize, success.Value.Select(x => x.Map()).ToList()),
|
success => PagedResult(parameters.Page, parameters.PageSize, success.Value.Select(x => x.Map()).ToList()),
|
||||||
error => InternalError()
|
error => InternalError()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpGet("{bookId}")]
|
[HttpGet("{bookId}")]
|
||||||
public async Task<IActionResult> GetBookAsync(int bookId)
|
public async Task<IResult> GetBookAsync(int bookId)
|
||||||
{
|
{
|
||||||
var result = await _libraryService.GetBookAsync(bookId);
|
var result = await _libraryService.GetBookAsync(bookId);
|
||||||
return result.Match(
|
return result.Match(
|
||||||
success => Ok(success.Value.Map()),
|
success => Results.Ok(success.Value.Map()),
|
||||||
notfound => NotFound(),
|
notfound => Results.NotFound(),
|
||||||
error => InternalError()
|
error => InternalError()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpPost]
|
[HttpPost]
|
||||||
public async Task<IActionResult> AddBookAsync([FromBody] BookRequest bookRequest)
|
public async Task<IResult> AddBookAsync([FromBody] BookRequest bookRequest)
|
||||||
{
|
{
|
||||||
|
var validationResult = await _bookValidator.ValidateAsync(bookRequest);
|
||||||
|
|
||||||
|
if (!validationResult.IsValid)
|
||||||
|
return Results.ValidationProblem(validationResult.ToDictionary());
|
||||||
|
|
||||||
var result = await _libraryService.AddBookAsync(bookRequest.Map());
|
var result = await _libraryService.AddBookAsync(bookRequest.Map());
|
||||||
return result.Match(
|
return result.Match(
|
||||||
success => Ok(success.Value.Map()),
|
success => Results.Ok(success.Value.Map()),
|
||||||
error => InternalError()
|
error => InternalError()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<PackageReference Include="FluentValidation" Version="11.5.2" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="7.0.5" />
|
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="7.0.5" />
|
||||||
<PackageReference Include="OneOf" Version="3.0.255" />
|
<PackageReference Include="OneOf" Version="3.0.255" />
|
||||||
<PackageReference Include="Serilog" Version="3.0.1" />
|
<PackageReference Include="Serilog" Version="3.0.1" />
|
||||||
|
|
7
src/GitHubActionsDemo.Api/Models/PageParameters.cs
Normal file
7
src/GitHubActionsDemo.Api/Models/PageParameters.cs
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
namespace GitHubActionsDemo.Api.Models;
|
||||||
|
|
||||||
|
public class PageParameters
|
||||||
|
{
|
||||||
|
public int Page { get; set; } = 1;
|
||||||
|
public int PageSize { get; set; } = 10;
|
||||||
|
}
|
|
@ -0,0 +1,12 @@
|
||||||
|
using FluentValidation;
|
||||||
|
|
||||||
|
namespace GitHubActionsDemo.Api.Models.Validators;
|
||||||
|
|
||||||
|
public class AuthorRequestValidator : AbstractValidator<AuthorRequest>
|
||||||
|
{
|
||||||
|
public AuthorRequestValidator()
|
||||||
|
{
|
||||||
|
RuleFor(x => x.FirstName).NotEmpty();
|
||||||
|
RuleFor(x => x.LastName).NotEmpty();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,21 @@
|
||||||
|
using FluentValidation;
|
||||||
|
|
||||||
|
namespace GitHubActionsDemo.Api.Models.Validators;
|
||||||
|
|
||||||
|
public class BookRequestValidator : AbstractValidator<BookRequest>
|
||||||
|
{
|
||||||
|
public BookRequestValidator()
|
||||||
|
{
|
||||||
|
RuleFor(x => x.Title).NotEmpty();
|
||||||
|
RuleFor(x => x.AuthorId).NotEmpty();
|
||||||
|
|
||||||
|
RuleFor(x => x.Isbn)
|
||||||
|
.NotEmpty()
|
||||||
|
.MinimumLength(10)
|
||||||
|
.MaximumLength(17)
|
||||||
|
.Matches(@"^(?:ISBN(?:-1[03])?:? )?(?=[0-9X]{10}$|(?=(?:[0-9]+[- ]){3})[- 0 - 9X]{ 13}$| 97[89][0 - 9]{ 10}$| (?= (?:[0 - 9] +[- ]){ 4})[- 0 - 9]{ 17}$)(?: 97[89][- ] ?)?[0 - 9]{ 1,5}[- ]?[0 - 9]+[- ]?[0 - 9] +[- ]?[0 - 9X]$");
|
||||||
|
|
||||||
|
RuleFor(x => x.DatePublished)
|
||||||
|
.NotEmpty();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,12 @@
|
||||||
|
using FluentValidation;
|
||||||
|
|
||||||
|
namespace GitHubActionsDemo.Api.Models.Validators;
|
||||||
|
|
||||||
|
public class PageParametersValidator : AbstractValidator<PageParameters>
|
||||||
|
{
|
||||||
|
public PageParametersValidator()
|
||||||
|
{
|
||||||
|
RuleFor(x => x.Page).GreaterThan(0);
|
||||||
|
RuleFor(x => x.PageSize).InclusiveBetween(1, 100);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,6 +1,9 @@
|
||||||
using GitHubActionsDemo.Service.Infrastructure;
|
using GitHubActionsDemo.Service.Infrastructure;
|
||||||
using GitHubActionsDemo.Persistance.Infrastructure;
|
using GitHubActionsDemo.Persistance.Infrastructure;
|
||||||
using Serilog;
|
using Serilog;
|
||||||
|
using FluentValidation;
|
||||||
|
using GitHubActionsDemo.Api.Models;
|
||||||
|
using GitHubActionsDemo.Api.Models.Validators;
|
||||||
|
|
||||||
var builder = WebApplication.CreateBuilder(args);
|
var builder = WebApplication.CreateBuilder(args);
|
||||||
|
|
||||||
|
@ -10,6 +13,10 @@ var logger = new LoggerConfiguration()
|
||||||
.CreateLogger();
|
.CreateLogger();
|
||||||
builder.Logging.AddSerilog(logger);
|
builder.Logging.AddSerilog(logger);
|
||||||
|
|
||||||
|
builder.Services.AddScoped<IValidator<AuthorRequest>, AuthorRequestValidator>();
|
||||||
|
builder.Services.AddScoped<IValidator<BookRequest>, BookRequestValidator>();
|
||||||
|
builder.Services.AddScoped<IValidator<PageParameters>, PageParametersValidator>();
|
||||||
|
|
||||||
builder.Services.AddControllers();
|
builder.Services.AddControllers();
|
||||||
builder.Services.AddEndpointsApiExplorer();
|
builder.Services.AddEndpointsApiExplorer();
|
||||||
builder.Services.AddSwaggerGen();
|
builder.Services.AddSwaggerGen();
|
||||||
|
|
Loading…
Reference in a new issue