diff --git a/src/Tests/SystemTests/Weather.API.SystemTests/WeatherSystemTests.cs b/src/Tests/SystemTests/Weather.API.SystemTests/WeatherSystemTests.cs index c122239..1b27a06 100644 --- a/src/Tests/SystemTests/Weather.API.SystemTests/WeatherSystemTests.cs +++ b/src/Tests/SystemTests/Weather.API.SystemTests/WeatherSystemTests.cs @@ -1,9 +1,9 @@ using Microsoft.AspNetCore.Mvc.Testing; using Newtonsoft.Json; +using SmallApiToolkit.Core.Response; using System.Text; using Weather.Domain.Commands; using Weather.Domain.Dtos; -using Weather.Domain.Http; namespace Weather.API.SystemTests { diff --git a/src/Tests/UnitTests/Weather.Core.UnitTests/Commands/AddFavoriteHandlerTests.cs b/src/Tests/UnitTests/Weather.Core.UnitTests/Commands/AddFavoriteHandlerTests.cs index f609c4a..5f42bc2 100644 --- a/src/Tests/UnitTests/Weather.Core.UnitTests/Commands/AddFavoriteHandlerTests.cs +++ b/src/Tests/UnitTests/Weather.Core.UnitTests/Commands/AddFavoriteHandlerTests.cs @@ -1,4 +1,6 @@ -using Weather.Core.Abstractions; +using SmallApiToolkit.Core.RequestHandlers; +using SmallApiToolkit.Core.Validation; +using Weather.Core.Abstractions; using Weather.Core.Commands; using Weather.Core.Resources; using Weather.Domain.Commands; @@ -10,15 +12,15 @@ namespace Weather.Core.UnitTests.Commands public class AddFavoriteHandlerTests { private readonly Mock _weatherCommandsRepositoryMock; - private readonly Mock> _addFavoriteCommandValidatorMock; - private readonly Mock> _loggerMock; + private readonly Mock> _addFavoriteCommandValidatorMock; + private readonly Mock> _loggerMock; - private readonly IAddFavoriteHandler _uut; + private readonly IHttpRequestHandler _uut; public AddFavoriteHandlerTests() { - _weatherCommandsRepositoryMock = new Mock(); - _addFavoriteCommandValidatorMock = new Mock>(); - _loggerMock = new Mock>(); + _weatherCommandsRepositoryMock = new(); + _addFavoriteCommandValidatorMock = new(); + _loggerMock = new(); _uut = new AddFavoriteHandler(_weatherCommandsRepositoryMock.Object, _addFavoriteCommandValidatorMock.Object, _loggerMock.Object); } @@ -30,7 +32,7 @@ public async Task InvalidLocation() //Arrange var addFavoriteCommand = new AddFavoriteCommand { Location = new Domain.Dtos.LocationDto { Latitude = 1, Longitude = 1 } }; - _addFavoriteCommandValidatorMock.Setup(x => x.IsValid(It.IsAny())).Returns(false); + _addFavoriteCommandValidatorMock.Setup(x => x.Validate(It.IsAny())).Returns(new RequestValidationResult { IsValid = false}); //Act var result = await _uut.HandleAsync(addFavoriteCommand, CancellationToken.None); @@ -38,7 +40,7 @@ public async Task InvalidLocation() //Assert Assert.Equal(HttpStatusCode.BadRequest, result.StatusCode); Assert.Single(result.Errors); - _addFavoriteCommandValidatorMock.Verify(x => x.IsValid(It.Is(y => y.Equals(addFavoriteCommand))), Times.Once); + _addFavoriteCommandValidatorMock.Verify(x => x.Validate(It.Is(y => y.Equals(addFavoriteCommand))), Times.Once); } [Fact] @@ -48,7 +50,7 @@ public async Task AddFavoriteLocation_Failed() var addFavoriteCommand = new AddFavoriteCommand { Location = new Domain.Dtos.LocationDto { Latitude = 1, Longitude = 1 } }; var errorMessage = "errorMessage"; - _addFavoriteCommandValidatorMock.Setup(x => x.IsValid(It.IsAny())).Returns(true); + _addFavoriteCommandValidatorMock.Setup(x => x.Validate(It.IsAny())).Returns(new RequestValidationResult { IsValid = true }); _weatherCommandsRepositoryMock.Setup(x => x.AddFavoriteLocation(It.IsAny(), It.IsAny())).ReturnsAsync(Result.Fail(errorMessage)); //Act @@ -58,7 +60,7 @@ public async Task AddFavoriteLocation_Failed() Assert.Equal(HttpStatusCode.InternalServerError, result.StatusCode); Assert.Single(result.Errors); Assert.Equal(ErrorMessages.CantStoreLocation, result.Errors.Single()); - _addFavoriteCommandValidatorMock.Verify(x => x.IsValid(It.Is(y => y.Equals(addFavoriteCommand))), Times.Once); + _addFavoriteCommandValidatorMock.Verify(x => x.Validate(It.Is(y => y.Equals(addFavoriteCommand))), Times.Once); _weatherCommandsRepositoryMock.Verify(x => x.AddFavoriteLocation(It.Is(y=>y.Equals(addFavoriteCommand)), It.IsAny()), Times.Once); _loggerMock.VerifyLog(LogLevel.Error, LogEvents.FavoriteWeathersStoreToDatabase, errorMessage, Times.Once()); } @@ -70,7 +72,7 @@ public async Task Success() var addFavoriteCommand = new AddFavoriteCommand { Location = new Domain.Dtos.LocationDto { Latitude = 1, Longitude = 1 } }; var locationId = 1; - _addFavoriteCommandValidatorMock.Setup(x => x.IsValid(It.IsAny())).Returns(true); + _addFavoriteCommandValidatorMock.Setup(x => x.Validate(It.IsAny())).Returns(new RequestValidationResult { IsValid = true }); _weatherCommandsRepositoryMock.Setup(x => x.AddFavoriteLocation(It.IsAny(), It.IsAny())).ReturnsAsync(Result.Ok(locationId)); //Act @@ -80,7 +82,7 @@ public async Task Success() Assert.Equal(HttpStatusCode.OK, result.StatusCode); Assert.Empty(result.Errors); Assert.Equal(locationId, result.Data); - _addFavoriteCommandValidatorMock.Verify(x => x.IsValid(It.Is(y => y.Equals(addFavoriteCommand))), Times.Once); + _addFavoriteCommandValidatorMock.Verify(x => x.Validate(It.Is(y => y.Equals(addFavoriteCommand))), Times.Once); _weatherCommandsRepositoryMock.Verify(x => x.AddFavoriteLocation(It.Is(y => y.Equals(addFavoriteCommand)), It.IsAny()), Times.Once); } } diff --git a/src/Tests/UnitTests/Weather.Core.UnitTests/Commands/DeleteFavoriteHandlerTests.cs b/src/Tests/UnitTests/Weather.Core.UnitTests/Commands/DeleteFavoriteHandlerTests.cs index cb2f878..6e1bf15 100644 --- a/src/Tests/UnitTests/Weather.Core.UnitTests/Commands/DeleteFavoriteHandlerTests.cs +++ b/src/Tests/UnitTests/Weather.Core.UnitTests/Commands/DeleteFavoriteHandlerTests.cs @@ -1,4 +1,6 @@ -using Weather.Core.Abstractions; +using SmallApiToolkit.Core.RequestHandlers; +using SmallApiToolkit.Core.Validation; +using Weather.Core.Abstractions; using Weather.Core.Commands; using Weather.Domain.Commands; @@ -7,9 +9,9 @@ namespace Weather.Core.UnitTests.Commands public class DeleteFavoriteHandlerTests { private readonly Mock _weatherCommandsRepositoryMock; - private readonly Mock> _validatorMock; + private readonly Mock> _validatorMock; - private readonly IDeleteFavoriteHandler _uut; + private readonly IHttpRequestHandler _uut; public DeleteFavoriteHandlerTests() { _weatherCommandsRepositoryMock = new(); @@ -24,7 +26,7 @@ public async Task InvalidRequest() //Arrange var deleteFavoriteCommand = new DeleteFavoriteCommand { Id = 5 }; - _validatorMock.Setup(x => x.IsValid(It.IsAny())).Returns(false); + _validatorMock.Setup(x => x.Validate(It.IsAny())).Returns(new RequestValidationResult { IsValid = false}); //Act var result = await _uut.HandleAsync(deleteFavoriteCommand, CancellationToken.None); @@ -32,7 +34,7 @@ public async Task InvalidRequest() //Assert Assert.Equal(HttpStatusCode.BadRequest, result.StatusCode); Assert.Single(result.Errors); - _validatorMock.Verify(x => x.IsValid(It.Is(y => y.Equals(deleteFavoriteCommand))), Times.Once); + _validatorMock.Verify(x => x.Validate(It.Is(y => y.Equals(deleteFavoriteCommand))), Times.Once); } [Fact] @@ -40,8 +42,8 @@ public async Task DeleteFavoriteLocationSafeAsync_Failed() { //Arrange var deleteFavoriteCommand = new DeleteFavoriteCommand { Id = 5 }; - - _validatorMock.Setup(x => x.IsValid(deleteFavoriteCommand)).Returns(true); + + _validatorMock.Setup(x => x.Validate(It.IsAny())).Returns(new RequestValidationResult { IsValid = true }); _weatherCommandsRepositoryMock.Setup(x => x.DeleteFavoriteLocationSafeAsync(deleteFavoriteCommand, CancellationToken.None)) .ReturnsAsync(Result.Fail(string.Empty)); @@ -51,7 +53,7 @@ public async Task DeleteFavoriteLocationSafeAsync_Failed() //Assert Assert.Equal(HttpStatusCode.InternalServerError, result.StatusCode); Assert.Single(result.Errors); - _validatorMock.Verify(x => x.IsValid(deleteFavoriteCommand), Times.Once); + _validatorMock.Verify(x => x.Validate(deleteFavoriteCommand), Times.Once); _weatherCommandsRepositoryMock.Verify(x => x.DeleteFavoriteLocationSafeAsync(deleteFavoriteCommand, CancellationToken.None), Times.Once); } @@ -61,7 +63,7 @@ public async Task DeleteFavoriteLocationSafeAsync_Success() //Arrange var deleteFavoriteCommand = new DeleteFavoriteCommand { Id = 5 }; - _validatorMock.Setup(x => x.IsValid(deleteFavoriteCommand)).Returns(true); + _validatorMock.Setup(x => x.Validate(It.IsAny())).Returns(new RequestValidationResult { IsValid = true }); _weatherCommandsRepositoryMock.Setup(x => x.DeleteFavoriteLocationSafeAsync(deleteFavoriteCommand, CancellationToken.None)) .ReturnsAsync(Result.Ok()); @@ -71,7 +73,7 @@ public async Task DeleteFavoriteLocationSafeAsync_Success() //Assert Assert.Equal(HttpStatusCode.OK, result.StatusCode); Assert.Empty(result.Errors); - _validatorMock.Verify(x => x.IsValid(deleteFavoriteCommand), Times.Once); + _validatorMock.Verify(x => x.Validate(deleteFavoriteCommand), Times.Once); _weatherCommandsRepositoryMock.Verify(x => x.DeleteFavoriteLocationSafeAsync(deleteFavoriteCommand, CancellationToken.None), Times.Once); } } diff --git a/src/Tests/UnitTests/Weather.Core.UnitTests/Queries/GetCurrentWeatherHandlerTests.cs b/src/Tests/UnitTests/Weather.Core.UnitTests/Queries/GetCurrentWeatherHandlerTests.cs index 46d217b..279a541 100644 --- a/src/Tests/UnitTests/Weather.Core.UnitTests/Queries/GetCurrentWeatherHandlerTests.cs +++ b/src/Tests/UnitTests/Weather.Core.UnitTests/Queries/GetCurrentWeatherHandlerTests.cs @@ -1,4 +1,6 @@ -using Validot.Results; +using SmallApiToolkit.Core.RequestHandlers; +using SmallApiToolkit.Core.Validation; +using Validot.Results; using Weather.Core.Abstractions; using Weather.Core.Queries; using Weather.Core.Resources; @@ -11,18 +13,18 @@ namespace Weather.Core.UnitTests.Queries { public class GetCurrentWeatherHandlerTests { - private readonly Mock> _getCurrentWeatherQueryValidatorMock; - private readonly Mock> _currentWeatherValidatorMock; + private readonly Mock> _getCurrentWeatherQueryValidatorMock; + private readonly Mock> _currentWeatherValidatorMock; private readonly Mock _weatherServiceMock; - private readonly Mock> _loggerMock; + private readonly Mock> _loggerMock; - private readonly IGetCurrentWeatherHandler _uut; + private readonly IHttpRequestHandler _uut; public GetCurrentWeatherHandlerTests() { - _getCurrentWeatherQueryValidatorMock = new Mock>(); - _currentWeatherValidatorMock = new Mock>(); - _weatherServiceMock = new Mock(); - _loggerMock = new Mock>(); + _getCurrentWeatherQueryValidatorMock = new(); + _currentWeatherValidatorMock = new(); + _weatherServiceMock = new(); + _loggerMock = new(); _uut = new GetCurrentWeatherHandler(_getCurrentWeatherQueryValidatorMock.Object, _currentWeatherValidatorMock.Object, _weatherServiceMock.Object, _loggerMock.Object); } @@ -33,7 +35,7 @@ public async Task InvalidLocation() //Arrange var getCurrentWeatherQuery = new GetCurrentWeatherQuery(1,1); - _getCurrentWeatherQueryValidatorMock.Setup(x => x.IsValid(It.IsAny())).Returns(false); + _getCurrentWeatherQueryValidatorMock.Setup(x => x.Validate(It.IsAny())).Returns(new RequestValidationResult { IsValid = false}); //Act var result = await _uut.HandleAsync(getCurrentWeatherQuery, CancellationToken.None); @@ -42,7 +44,7 @@ public async Task InvalidLocation() Assert.Equal(HttpStatusCode.BadRequest, result.StatusCode); Assert.Single(result.Errors); Assert.Null(result.Data); - _getCurrentWeatherQueryValidatorMock.Verify(x => x.IsValid(It.Is(y => y.Equals(getCurrentWeatherQuery))), Times.Once); + _getCurrentWeatherQueryValidatorMock.Verify(x => x.Validate(It.Is(y => y.Equals(getCurrentWeatherQuery))), Times.Once); } [Fact] @@ -52,7 +54,7 @@ public async Task GetCurrentWeather_Failed() var errorMessage = "error"; var getCurrentWeatherQuery = new GetCurrentWeatherQuery(1, 1); - _getCurrentWeatherQueryValidatorMock.Setup(x => x.IsValid(It.IsAny())).Returns(true); + _getCurrentWeatherQueryValidatorMock.Setup(x => x.Validate(It.IsAny())).Returns(new RequestValidationResult { IsValid = true }); _weatherServiceMock.Setup(x=>x.GetCurrentWeather(It.IsAny(), It.IsAny())).ReturnsAsync(Result.Fail(errorMessage)); //Act var result = await _uut.HandleAsync(getCurrentWeatherQuery, CancellationToken.None); @@ -62,7 +64,7 @@ public async Task GetCurrentWeather_Failed() Assert.Single(result.Errors); Assert.Equal(ErrorMessages.ExternalApiError, result.Errors.Single()); Assert.Null(result.Data); - _getCurrentWeatherQueryValidatorMock.Verify(x => x.IsValid(It.Is(y => y.Equals(getCurrentWeatherQuery))), Times.Once); + _getCurrentWeatherQueryValidatorMock.Verify(x => x.Validate(It.Is(y => y.Equals(getCurrentWeatherQuery))), Times.Once); _weatherServiceMock.Verify(x => x.GetCurrentWeather(It.Is(y => y.Equals(getCurrentWeatherQuery.Location)), It.IsAny()), Times.Once); _loggerMock.VerifyLog(LogLevel.Error, LogEvents.CurrentWeathersGet, errorMessage, Times.Once()); } @@ -74,11 +76,9 @@ public async Task CurrentWeather_ValidationFailed() var getCurrentWeatherQuery = new GetCurrentWeatherQuery(1, 1); var currentWeather = new CurrentWeatherDto(); - var validationResutlMock = new Mock(); - validationResutlMock.SetupGet(x=>x.AnyErrors).Returns(true); - _getCurrentWeatherQueryValidatorMock.Setup(x => x.IsValid(It.IsAny())).Returns(true); + _getCurrentWeatherQueryValidatorMock.Setup(x => x.Validate(It.IsAny())).Returns(new RequestValidationResult { IsValid = true }); _weatherServiceMock.Setup(x => x.GetCurrentWeather(It.IsAny(), It.IsAny())).ReturnsAsync(Result.Ok(currentWeather)); - _currentWeatherValidatorMock.Setup(x => x.Validate(It.IsAny(), It.IsAny())).Returns(validationResutlMock.Object); + _currentWeatherValidatorMock.Setup(x => x.Validate(It.IsAny())).Returns(new RequestValidationResult { IsValid = false}); //Act var result = await _uut.HandleAsync(getCurrentWeatherQuery, CancellationToken.None); @@ -87,10 +87,9 @@ public async Task CurrentWeather_ValidationFailed() Assert.Equal(HttpStatusCode.InternalServerError, result.StatusCode); Assert.Single(result.Errors); Assert.Null(result.Data); - _getCurrentWeatherQueryValidatorMock.Verify(x => x.IsValid(It.Is(y => y.Equals(getCurrentWeatherQuery))), Times.Once); + _getCurrentWeatherQueryValidatorMock.Verify(x => x.Validate(It.Is(y => y.Equals(getCurrentWeatherQuery))), Times.Once); _weatherServiceMock.Verify(x => x.GetCurrentWeather(It.Is(y => y.Equals(getCurrentWeatherQuery.Location)), It.IsAny()), Times.Once); - _currentWeatherValidatorMock.Verify(x => x.Validate(It.Is(y=>y.Equals(currentWeather)), It.Is(y=>!y)), Times.Once); - validationResutlMock.VerifyGet(x=>x.AnyErrors, Times.Once); + _currentWeatherValidatorMock.Verify(x => x.Validate(It.Is(y=>y.Equals(currentWeather))), Times.Once); _loggerMock.VerifyLog(LogLevel.Error, LogEvents.CurrentWeathersValidation, Times.Once()); } @@ -101,11 +100,9 @@ public async Task Success() var getCurrentWeatherQuery = new GetCurrentWeatherQuery(1, 1); var currentWeather = new CurrentWeatherDto(); - var validationResutlMock = new Mock(); - validationResutlMock.SetupGet(x => x.AnyErrors).Returns(false); - _getCurrentWeatherQueryValidatorMock.Setup(x => x.IsValid(It.IsAny())).Returns(true); + _getCurrentWeatherQueryValidatorMock.Setup(x => x.Validate(It.IsAny())).Returns(new RequestValidationResult { IsValid = true }); _weatherServiceMock.Setup(x => x.GetCurrentWeather(It.IsAny(), It.IsAny())).ReturnsAsync(Result.Ok(currentWeather)); - _currentWeatherValidatorMock.Setup(x => x.Validate(It.IsAny(), It.IsAny())).Returns(validationResutlMock.Object); + _currentWeatherValidatorMock.Setup(x => x.Validate(It.IsAny())).Returns(new RequestValidationResult { IsValid = true}); //Act var result = await _uut.HandleAsync(getCurrentWeatherQuery, CancellationToken.None); @@ -115,10 +112,9 @@ public async Task Success() Assert.Empty(result.Errors); Assert.NotNull(result.Data); Assert.Equal(currentWeather, result.Data); - _getCurrentWeatherQueryValidatorMock.Verify(x => x.IsValid(It.Is(y => y.Equals(getCurrentWeatherQuery))), Times.Once); + _getCurrentWeatherQueryValidatorMock.Verify(x => x.Validate(It.Is(y => y.Equals(getCurrentWeatherQuery))), Times.Once); _weatherServiceMock.Verify(x => x.GetCurrentWeather(It.Is(y => y.Equals(getCurrentWeatherQuery.Location)), It.IsAny()), Times.Once); - _currentWeatherValidatorMock.Verify(x => x.Validate(It.Is(y => y.Equals(currentWeather)), It.Is(y => !y)), Times.Once); - validationResutlMock.VerifyGet(x => x.AnyErrors, Times.Once); + _currentWeatherValidatorMock.Verify(x => x.Validate(It.Is(y => y.Equals(currentWeather))), Times.Once); } } } diff --git a/src/Tests/UnitTests/Weather.Core.UnitTests/Queries/GetFavoritesHandlerTests.cs b/src/Tests/UnitTests/Weather.Core.UnitTests/Queries/GetFavoritesHandlerTests.cs index e4200eb..bdacd64 100644 --- a/src/Tests/UnitTests/Weather.Core.UnitTests/Queries/GetFavoritesHandlerTests.cs +++ b/src/Tests/UnitTests/Weather.Core.UnitTests/Queries/GetFavoritesHandlerTests.cs @@ -1,9 +1,10 @@ -using Weather.Core.Abstractions; +using SmallApiToolkit.Core.RequestHandlers; +using SmallApiToolkit.Core.Response; +using SmallApiToolkit.Core.Validation; +using Weather.Core.Abstractions; using Weather.Core.Queries; -using Weather.Core.Resources; using Weather.Domain.BusinessEntities; using Weather.Domain.Dtos; -using Weather.Domain.Http; using Weather.Domain.Logging; using Weather.UnitTests.Common.Extensions; @@ -13,18 +14,18 @@ public class GetFavoritesHandlerTests { private readonly Mock _weatherRepositoryMock; private readonly Mock _weatherServiceMock; - private readonly Mock> _loggerMock; - private readonly Mock> _locationValidatorMock; - private readonly Mock> _currentWeatherValidatorMock; + private readonly Mock> _loggerMock; + private readonly Mock> _locationValidatorMock; + private readonly Mock> _currentWeatherValidatorMock; - private readonly IGetFavoritesHandler _uut; + private readonly IHttpRequestHandler _uut; public GetFavoritesHandlerTests() { - _weatherRepositoryMock = new Mock(); - _weatherServiceMock = new Mock(); - _loggerMock = new Mock>(); - _locationValidatorMock = new Mock>(); - _currentWeatherValidatorMock = new Mock>(); + _weatherRepositoryMock = new(); + _weatherServiceMock = new(); + _loggerMock = new(); + _locationValidatorMock = new(); + _currentWeatherValidatorMock = new(); _uut = new GetFavoritesHandler(_weatherRepositoryMock.Object, _weatherServiceMock.Object, @@ -61,7 +62,7 @@ public async Task InvalidLocation() locationDto, }); - _locationValidatorMock.Setup(x => x.IsValid(It.IsAny())).Returns(false); + _locationValidatorMock.Setup(x => x.Validate(It.IsAny())).Returns(new RequestValidationResult { IsValid = false}); //Act var result = await _uut.HandleAsync(EmptyRequest.Instance, CancellationToken.None); @@ -72,7 +73,7 @@ public async Task InvalidLocation() Assert.Null(result.Data); _weatherRepositoryMock.Verify(x => x.GetFavorites(It.IsAny()), Times.Once); _weatherServiceMock.Verify(x => x.GetCurrentWeather(It.Is(y => y.Equals(locationDto)), It.IsAny()), Times.Never); - _locationValidatorMock.Verify(x => x.IsValid(It.Is(y => y.Equals(locationDto))), Times.Once); + _locationValidatorMock.Verify(x => x.Validate(It.Is(y => y.Equals(locationDto))), Times.Once); } [Fact] @@ -88,7 +89,7 @@ public async Task EmptyResult_GetCurrentWeather_Fail() locationDto, }); - _locationValidatorMock.Setup(x=>x.IsValid(It.IsAny())).Returns(true); + _locationValidatorMock.Setup(x => x.Validate(It.IsAny())).Returns(new RequestValidationResult { IsValid = true }); _weatherServiceMock.Setup(x => x.GetCurrentWeather(It.IsAny(), It.IsAny())).ReturnsAsync(Result.Fail(failMessage)); //Act @@ -100,7 +101,7 @@ public async Task EmptyResult_GetCurrentWeather_Fail() _weatherRepositoryMock.Verify(x => x.GetFavorites(It.IsAny()), Times.Once); _weatherServiceMock.Verify(x => x.GetCurrentWeather(It.Is(y=>y.Equals(locationDto)), It.IsAny()), Times.Once); _loggerMock.VerifyLog(LogLevel.Warning, LogEvents.FavoriteWeathersGeneral, failMessage, Times.Once()); - _locationValidatorMock.Verify(x => x.IsValid(It.Is(y=>y.Equals(locationDto))), Times.Once); + _locationValidatorMock.Verify(x => x.Validate(It.Is(y=>y.Equals(locationDto))), Times.Once); } [Fact] @@ -117,11 +118,11 @@ public async Task One_Of_GetCurrentWeather_Failed() new FavoriteLocation(), }); - _locationValidatorMock.Setup(x => x.IsValid(It.IsAny())).Returns(true); + _locationValidatorMock.Setup(x => x.Validate(It.IsAny())).Returns(new RequestValidationResult { IsValid = true }); var currentWeather = new CurrentWeatherDto(); - _currentWeatherValidatorMock.Setup(x => x.IsValid(It.IsAny())).Returns(true); + _currentWeatherValidatorMock.Setup(x => x.Validate(It.IsAny())).Returns(new RequestValidationResult { IsValid = true }); _weatherServiceMock.Setup(x => x.GetCurrentWeather(It.Is(y=> y.Equals(locationDto)), It.IsAny())).ReturnsAsync(Result.Fail(failMessage)); _weatherServiceMock.Setup(x => x.GetCurrentWeather(It.Is(y => !y.Equals(locationDto)), It.IsAny())).ReturnsAsync(Result.Ok(currentWeather)); @@ -137,8 +138,8 @@ public async Task One_Of_GetCurrentWeather_Failed() _weatherRepositoryMock.Verify(x => x.GetFavorites(It.IsAny()), Times.Once); _weatherServiceMock.Verify(x => x.GetCurrentWeather(It.IsAny(), It.IsAny()), Times.Exactly(2)); _loggerMock.VerifyLog(LogLevel.Warning, LogEvents.FavoriteWeathersGeneral, failMessage, Times.Once()); - _locationValidatorMock.Verify(x => x.IsValid(It.Is(y => y.Equals(locationDto))), Times.Once); - _currentWeatherValidatorMock.Verify(x => x.IsValid(It.Is(y => y.Equals(currentWeather))), Times.Once); + _locationValidatorMock.Verify(x => x.Validate(It.Is(y => y.Equals(locationDto))), Times.Once); + _currentWeatherValidatorMock.Verify(x => x.Validate(It.Is(y => y.Equals(currentWeather))), Times.Once); } [Fact] @@ -153,8 +154,8 @@ public async Task GetCurrentWeather_Validation_Fail() locationDto, }); - _locationValidatorMock.Setup(x => x.IsValid(It.IsAny())).Returns(true); - _currentWeatherValidatorMock.Setup(x => x.IsValid(It.IsAny())).Returns(false); + _locationValidatorMock.Setup(x => x.Validate(It.IsAny())).Returns(new RequestValidationResult { IsValid = true }); + _currentWeatherValidatorMock.Setup(x => x.Validate(It.IsAny())).Returns(new RequestValidationResult { IsValid = false }); var currentWeather = new CurrentWeatherDto(); _weatherServiceMock.Setup(x => x.GetCurrentWeather(It.IsAny(), It.IsAny())).ReturnsAsync(Result.Ok(currentWeather)); @@ -167,8 +168,8 @@ public async Task GetCurrentWeather_Validation_Fail() Assert.Null(result.Data); _weatherRepositoryMock.Verify(x => x.GetFavorites(It.IsAny()), Times.Once); _weatherServiceMock.Verify(x => x.GetCurrentWeather(It.Is(y => y.Equals(locationDto)), It.IsAny()), Times.Once); - _locationValidatorMock.Verify(x => x.IsValid(It.Is(y => y.Equals(locationDto))), Times.Once); - _currentWeatherValidatorMock.Verify(x => x.IsValid(It.Is(y => y.Equals(currentWeather))), Times.Once); + _locationValidatorMock.Verify(x => x.Validate(It.Is(y => y.Equals(locationDto))), Times.Once); + _currentWeatherValidatorMock.Verify(x => x.Validate(It.Is(y => y.Equals(currentWeather))), Times.Once); } [Fact] @@ -183,8 +184,8 @@ public async Task Success() locationDto, }); - _locationValidatorMock.Setup(x => x.IsValid(It.IsAny())).Returns(true); - _currentWeatherValidatorMock.Setup(x=>x.IsValid(It.IsAny())).Returns(true); + _locationValidatorMock.Setup(x => x.Validate(It.IsAny())).Returns(new RequestValidationResult { IsValid = true }); + _currentWeatherValidatorMock.Setup(x=>x.Validate(It.IsAny())).Returns(new RequestValidationResult { IsValid = true }); var currentWeather = new CurrentWeatherDto(); _weatherServiceMock.Setup(x => x.GetCurrentWeather(It.IsAny(), It.IsAny())).ReturnsAsync(Result.Ok(currentWeather)); @@ -199,8 +200,8 @@ public async Task Success() Assert.Equal(currentWeather.CityName, result.Data.FavoriteWeathers.Single().CityName); _weatherRepositoryMock.Verify(x => x.GetFavorites(It.IsAny()), Times.Once); _weatherServiceMock.Verify(x => x.GetCurrentWeather(It.Is(y=>y.Equals(locationDto)), It.IsAny()), Times.Once); - _locationValidatorMock.Verify(x => x.IsValid(It.Is(y => y.Equals(locationDto))), Times.Once); - _currentWeatherValidatorMock.Verify(x => x.IsValid(It.Is(y=>y.Equals(currentWeather))), Times.Once); + _locationValidatorMock.Verify(x => x.Validate(It.Is(y => y.Equals(locationDto))), Times.Once); + _currentWeatherValidatorMock.Verify(x => x.Validate(It.Is(y=>y.Equals(currentWeather))), Times.Once); } } } diff --git a/src/Tests/UnitTests/Weather.Core.UnitTests/Queries/GetForecastWeatherHandlerTests.cs b/src/Tests/UnitTests/Weather.Core.UnitTests/Queries/GetForecastWeatherHandlerTests.cs index f535227..83092ea 100644 --- a/src/Tests/UnitTests/Weather.Core.UnitTests/Queries/GetForecastWeatherHandlerTests.cs +++ b/src/Tests/UnitTests/Weather.Core.UnitTests/Queries/GetForecastWeatherHandlerTests.cs @@ -1,4 +1,6 @@ -using Validot.Results; +using SmallApiToolkit.Core.RequestHandlers; +using SmallApiToolkit.Core.Validation; +using Validot.Results; using Weather.Core.Abstractions; using Weather.Core.Queries; using Weather.Core.Resources; @@ -11,20 +13,24 @@ namespace Weather.Core.UnitTests.Queries { public class GetForecastWeatherHandlerTests { - private readonly Mock> _getForecastWeatherQueryValidatorMock; - private readonly Mock> _forecastWeatherValidatorMock; + private readonly Mock> _getForecastWeatherQueryValidatorMock; + private readonly Mock> _forecastWeatherValidatorMock; private readonly Mock _weatherServiceMock; - private readonly Mock> _loggerMock; + private readonly Mock> _loggerMock; - private readonly IGetForecastWeatherHandler _uut; + private readonly IHttpRequestHandler _uut; public GetForecastWeatherHandlerTests() { - _getForecastWeatherQueryValidatorMock = new Mock>(); - _forecastWeatherValidatorMock = new Mock>(); - _weatherServiceMock = new Mock(); - _loggerMock = new Mock>(); - - _uut = new GetForecastWeatherHandler(_getForecastWeatherQueryValidatorMock.Object, _weatherServiceMock.Object, _forecastWeatherValidatorMock.Object, _loggerMock.Object); + _getForecastWeatherQueryValidatorMock = new(); + _forecastWeatherValidatorMock = new(); + _weatherServiceMock = new(); + _loggerMock = new(); + + _uut = new GetForecastWeatherHandler( + _getForecastWeatherQueryValidatorMock.Object, + _weatherServiceMock.Object, + _forecastWeatherValidatorMock.Object, + _loggerMock.Object); } [Fact] @@ -33,7 +39,7 @@ public async Task InvalidLocation() //Arrange var getForecastWeatherQuery = new GetForecastWeatherQuery(1, 1); - _getForecastWeatherQueryValidatorMock.Setup(x => x.IsValid(It.IsAny())).Returns(false); + _getForecastWeatherQueryValidatorMock.Setup(x => x.Validate(It.IsAny())).Returns(new RequestValidationResult { IsValid = false }); //Act var result = await _uut.HandleAsync(getForecastWeatherQuery, CancellationToken.None); @@ -42,7 +48,7 @@ public async Task InvalidLocation() Assert.Equal(HttpStatusCode.BadRequest, result.StatusCode); Assert.Single(result.Errors); Assert.Null(result.Data); - _getForecastWeatherQueryValidatorMock.Verify(x => x.IsValid(It.Is(y => y.Equals(getForecastWeatherQuery))), Times.Once); + _getForecastWeatherQueryValidatorMock.Verify(x => x.Validate(It.Is(y => y.Equals(getForecastWeatherQuery))), Times.Once); } [Fact] @@ -52,7 +58,7 @@ public async Task GetForecastWeather_Failed() var errorMessage = "error"; var getForecastWeatherQuery = new GetForecastWeatherQuery(1, 1); - _getForecastWeatherQueryValidatorMock.Setup(x => x.IsValid(It.IsAny())).Returns(true); + _getForecastWeatherQueryValidatorMock.Setup(x => x.Validate(It.IsAny())).Returns(new RequestValidationResult { IsValid = true }); _weatherServiceMock.Setup(x => x.GetForecastWeather(It.IsAny(), It.IsAny())).ReturnsAsync(Result.Fail(errorMessage)); //Act var result = await _uut.HandleAsync(getForecastWeatherQuery, CancellationToken.None); @@ -62,7 +68,7 @@ public async Task GetForecastWeather_Failed() Assert.Single(result.Errors); Assert.Equal(ErrorMessages.ExternalApiError, result.Errors.Single()); Assert.Null(result.Data); - _getForecastWeatherQueryValidatorMock.Verify(x => x.IsValid(It.Is(y => y.Equals(getForecastWeatherQuery))), Times.Once); + _getForecastWeatherQueryValidatorMock.Verify(x => x.Validate(It.Is(y => y.Equals(getForecastWeatherQuery))), Times.Once); _weatherServiceMock.Verify(x => x.GetForecastWeather(It.Is(y => y.Equals(getForecastWeatherQuery.Location)), It.IsAny()), Times.Once); _loggerMock.VerifyLog(LogLevel.Error, LogEvents.ForecastWeathersGet, errorMessage, Times.Once()); } @@ -74,11 +80,9 @@ public async Task GetForecastWeather_ValidationFailed() var getForecastWeatherQuery = new GetForecastWeatherQuery(1, 1); var forecastWeather = new ForecastWeatherDto(); - var validationResutlMock = new Mock(); - validationResutlMock.SetupGet(x => x.AnyErrors).Returns(true); - _getForecastWeatherQueryValidatorMock.Setup(x => x.IsValid(It.IsAny())).Returns(true); + _getForecastWeatherQueryValidatorMock.Setup(x => x.Validate(It.IsAny())).Returns(new RequestValidationResult { IsValid = true }); _weatherServiceMock.Setup(x => x.GetForecastWeather(It.IsAny(), It.IsAny())).ReturnsAsync(Result.Ok(forecastWeather)); - _forecastWeatherValidatorMock.Setup(x => x.Validate(It.IsAny(), It.IsAny())).Returns(validationResutlMock.Object); + _forecastWeatherValidatorMock.Setup(x => x.Validate(It.IsAny())).Returns(new RequestValidationResult { IsValid = false }); //Act var result = await _uut.HandleAsync(getForecastWeatherQuery, CancellationToken.None); @@ -87,10 +91,9 @@ public async Task GetForecastWeather_ValidationFailed() Assert.Equal(HttpStatusCode.InternalServerError, result.StatusCode); Assert.Single(result.Errors); Assert.Null(result.Data); - _getForecastWeatherQueryValidatorMock.Verify(x => x.IsValid(It.Is(y => y.Equals(getForecastWeatherQuery))), Times.Once); + _getForecastWeatherQueryValidatorMock.Verify(x => x.Validate(It.Is(y => y.Equals(getForecastWeatherQuery))), Times.Once); _weatherServiceMock.Verify(x => x.GetForecastWeather(It.Is(y => y.Equals(getForecastWeatherQuery.Location)), It.IsAny()), Times.Once); - _forecastWeatherValidatorMock.Verify(x => x.Validate(It.Is(y => y.Equals(forecastWeather)), It.Is(y => !y)), Times.Once); - validationResutlMock.VerifyGet(x => x.AnyErrors, Times.Once); + _forecastWeatherValidatorMock.Verify(x => x.Validate(It.Is(y => y.Equals(forecastWeather))), Times.Once); _loggerMock.VerifyLog(LogLevel.Error, LogEvents.ForecastWeathersValidation, Times.Once()); } @@ -101,11 +104,9 @@ public async Task Success() var getForecastWeatherQuery = new GetForecastWeatherQuery(1, 1); var forecastWeather = new ForecastWeatherDto(); - var validationResutlMock = new Mock(); - validationResutlMock.SetupGet(x => x.AnyErrors).Returns(false); - _getForecastWeatherQueryValidatorMock.Setup(x => x.IsValid(It.IsAny())).Returns(true); + _getForecastWeatherQueryValidatorMock.Setup(x => x.Validate(It.IsAny())).Returns(new RequestValidationResult { IsValid = true }); _weatherServiceMock.Setup(x => x.GetForecastWeather(It.IsAny(), It.IsAny())).ReturnsAsync(Result.Ok(forecastWeather)); - _forecastWeatherValidatorMock.Setup(x => x.Validate(It.IsAny(), It.IsAny())).Returns(validationResutlMock.Object); + _forecastWeatherValidatorMock.Setup(x => x.Validate(It.IsAny())).Returns(new RequestValidationResult { IsValid = true }); //Act var result = await _uut.HandleAsync(getForecastWeatherQuery, CancellationToken.None); @@ -115,10 +116,9 @@ public async Task Success() Assert.Empty(result.Errors); Assert.NotNull(result.Data); Assert.Equal(forecastWeather, result.Data); - _getForecastWeatherQueryValidatorMock.Verify(x => x.IsValid(It.Is(y => y.Equals(getForecastWeatherQuery))), Times.Once); + _getForecastWeatherQueryValidatorMock.Verify(x => x.Validate(It.Is(y => y.Equals(getForecastWeatherQuery))), Times.Once); _weatherServiceMock.Verify(x => x.GetForecastWeather(It.Is(y => y.Equals(getForecastWeatherQuery.Location)), It.IsAny()), Times.Once); - _forecastWeatherValidatorMock.Verify(x => x.Validate(It.Is(y => y.Equals(forecastWeather)), It.Is(y => !y)), Times.Once); - validationResutlMock.VerifyGet(x => x.AnyErrors, Times.Once); + _forecastWeatherValidatorMock.Verify(x => x.Validate(It.Is(y => y.Equals(forecastWeather))), Times.Once); } } } diff --git a/src/Weather.API/EndpointBuilders/WeatherBuilder.cs b/src/Weather.API/EndpointBuilders/WeatherBuilder.cs index 0cd544e..8d795b2 100644 --- a/src/Weather.API/EndpointBuilders/WeatherBuilder.cs +++ b/src/Weather.API/EndpointBuilders/WeatherBuilder.cs @@ -1,8 +1,8 @@ using Microsoft.AspNetCore.Mvc; +using SmallApiToolkit.Core.Extensions; +using SmallApiToolkit.Core.RequestHandlers; using SmallApiToolkit.Core.Response; using SmallApiToolkit.Extensions; -using Weather.API.Extensions; -using Weather.Core.Abstractions; using Weather.Domain.Commands; using Weather.Domain.Dtos; using Weather.Domain.Queries; @@ -27,7 +27,7 @@ public static IEndpointRouteBuilder BuildWeatherEndpoints(this IEndpointRouteBui private static IEndpointRouteBuilder BuildActualWeatherEndpoints(this IEndpointRouteBuilder endpointRouteBuilder) { endpointRouteBuilder.MapGet("current", - async (double latitude, double longitude, [FromServices] IGetCurrentWeatherHandler handler, CancellationToken cancellationToken) => + async (double latitude, double longitude, [FromServices] IHttpRequestHandler handler, CancellationToken cancellationToken) => await handler.SendAsync(new GetCurrentWeatherQuery(latitude, longitude), cancellationToken)) .ProducesDataResponse() .WithName("GetCurrentWeather") @@ -38,7 +38,7 @@ await handler.SendAsync(new GetCurrentWeatherQuery(latitude, longitude), cancell private static IEndpointRouteBuilder BuildForecastWeatherEndpoints(this IEndpointRouteBuilder endpointRouteBuilder) { endpointRouteBuilder.MapGet("forecast", - async (double latitude, double longitude, [FromServices] IGetForecastWeatherHandler handler, CancellationToken cancellationToken) => + async (double latitude, double longitude, [FromServices] IHttpRequestHandler handler, CancellationToken cancellationToken) => await handler.SendAsync(new GetForecastWeatherQuery(latitude, longitude), cancellationToken)) .ProducesDataResponse() .WithName("GetForecastWeather") @@ -50,21 +50,21 @@ await handler.SendAsync(new GetForecastWeatherQuery(latitude, longitude), cancel private static IEndpointRouteBuilder BuildFavoriteWeatherEndpoints(this IEndpointRouteBuilder endpointRouteBuilder) { endpointRouteBuilder.MapGet("favorites", - async ([FromServices] IGetFavoritesHandler handler, CancellationToken cancellationToken) => + async ([FromServices] IHttpRequestHandler handler, CancellationToken cancellationToken) => await handler.SendAsync(EmptyRequest.Instance, cancellationToken)) .ProducesDataResponse() .WithName("GetFavorites") .WithTags("Getters"); endpointRouteBuilder.MapPost("favorite", - async ([FromBody] AddFavoriteCommand addFavoriteCommand, [FromServices] IAddFavoriteHandler handler, CancellationToken cancellationToken) => + async ([FromBody] AddFavoriteCommand addFavoriteCommand, [FromServices] IHttpRequestHandler handler, CancellationToken cancellationToken) => await handler.SendAsync(addFavoriteCommand, cancellationToken)) .ProducesDataResponse() .WithName("AddFavorite") .WithTags("Setters"); endpointRouteBuilder.MapDelete("favorite/{id}", - async (int id, [FromServices] IDeleteFavoriteHandler handler, CancellationToken cancellationToken) => + async (int id, [FromServices] IHttpRequestHandler handler, CancellationToken cancellationToken) => await handler.SendAsync(new DeleteFavoriteCommand { Id = id }, cancellationToken)) .ProducesDataResponse() .WithName("DeleteFavorite") diff --git a/src/Weather.API/Program.cs b/src/Weather.API/Program.cs index d5e6929..b981d75 100644 --- a/src/Weather.API/Program.cs +++ b/src/Weather.API/Program.cs @@ -1,6 +1,6 @@ +using SmallApiToolkit.Middleware; using Weather.API.Configuration; using Weather.API.EndpointBuilders; -using Weather.API.Middlewares; using Weather.Core.Configuration; using Weather.Infrastructure.Configuration; @@ -24,6 +24,7 @@ app.UseHttpsRedirection(); app.UseMiddleware(); +app.UseMiddleware(); app.BuildWeatherEndpoints(); diff --git a/src/Weather.Core/Abstractions/IAddFavoriteHandler.cs b/src/Weather.Core/Abstractions/IAddFavoriteHandler.cs deleted file mode 100644 index 087c72a..0000000 --- a/src/Weather.Core/Abstractions/IAddFavoriteHandler.cs +++ /dev/null @@ -1,10 +0,0 @@ -using SmallApiToolkit.Core.RequestHandlers; -using Weather.Domain.Commands; - -namespace Weather.Core.Abstractions -{ - public interface IAddFavoriteHandler : IHttpRequestHandler - { - - } -} diff --git a/src/Weather.Core/Abstractions/IDeleteFavoriteHandler.cs b/src/Weather.Core/Abstractions/IDeleteFavoriteHandler.cs deleted file mode 100644 index ba45166..0000000 --- a/src/Weather.Core/Abstractions/IDeleteFavoriteHandler.cs +++ /dev/null @@ -1,9 +0,0 @@ -using SmallApiToolkit.Core.RequestHandlers; -using Weather.Domain.Commands; - -namespace Weather.Core.Abstractions -{ - public interface IDeleteFavoriteHandler : IHttpRequestHandler - { - } -} diff --git a/src/Weather.Core/Abstractions/IGetCurrentWeatherHandler.cs b/src/Weather.Core/Abstractions/IGetCurrentWeatherHandler.cs deleted file mode 100644 index ab3cce7..0000000 --- a/src/Weather.Core/Abstractions/IGetCurrentWeatherHandler.cs +++ /dev/null @@ -1,10 +0,0 @@ -using SmallApiToolkit.Core.RequestHandlers; -using Weather.Domain.Dtos; -using Weather.Domain.Queries; - -namespace Weather.Core.Abstractions -{ - public interface IGetCurrentWeatherHandler : IHttpRequestHandler - { - } -} diff --git a/src/Weather.Core/Abstractions/IGetFavoritesHandler.cs b/src/Weather.Core/Abstractions/IGetFavoritesHandler.cs deleted file mode 100644 index 6d620ec..0000000 --- a/src/Weather.Core/Abstractions/IGetFavoritesHandler.cs +++ /dev/null @@ -1,10 +0,0 @@ -using SmallApiToolkit.Core.RequestHandlers; -using SmallApiToolkit.Core.Response; -using Weather.Domain.Dtos; - -namespace Weather.Core.Abstractions -{ - public interface IGetFavoritesHandler : IHttpRequestHandler - { - } -} diff --git a/src/Weather.Core/Abstractions/IGetForecastWeatherHandler.cs b/src/Weather.Core/Abstractions/IGetForecastWeatherHandler.cs deleted file mode 100644 index fd19e3b..0000000 --- a/src/Weather.Core/Abstractions/IGetForecastWeatherHandler.cs +++ /dev/null @@ -1,10 +0,0 @@ -using SmallApiToolkit.Core.RequestHandlers; -using Weather.Domain.Dtos; -using Weather.Domain.Queries; - -namespace Weather.Core.Abstractions -{ - public interface IGetForecastWeatherHandler : IHttpRequestHandler - { - } -} diff --git a/src/Weather.Core/Abstractions/IRequestHandler.cs b/src/Weather.Core/Abstractions/IRequestHandler.cs deleted file mode 100644 index cc0f9d2..0000000 --- a/src/Weather.Core/Abstractions/IRequestHandler.cs +++ /dev/null @@ -1,9 +0,0 @@ -using Weather.Domain.Http; - -namespace Weather.Core.Abstractions -{ - public interface IRequestHandler - { - Task> HandleAsync(TRequest request, CancellationToken cancellationToken); - } -} diff --git a/src/Weather.Core/Commands/AddFavoriteHandler.cs b/src/Weather.Core/Commands/AddFavoriteHandler.cs index 7431ec8..2e5acc3 100644 --- a/src/Weather.Core/Commands/AddFavoriteHandler.cs +++ b/src/Weather.Core/Commands/AddFavoriteHandler.cs @@ -1,6 +1,7 @@ using Ardalis.GuardClauses; using Microsoft.Extensions.Logging; using SmallApiToolkit.Core.Extensions; +using SmallApiToolkit.Core.RequestHandlers; using SmallApiToolkit.Core.Response; using SmallApiToolkit.Core.Validation; using Weather.Core.Abstractions; @@ -11,28 +12,22 @@ namespace Weather.Core.Commands { - internal sealed class AddFavoriteHandler : IAddFavoriteHandler + internal sealed class AddFavoriteHandler : ValidationHttpRequestHandler { - private readonly IRequestValidator _addFavoriteCommandValidator; - private readonly ILogger _logger; + private readonly ILogger _logger; private readonly IWeatherCommandsRepository _weatherCommandsRepository; public AddFavoriteHandler( IWeatherCommandsRepository weatherCommandsRepository, IRequestValidator addFavoriteCommandValidator, - ILogger logger) + ILogger logger) + :base(addFavoriteCommandValidator) { _weatherCommandsRepository = Guard.Against.Null(weatherCommandsRepository); - _addFavoriteCommandValidator = Guard.Against.Null(addFavoriteCommandValidator); _logger = Guard.Against.Null(logger); } - public async Task> HandleAsync(AddFavoriteCommand request, CancellationToken cancellationToken) + protected override async Task> HandleValidRequestAsync(AddFavoriteCommand request, CancellationToken cancellationToken) { - if (!_addFavoriteCommandValidator.IsValid(request)) - { - return HttpDataResponses.AsBadRequest(string.Format(ErrorMessages.RequestValidationError, request)); - } - var addResult = await _weatherCommandsRepository.AddFavoriteLocation(request, cancellationToken); if(addResult.IsFailed) { diff --git a/src/Weather.Core/Commands/DeleteFavoriteHandler.cs b/src/Weather.Core/Commands/DeleteFavoriteHandler.cs index b7b7910..8acfff0 100644 --- a/src/Weather.Core/Commands/DeleteFavoriteHandler.cs +++ b/src/Weather.Core/Commands/DeleteFavoriteHandler.cs @@ -1,34 +1,27 @@ using Ardalis.GuardClauses; using SmallApiToolkit.Core.Extensions; +using SmallApiToolkit.Core.RequestHandlers; using SmallApiToolkit.Core.Response; using SmallApiToolkit.Core.Validation; -using Validot; using Weather.Core.Abstractions; -using Weather.Core.Resources; using Weather.Domain.Commands; namespace Weather.Core.Commands { - internal sealed class DeleteFavoriteHandler : IDeleteFavoriteHandler + internal sealed class DeleteFavoriteHandler : ValidationHttpRequestHandler { private readonly IWeatherCommandsRepository _weatherCommandsRepository; - private readonly IRequestValidator _validator; public DeleteFavoriteHandler( IWeatherCommandsRepository weatherCommandsRepository, IRequestValidator validator) + : base(validator) { _weatherCommandsRepository = Guard.Against.Null(weatherCommandsRepository); - _validator = Guard.Against.Null(validator); } - public async Task> HandleAsync(DeleteFavoriteCommand request, CancellationToken cancellationToken) + protected override async Task> HandleValidRequestAsync(DeleteFavoriteCommand request, CancellationToken cancellationToken) { - if (!_validator.IsValid(request)) - { - return HttpDataResponses.AsBadRequest(string.Format(ErrorMessages.RequestValidationError, request)); - } - var addResult = await _weatherCommandsRepository.DeleteFavoriteLocationSafeAsync(request, cancellationToken); if (addResult.IsFailed) { diff --git a/src/Weather.Core/Configuration/ContainerConfigurationExtension.cs b/src/Weather.Core/Configuration/ContainerConfigurationExtension.cs index 671d3c1..5133697 100644 --- a/src/Weather.Core/Configuration/ContainerConfigurationExtension.cs +++ b/src/Weather.Core/Configuration/ContainerConfigurationExtension.cs @@ -1,10 +1,8 @@ using Microsoft.Extensions.DependencyInjection; using SmallApiToolkit.Core.RequestHandlers; +using SmallApiToolkit.Core.Response; using SmallApiToolkit.Core.Validation; -using Validot; -using Weather.Core.Abstractions; using Weather.Core.Commands; -using Weather.Core.Extensions; using Weather.Core.Queries; using Weather.Core.Validation; using Weather.Domain.Commands; @@ -23,19 +21,19 @@ public static IServiceCollection AddCore(this IServiceCollection serviceCollecti private static IServiceCollection AddHandlers(this IServiceCollection serviceCollection) => serviceCollection .AddScoped, GetCurrentWeatherHandler>() - .AddScoped() - .AddScoped() - .AddScoped() - .AddScoped(); + .AddScoped, GetFavoritesHandler>() + .AddScoped, GetForecastWeatherHandler>() + .AddScoped, AddFavoriteHandler>() + .AddScoped, DeleteFavoriteHandler>(); private static IServiceCollection AddValidation(this IServiceCollection serviceCollection) => serviceCollection - .AddValidotSingleton, CurrentWeatherDtoValidator, CurrentWeatherDto>() - .AddValidotSingleton, ForecastWeatherDtoValidator, ForecastWeatherDto>() - .AddValidotSingleton, LocationDtoValidator, LocationDto>() + .AddSingleton, CurrentWeatherDtoValidator>() + .AddSingleton, ForecastWeatherDtoValidator>() + .AddSingleton, LocationDtoValidator>() .AddSingleton, AddFavoriteCommandValidator>() - .AddValidotSingleton, GetCurrentWeatherQueryValidator, GetCurrentWeatherQuery>() - .AddValidotSingleton, GetForecastWeatherValidator, GetForecastWeatherQuery>() - .AddValidotSingleton, DeleteFavoriteCommandValidator, DeleteFavoriteCommand>(); + .AddSingleton, GetCurrentWeatherQueryValidator>() + .AddSingleton, GetForecastWeatherValidator>() + .AddSingleton, DeleteFavoriteCommandValidator>(); } } diff --git a/src/Weather.Core/Extensions/ValidotDependencyInjectionExtensions.cs b/src/Weather.Core/Extensions/ValidotDependencyInjectionExtensions.cs deleted file mode 100644 index c98fc52..0000000 --- a/src/Weather.Core/Extensions/ValidotDependencyInjectionExtensions.cs +++ /dev/null @@ -1,15 +0,0 @@ -using Microsoft.Extensions.DependencyInjection; -using Validot; - -namespace Weather.Core.Extensions -{ - public static class ValidotDependencyInjectionExtensions - { - public static IServiceCollection AddValidotSingleton(this IServiceCollection serviceCollection) - where TValidator : IValidator - where THolder : ISpecificationHolder, new() - { - return serviceCollection.AddSingleton(typeof(TValidator), Validator.Factory.Create(new THolder())); - } - } -} diff --git a/src/Weather.Core/Queries/GetCurrentWeatherHandler.cs b/src/Weather.Core/Queries/GetCurrentWeatherHandler.cs index 1b8e4ed..980f03c 100644 --- a/src/Weather.Core/Queries/GetCurrentWeatherHandler.cs +++ b/src/Weather.Core/Queries/GetCurrentWeatherHandler.cs @@ -4,7 +4,6 @@ using SmallApiToolkit.Core.RequestHandlers; using SmallApiToolkit.Core.Response; using SmallApiToolkit.Core.Validation; -using Validot; using Weather.Core.Abstractions; using Weather.Core.Resources; using Weather.Domain.Dtos; @@ -19,11 +18,11 @@ internal sealed class GetCurrentWeatherHandler : ValidationHttpRequestHandler _currentWeatherValidator; private readonly IWeatherService _weatherService; - private readonly ILogger _logger; + private readonly ILogger _logger; public GetCurrentWeatherHandler(IRequestValidator getCurrentWeatherQueryValidator, IRequestValidator currentWeatherValidator, IWeatherService weatherService, - ILogger logger) + ILogger logger) : base(getCurrentWeatherQueryValidator) { _weatherService = Guard.Against.Null(weatherService); @@ -31,8 +30,11 @@ public GetCurrentWeatherHandler(IRequestValidator getCur _logger = Guard.Against.Null(logger); } - protected override HttpDataResponse CreateInvalidResponse(GetCurrentWeatherQuery request) - => HttpDataResponses.AsBadRequest(string.Format(ErrorMessages.RequestValidationError, request)); + protected override HttpDataResponse CreateInvalidResponse(GetCurrentWeatherQuery request, RequestValidationResult validationResult) + { + _logger.LogError(LogEvents.CurrentWeathersValidation, validationResult.ToString()); + return HttpDataResponses.AsBadRequest(string.Format(ErrorMessages.RequestValidationError, request)); + } protected override async Task> HandleValidRequestAsync(GetCurrentWeatherQuery request, CancellationToken cancellationToken) { @@ -44,7 +46,7 @@ protected override async Task> HandleValidRe } var validationResult = _currentWeatherValidator.Validate(getCurrentWeatherResult.Value); - if (validationResult.AnyErrors) + if (!validationResult.IsValid) { _logger.LogError(LogEvents.CurrentWeathersValidation, ErrorLogMessages.ValidationErrorLog, validationResult.ToString()); return HttpDataResponses.AsInternalServerError(ErrorMessages.ExternalApiError); diff --git a/src/Weather.Core/Queries/GetFavoritesHandler.cs b/src/Weather.Core/Queries/GetFavoritesHandler.cs index 6743343..22f3d14 100644 --- a/src/Weather.Core/Queries/GetFavoritesHandler.cs +++ b/src/Weather.Core/Queries/GetFavoritesHandler.cs @@ -2,6 +2,7 @@ using FluentResults; using Microsoft.Extensions.Logging; using SmallApiToolkit.Core.Extensions; +using SmallApiToolkit.Core.RequestHandlers; using SmallApiToolkit.Core.Response; using SmallApiToolkit.Core.Validation; using Weather.Core.Abstractions; @@ -14,19 +15,19 @@ namespace Weather.Core.Queries { - internal sealed class GetFavoritesHandler : IGetFavoritesHandler + internal sealed class GetFavoritesHandler : IHttpRequestHandler { private readonly IRequestValidator _locationValidator; private readonly IRequestValidator _currentWeatherValidator; private readonly IWeatherQueriesRepository _weatherQueriesRepository; private readonly IWeatherService _weatherService; - private readonly ILogger _logger; + private readonly ILogger _logger; public GetFavoritesHandler(IWeatherQueriesRepository weatherQueriesRepository, IWeatherService weatherService, IRequestValidator locationValidator, IRequestValidator currentWeatherValidator, - ILogger logger) + ILogger logger) { _locationValidator = Guard.Against.Null(locationValidator); _currentWeatherValidator = Guard.Against.Null(currentWeatherValidator); @@ -81,7 +82,7 @@ await favoriteLocationsResult.ForEachAsync(async (location) => private async Task> GetWeatherAsync(LocationDto location, CancellationToken cancellationToken) { - if (!_locationValidator.IsValid(location)) + if (!_locationValidator.Validate(location).IsValid) { _logger.LogWarning(LogEvents.FavoriteWeathersGeneral, ErrorLogMessages.InvalidLocation, location); return Result.Fail(string.Format(ErrorMessages.InvalidStoredLocation, location)); @@ -94,7 +95,7 @@ private async Task> GetWeatherAsync(LocationDto locati return Result.Fail(ErrorMessages.ExternalApiError); } - if (!_currentWeatherValidator.IsValid(favoriteWeather.Value)) + if (!_currentWeatherValidator.Validate(favoriteWeather.Value).IsValid) { _logger.LogWarning(LogEvents.FavoriteWeathersGeneral, ErrorLogMessages.InvalidWeather, location); return Result.Fail(ErrorMessages.ExternalApiError); diff --git a/src/Weather.Core/Queries/GetForecastWeatherHandler.cs b/src/Weather.Core/Queries/GetForecastWeatherHandler.cs index 5cf5bf4..7f7bd79 100644 --- a/src/Weather.Core/Queries/GetForecastWeatherHandler.cs +++ b/src/Weather.Core/Queries/GetForecastWeatherHandler.cs @@ -1,6 +1,7 @@ using Ardalis.GuardClauses; using Microsoft.Extensions.Logging; using SmallApiToolkit.Core.Extensions; +using SmallApiToolkit.Core.RequestHandlers; using SmallApiToolkit.Core.Response; using SmallApiToolkit.Core.Validation; using Weather.Core.Abstractions; @@ -13,30 +14,24 @@ namespace Weather.Core.Queries { - internal sealed class GetForecastWeatherHandler : IGetForecastWeatherHandler + internal sealed class GetForecastWeatherHandler : ValidationHttpRequestHandler { - private readonly IRequestValidator _getForecastWeatherQueryValidator; private readonly IRequestValidator _forecastWeatherValidator; private readonly IWeatherService _weatherService; - private readonly ILogger _logger; + private readonly ILogger _logger; public GetForecastWeatherHandler( IRequestValidator getForecastWeatherQueryValidator, IWeatherService weatherService, IRequestValidator forecastWeatherValidator, - ILogger logger) + ILogger logger) + : base(getForecastWeatherQueryValidator) { - _getForecastWeatherQueryValidator = Guard.Against.Null(getForecastWeatherQueryValidator); _weatherService = Guard.Against.Null(weatherService); _forecastWeatherValidator = Guard.Against.Null(forecastWeatherValidator); _logger = Guard.Against.Null(logger); } - public async Task> HandleAsync(GetForecastWeatherQuery request, CancellationToken cancellationToken) + protected override async Task> HandleValidRequestAsync(GetForecastWeatherQuery request, CancellationToken cancellationToken) { - if(!_getForecastWeatherQueryValidator.IsValid(request)) - { - return HttpDataResponses.AsBadRequest(string.Format(ErrorMessages.RequestValidationError, request)); - } - var forecastResult = await _weatherService.GetForecastWeather(request.Location, cancellationToken); if(forecastResult.IsFailed) @@ -46,7 +41,7 @@ public async Task> HandleAsync(GetForecastW } var validationResult = _forecastWeatherValidator.Validate(forecastResult.Value); - if (validationResult.AnyErrors) + if (!validationResult.IsValid) { _logger.LogError(LogEvents.ForecastWeathersValidation, ErrorLogMessages.ValidationErrorLog, validationResult.ToString()); return HttpDataResponses.AsInternalServerError(ErrorMessages.ExternalApiError); diff --git a/src/Weather.Core/Validation/AddFavoriteCommandValidator.cs b/src/Weather.Core/Validation/AddFavoriteCommandValidator.cs index 2211ee4..57e8530 100644 --- a/src/Weather.Core/Validation/AddFavoriteCommandValidator.cs +++ b/src/Weather.Core/Validation/AddFavoriteCommandValidator.cs @@ -16,8 +16,8 @@ public AddFavoriteCommandValidator() _validator = Validot.Validator.Factory.Create(addFavoriteCommandSpecification); } - public bool IsValid(AddFavoriteCommand request) - => _validator.IsValid(request); + public RequestValidationResult Validate(AddFavoriteCommand request) + => new() { IsValid = _validator.IsValid(request) }; } } diff --git a/src/Weather.Core/Validation/CurrentWeatherDtoValidator.cs b/src/Weather.Core/Validation/CurrentWeatherDtoValidator.cs index 7bb3312..c8eaeb5 100644 --- a/src/Weather.Core/Validation/CurrentWeatherDtoValidator.cs +++ b/src/Weather.Core/Validation/CurrentWeatherDtoValidator.cs @@ -27,7 +27,14 @@ public CurrentWeatherDtoValidator() _validator = Validot.Validator.Factory.Create(currentWeatherDtoSpecification); } - public bool IsValid(CurrentWeatherDto request) - => _validator.IsValid(request); + public RequestValidationResult Validate(CurrentWeatherDto request) + { + var result = _validator.Validate(request); + return new RequestValidationResult + { + IsValid = !result.AnyErrors, + ErrorMessages = [.. result.Codes] + }; + } } } diff --git a/src/Weather.Core/Validation/DeleteFavoriteCommandValidator.cs b/src/Weather.Core/Validation/DeleteFavoriteCommandValidator.cs index b9bc619..7a2ad15 100644 --- a/src/Weather.Core/Validation/DeleteFavoriteCommandValidator.cs +++ b/src/Weather.Core/Validation/DeleteFavoriteCommandValidator.cs @@ -16,7 +16,7 @@ public DeleteFavoriteCommandValidator() _validator = Validot.Validator.Factory.Create(deleteFavoriteCommandSpecification); } - public bool IsValid(DeleteFavoriteCommand request) - => _validator.IsValid(request); + public RequestValidationResult Validate(DeleteFavoriteCommand request) + => new() { IsValid = _validator.IsValid(request) }; } } diff --git a/src/Weather.Core/Validation/ForecastWeatherDtoValidator.cs b/src/Weather.Core/Validation/ForecastWeatherDtoValidator.cs index 2582225..44571f9 100644 --- a/src/Weather.Core/Validation/ForecastWeatherDtoValidator.cs +++ b/src/Weather.Core/Validation/ForecastWeatherDtoValidator.cs @@ -26,7 +26,7 @@ public ForecastWeatherDtoValidator() _validator = Validot.Validator.Factory.Create(forecastSpecification); } - public bool IsValid(ForecastWeatherDto request) - => _validator.IsValid(request); + public RequestValidationResult Validate(ForecastWeatherDto request) + => new() { IsValid = _validator.IsValid(request) }; } } diff --git a/src/Weather.Core/Validation/GetCurrentWeatherQueryValidator.cs b/src/Weather.Core/Validation/GetCurrentWeatherQueryValidator.cs index 94a28fc..253cc64 100644 --- a/src/Weather.Core/Validation/GetCurrentWeatherQueryValidator.cs +++ b/src/Weather.Core/Validation/GetCurrentWeatherQueryValidator.cs @@ -16,7 +16,14 @@ public GetCurrentWeatherQueryValidator() _validator = Validot.Validator.Factory.Create(getCurrentWeatherQuerySpecification); } - public bool IsValid(GetCurrentWeatherQuery request) - => _validator.IsValid(request); + public RequestValidationResult Validate(GetCurrentWeatherQuery request) + { + var result = _validator.Validate(request); + return new RequestValidationResult + { + IsValid = !result.AnyErrors, + ErrorMessages = [.. result.Codes] + }; + } } } diff --git a/src/Weather.Core/Validation/GetForecastWeatherValidator.cs b/src/Weather.Core/Validation/GetForecastWeatherValidator.cs index f412ce6..19eac5c 100644 --- a/src/Weather.Core/Validation/GetForecastWeatherValidator.cs +++ b/src/Weather.Core/Validation/GetForecastWeatherValidator.cs @@ -16,7 +16,7 @@ public GetForecastWeatherValidator() _validator = Validot.Validator.Factory.Create(getForecastWeatherQuerySpecification); } - public bool IsValid(GetForecastWeatherQuery request) - => _validator.IsValid(request); + public RequestValidationResult Validate(GetForecastWeatherQuery request) + => new() { IsValid = _validator.IsValid(request) }; } } diff --git a/src/Weather.Core/Validation/LocationDtoValidator.cs b/src/Weather.Core/Validation/LocationDtoValidator.cs index d07fff3..2450fb9 100644 --- a/src/Weather.Core/Validation/LocationDtoValidator.cs +++ b/src/Weather.Core/Validation/LocationDtoValidator.cs @@ -13,7 +13,7 @@ public LocationDtoValidator() _validator = Validot.Validator.Factory.Create(GeneralPredicates.isValidLocation); } - public bool IsValid(LocationDto request) - => _validator.IsValid(request); + public RequestValidationResult Validate(LocationDto request) + => new() { IsValid = _validator.IsValid(request) }; } } diff --git a/src/Weather.Core/Weather.Core.csproj b/src/Weather.Core/Weather.Core.csproj index be170ad..d4eb5e2 100644 --- a/src/Weather.Core/Weather.Core.csproj +++ b/src/Weather.Core/Weather.Core.csproj @@ -38,4 +38,10 @@ + + + <_Parameter1>DynamicProxyGenAssembly2 + + + diff --git a/src/Weather.Domain/Extensions/EnumerableExtensions.cs b/src/Weather.Domain/Extensions/EnumerableExtensions.cs index 3deab9c..3c280ee 100644 --- a/src/Weather.Domain/Extensions/EnumerableExtensions.cs +++ b/src/Weather.Domain/Extensions/EnumerableExtensions.cs @@ -19,8 +19,9 @@ public static async Task ForEachAsync(this IEnumerable values, Func(this IEnumerable values) - { - return values?.Any() ?? false; - } + => values?.Any() ?? false; + + public static string JoinToMessage(this IEnumerable values, char separator = ',') + => string.Join(separator, values); } }