diff --git a/README.md b/README.md index 46b5769..32666e5 100644 --- a/README.md +++ b/README.md @@ -105,6 +105,7 @@ And lastly, the most important sentence at the end: **the architecture of a proj ## Technologies * [ASP.NET Core 8](https://learn.microsoft.com/en-us/aspnet/core/introduction-to-aspnet-core?view=aspnetcore-8.0) * [Entity Framework Core InMemory](https://learn.microsoft.com/en-us/ef/core/providers/in-memory/?tabs=dotnet-core-cli) +* [SmallApiToolkit](https://github.com/Gramli/SmallApiToolkit) * [AutoMapper](https://github.com/AutoMapper/AutoMapper) * [FluentResuls](https://github.com/altmann/FluentResults) * [Validot](https://github.com/bartoszlenar/Validot) diff --git a/src/Tests/Weather.API.UnitTests/Features/AddFavorites/AddFavoriteHandlerTests.cs b/src/Tests/Weather.API.UnitTests/Features/AddFavorites/AddFavoriteHandlerTests.cs index 95f5ef8..84e0b10 100644 --- a/src/Tests/Weather.API.UnitTests/Features/AddFavorites/AddFavoriteHandlerTests.cs +++ b/src/Tests/Weather.API.UnitTests/Features/AddFavorites/AddFavoriteHandlerTests.cs @@ -2,6 +2,7 @@ using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Logging; using Moq; +using SmallApiToolkit.Core.RequestHandlers; using System.Net; using Validot; using Weather.API.Domain.Abstractions; @@ -22,7 +23,7 @@ public class AddFavoriteHandlerTests private readonly Mock _mapperMock; private readonly Mock> _favoriteLocationEntityDbSetMock; - private readonly IRequestHandler _uut; + private readonly IHttpRequestHandler _uut; public AddFavoriteHandlerTests() { _favoriteLocationEntityDbSetMock = new(); diff --git a/src/Tests/Weather.API.UnitTests/Features/DeleteFavorites/DeleteFavoriteHandlerTests.cs b/src/Tests/Weather.API.UnitTests/Features/DeleteFavorites/DeleteFavoriteHandlerTests.cs index c375773..a4feb4c 100644 --- a/src/Tests/Weather.API.UnitTests/Features/DeleteFavorites/DeleteFavoriteHandlerTests.cs +++ b/src/Tests/Weather.API.UnitTests/Features/DeleteFavorites/DeleteFavoriteHandlerTests.cs @@ -1,6 +1,7 @@ using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Logging; using Moq; +using SmallApiToolkit.Core.RequestHandlers; using System.Net; using Validot; using Weather.API.Domain.Abstractions; @@ -17,7 +18,7 @@ public class DeleteFavoriteHandlerTests private readonly Mock _weatherContextMock; private readonly Mock> _favoriteLocationEntityDbSetMock; - private readonly IRequestHandler _uut; + private readonly IHttpRequestHandler _uut; public DeleteFavoriteHandlerTests() { _deleteFavoriteCommandValidatorMock = new(); diff --git a/src/Tests/Weather.API.UnitTests/Features/GetCurrent/GetCurrentWeatherHandlerTests.cs b/src/Tests/Weather.API.UnitTests/Features/GetCurrent/GetCurrentWeatherHandlerTests.cs index 16fc87d..aaa6d75 100644 --- a/src/Tests/Weather.API.UnitTests/Features/GetCurrent/GetCurrentWeatherHandlerTests.cs +++ b/src/Tests/Weather.API.UnitTests/Features/GetCurrent/GetCurrentWeatherHandlerTests.cs @@ -1,6 +1,7 @@ using FluentResults; using Microsoft.Extensions.Logging; using Moq; +using SmallApiToolkit.Core.RequestHandlers; using System.Net; using Validot; using Validot.Results; @@ -20,7 +21,7 @@ public class GetCurrentWeatherHandlerTests private readonly Mock _weatherServiceMock; private readonly Mock> _loggerMock; - private readonly IRequestHandler _uut; + private readonly IHttpRequestHandler _uut; public GetCurrentWeatherHandlerTests() { _getCurrentWeatherQueryValidatorMock = new(); diff --git a/src/Tests/Weather.API.UnitTests/Features/GetFavorites/GetFavoritesHandlerTests.cs b/src/Tests/Weather.API.UnitTests/Features/GetFavorites/GetFavoritesHandlerTests.cs index adb0069..f123080 100644 --- a/src/Tests/Weather.API.UnitTests/Features/GetFavorites/GetFavoritesHandlerTests.cs +++ b/src/Tests/Weather.API.UnitTests/Features/GetFavorites/GetFavoritesHandlerTests.cs @@ -3,6 +3,8 @@ using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Logging; using Moq; +using SmallApiToolkit.Core.RequestHandlers; +using SmallApiToolkit.Core.Response; using System.Net; using Validot; using Weather.API.Domain.Abstractions; @@ -12,7 +14,6 @@ using Weather.API.Features.Favorites.GetFavorites; using Weather.API.UnitTests.Domain.Database; using Weather.API.UnitTests.TestExtensions; -using WeatherApi.Domain.Http; namespace Weather.API.UnitTests.Features.GetFavorites { @@ -26,7 +27,7 @@ public class GetFavoritesHandlerTests private readonly Mock _mapperMock; private readonly Mock> _favoriteLocationEntityDbSetMock; - private readonly IRequestHandler _uut; + private readonly IHttpRequestHandler _uut; public GetFavoritesHandlerTests() { _weatherServiceMock = new(); diff --git a/src/Tests/Weather.API.UnitTests/Features/GetForecast/GetForecastWeatherHandlerTests.cs b/src/Tests/Weather.API.UnitTests/Features/GetForecast/GetForecastWeatherHandlerTests.cs index 6d06183..f9f9397 100644 --- a/src/Tests/Weather.API.UnitTests/Features/GetForecast/GetForecastWeatherHandlerTests.cs +++ b/src/Tests/Weather.API.UnitTests/Features/GetForecast/GetForecastWeatherHandlerTests.cs @@ -1,6 +1,7 @@ using FluentResults; using Microsoft.Extensions.Logging; using Moq; +using SmallApiToolkit.Core.RequestHandlers; using System.Net; using Validot; using Validot.Results; @@ -20,7 +21,7 @@ public class GetForecastWeatherHandlerTests private readonly Mock _weatherServiceMock; private readonly Mock> _loggerMock; - private readonly IRequestHandler _uut; + private readonly IHttpRequestHandler _uut; public GetForecastWeatherHandlerTests() { _getForecastWeatherQueryValidatorMock = new Mock>(); diff --git a/src/Weather.API/Domain/Abstractions/IRequestHandler.cs b/src/Weather.API/Domain/Abstractions/IRequestHandler.cs deleted file mode 100644 index 1619e8e..0000000 --- a/src/Weather.API/Domain/Abstractions/IRequestHandler.cs +++ /dev/null @@ -1,9 +0,0 @@ -using WeatherApi.Domain.Http; - -namespace Weather.API.Domain.Abstractions -{ - public interface IRequestHandler - { - Task> HandleAsync(TRequest request, CancellationToken cancellationToken); - } -} diff --git a/src/Weather.API/Domain/Extensions/HttpDataResponses.cs b/src/Weather.API/Domain/Extensions/HttpDataResponses.cs deleted file mode 100644 index 2c701aa..0000000 --- a/src/Weather.API/Domain/Extensions/HttpDataResponses.cs +++ /dev/null @@ -1,70 +0,0 @@ -using WeatherApi.Domain.Http; - -namespace Weather.API.Domain.Extensions -{ - public static class HttpDataResponses - { - public static HttpDataResponse AsBadRequest(IEnumerable errorMessages) - { - return new HttpDataResponse - { - StatusCode = System.Net.HttpStatusCode.BadRequest, - Errors = errorMessages.ToList() - }; - } - - public static HttpDataResponse AsBadRequest(string errorMessages) - { - return new HttpDataResponse - { - StatusCode = System.Net.HttpStatusCode.BadRequest, - Errors = new List { errorMessages } - }; - } - - public static HttpDataResponse AsInternalServerError(IEnumerable errorMessages) - { - return new HttpDataResponse - { - StatusCode = System.Net.HttpStatusCode.InternalServerError, - Errors = errorMessages.ToList() - }; - } - - public static HttpDataResponse AsInternalServerError(string errorMessage) - { - return new HttpDataResponse - { - StatusCode = System.Net.HttpStatusCode.InternalServerError, - Errors = new List { errorMessage } - }; - } - - public static HttpDataResponse AsOK(T data) - { - return new HttpDataResponse - { - Data = data, - StatusCode = System.Net.HttpStatusCode.OK, - }; - } - - public static HttpDataResponse AsOK(T data, IEnumerable errorMessages) - { - return new HttpDataResponse - { - Data = data, - StatusCode = System.Net.HttpStatusCode.OK, - Errors = errorMessages.ToList() - }; - } - - public static HttpDataResponse AsNoContent() - { - return new HttpDataResponse - { - StatusCode = System.Net.HttpStatusCode.NoContent, - }; - } - } -} diff --git a/src/Weather.API/Domain/Extensions/IHandlerExtension.cs b/src/Weather.API/Domain/Extensions/IHandlerExtension.cs deleted file mode 100644 index 0b8dd08..0000000 --- a/src/Weather.API/Domain/Extensions/IHandlerExtension.cs +++ /dev/null @@ -1,14 +0,0 @@ -using Weather.API.Domain.Abstractions; -using WeatherApi.Domain.Http; - -namespace Weather.API.Domain.Extensions -{ - internal static class IHandlerExtension - { - internal static async Task SendAsync(this IRequestHandler requestHandler, TRequest request, CancellationToken cancellationToken) - { - var response = await requestHandler.HandleAsync(request, cancellationToken); - return Results.Json(new DataResponse { Data = response.Data, Errors = response.Errors }, statusCode: (int)response.StatusCode); - } - } -} diff --git a/src/Weather.API/Domain/Http/DataResponse.cs b/src/Weather.API/Domain/Http/DataResponse.cs deleted file mode 100644 index 04bd31d..0000000 --- a/src/Weather.API/Domain/Http/DataResponse.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace WeatherApi.Domain.Http -{ - public class DataResponse - { - public T? Data { get; init; } - - public IList Errors { get; init; } = new List(); - } -} diff --git a/src/Weather.API/Domain/Http/EmptyRequest.cs b/src/Weather.API/Domain/Http/EmptyRequest.cs deleted file mode 100644 index 6ba2a69..0000000 --- a/src/Weather.API/Domain/Http/EmptyRequest.cs +++ /dev/null @@ -1,20 +0,0 @@ -namespace WeatherApi.Domain.Http -{ - public class EmptyRequest - { - private static EmptyRequest? _instance; - public static EmptyRequest Instance - { - get - { - _instance ??= new EmptyRequest(); - return _instance; - } - } - - private EmptyRequest() - { - - } - } -} diff --git a/src/Weather.API/Domain/Http/HttpDataResponse.cs b/src/Weather.API/Domain/Http/HttpDataResponse.cs deleted file mode 100644 index 629fde8..0000000 --- a/src/Weather.API/Domain/Http/HttpDataResponse.cs +++ /dev/null @@ -1,10 +0,0 @@ -using System.Net; - -namespace WeatherApi.Domain.Http -{ - public class HttpDataResponse : DataResponse - { - public HttpStatusCode StatusCode { get; init; } - - } -} diff --git a/src/Weather.API/Features/AddFavorites/AddFavoriteHandler.cs b/src/Weather.API/Features/AddFavorites/AddFavoriteHandler.cs index fdb4eba..f1742d0 100644 --- a/src/Weather.API/Features/AddFavorites/AddFavoriteHandler.cs +++ b/src/Weather.API/Features/AddFavorites/AddFavoriteHandler.cs @@ -2,18 +2,18 @@ using AutoMapper; using FluentResults; using Microsoft.EntityFrameworkCore; +using SmallApiToolkit.Core.Extensions; +using SmallApiToolkit.Core.RequestHandlers; +using SmallApiToolkit.Core.Response; using Validot; -using Weather.API.Domain.Abstractions; using Weather.API.Domain.Database.EFContext; using Weather.API.Domain.Database.Entities; -using Weather.API.Domain.Extensions; using Weather.API.Domain.Logging; using Weather.API.Domain.Resources; -using WeatherApi.Domain.Http; namespace Weather.API.Features.Favorites.AddFavorites { - internal sealed class AddFavoriteHandler : IRequestHandler + internal sealed class AddFavoriteHandler : IHttpRequestHandler { private readonly IMapper _mapper; private readonly WeatherContext _weatherContext; diff --git a/src/Weather.API/Features/AddFavorites/ContainerConfigurationExtension.cs b/src/Weather.API/Features/AddFavorites/ContainerConfigurationExtension.cs index a0fe864..29cb69e 100644 --- a/src/Weather.API/Features/AddFavorites/ContainerConfigurationExtension.cs +++ b/src/Weather.API/Features/AddFavorites/ContainerConfigurationExtension.cs @@ -1,9 +1,10 @@ using Microsoft.AspNetCore.Mvc; +using SmallApiToolkit.Core.Extensions; +using SmallApiToolkit.Core.RequestHandlers; +using SmallApiToolkit.Extensions; using Validot; -using Weather.API.Domain.Abstractions; using Weather.API.Domain.Extensions; using Weather.API.Features.Favorites.AddFavorites; -using WeatherApi.Domain.Http; namespace Weather.API.Features.AddFavorites { @@ -11,10 +12,10 @@ public static class ContainerConfigurationExtension { public static IEndpointRouteBuilder BuildAddFavoriteWeatherEndpoints(this IEndpointRouteBuilder endpointRouteBuilder) { - endpointRouteBuilder.MapPost("v1/favorite", - async ([FromBody] AddFavoriteCommand addFavoriteCommand, [FromServices] IRequestHandler handler, CancellationToken cancellationToken) => + endpointRouteBuilder.MapPost("favorite", + async ([FromBody] AddFavoriteCommand addFavoriteCommand, [FromServices] IHttpRequestHandler handler, CancellationToken cancellationToken) => await handler.SendAsync(addFavoriteCommand, cancellationToken)) - .Produces>() + .ProducesDataResponse() .WithName("AddFavorite") .WithTags("Setters"); @@ -23,7 +24,7 @@ await handler.SendAsync(addFavoriteCommand, cancellationToken)) public static IServiceCollection AddAddFavorites(this IServiceCollection serviceCollection) => serviceCollection - .AddScoped, AddFavoriteHandler>() + .AddScoped, AddFavoriteHandler>() .AddValidotSingleton, AddFavoriteCommandSpecificationHolder, AddFavoriteCommand>(); } diff --git a/src/Weather.API/Features/DeleteFavorites/ContainerConfigurationExtension.cs b/src/Weather.API/Features/DeleteFavorites/ContainerConfigurationExtension.cs index b4b4210..7067620 100644 --- a/src/Weather.API/Features/DeleteFavorites/ContainerConfigurationExtension.cs +++ b/src/Weather.API/Features/DeleteFavorites/ContainerConfigurationExtension.cs @@ -1,8 +1,9 @@ using Microsoft.AspNetCore.Mvc; +using SmallApiToolkit.Core.Extensions; +using SmallApiToolkit.Core.RequestHandlers; +using SmallApiToolkit.Extensions; using Validot; -using Weather.API.Domain.Abstractions; using Weather.API.Domain.Extensions; -using WeatherApi.Domain.Http; namespace Weather.API.Features.DeleteFavorites { @@ -10,10 +11,10 @@ public static class ContainerConfigurationExtension { public static IEndpointRouteBuilder BuildDeleteFavoriteWeatherEndpoints(this IEndpointRouteBuilder endpointRouteBuilder) { - endpointRouteBuilder.MapDelete("v1/favorite/{id}", - async (int id, [FromServices] IRequestHandler handler, CancellationToken cancellationToken) => + endpointRouteBuilder.MapDelete("favorite/{id}", + async (int id, [FromServices] IHttpRequestHandler handler, CancellationToken cancellationToken) => await handler.SendAsync(new DeleteFavoriteCommand { Id = id }, cancellationToken)) - .Produces>() + .ProducesDataResponse() .WithName("DeleteFavorite") .WithTags("Delete"); @@ -22,7 +23,7 @@ await handler.SendAsync(new DeleteFavoriteCommand { Id = id }, cancellationToken public static IServiceCollection AddDeleteFavorites(this IServiceCollection serviceCollection) => serviceCollection - .AddScoped, DeleteFavoriteHandler>() + .AddScoped, DeleteFavoriteHandler>() .AddValidotSingleton, DeleteFavoriteCommandSpecificationHolder, DeleteFavoriteCommand>(); } diff --git a/src/Weather.API/Features/DeleteFavorites/DeleteFavoriteHandler.cs b/src/Weather.API/Features/DeleteFavorites/DeleteFavoriteHandler.cs index 37854e9..15d6439 100644 --- a/src/Weather.API/Features/DeleteFavorites/DeleteFavoriteHandler.cs +++ b/src/Weather.API/Features/DeleteFavorites/DeleteFavoriteHandler.cs @@ -1,17 +1,17 @@ using Ardalis.GuardClauses; using FluentResults; using Microsoft.EntityFrameworkCore; +using SmallApiToolkit.Core.Extensions; +using SmallApiToolkit.Core.RequestHandlers; +using SmallApiToolkit.Core.Response; using Validot; -using Weather.API.Domain.Abstractions; using Weather.API.Domain.Database.EFContext; -using Weather.API.Domain.Extensions; using Weather.API.Domain.Logging; using Weather.API.Domain.Resources; -using WeatherApi.Domain.Http; namespace Weather.API.Features.DeleteFavorites { - internal sealed class DeleteFavoriteHandler : IRequestHandler + internal sealed class DeleteFavoriteHandler : IHttpRequestHandler { private readonly WeatherContext _weatherContext; private readonly IValidator _validator; diff --git a/src/Weather.API/Features/GetCurrent/ContainerConfigurationExtension.cs b/src/Weather.API/Features/GetCurrent/ContainerConfigurationExtension.cs index 78b4618..82dec37 100644 --- a/src/Weather.API/Features/GetCurrent/ContainerConfigurationExtension.cs +++ b/src/Weather.API/Features/GetCurrent/ContainerConfigurationExtension.cs @@ -1,9 +1,10 @@ using Microsoft.AspNetCore.Mvc; +using SmallApiToolkit.Core.Extensions; +using SmallApiToolkit.Core.RequestHandlers; +using SmallApiToolkit.Extensions; using Validot; -using Weather.API.Domain.Abstractions; using Weather.API.Domain.Dtos; using Weather.API.Domain.Extensions; -using WeatherApi.Domain.Http; namespace Weather.API.Features.Weather.GetCurrent { @@ -11,10 +12,10 @@ public static class ContainerConfigurationExtension { public static IEndpointRouteBuilder BuildGetCurrentWeatherEndpoints(this IEndpointRouteBuilder endpointRouteBuilder) { - endpointRouteBuilder.MapGet("v1/current", - async (double latitude, double longitude, [FromServices] IRequestHandler handler, CancellationToken cancellationToken) => + endpointRouteBuilder.MapGet("current", + async (double latitude, double longitude, [FromServices] IHttpRequestHandler handler, CancellationToken cancellationToken) => await handler.SendAsync(new GetCurrentWeatherQuery(latitude, longitude), cancellationToken)) - .Produces>() + .ProducesDataResponse() .WithName("GetCurrentWeather") .WithTags("Getters"); return endpointRouteBuilder; @@ -22,7 +23,7 @@ await handler.SendAsync(new GetCurrentWeatherQuery(latitude, longitude), cancell public static IServiceCollection AddGetCurrentWeather(this IServiceCollection serviceCollection) => serviceCollection - .AddScoped, GetCurrentWeatherHandler>() + .AddScoped, GetCurrentWeatherHandler>() .AddValidotSingleton, CurrentWeatherDtoSpecificationHolder, CurrentWeatherDto>() .AddValidotSingleton, GetCurrentWeatherQuerySpecificationHolder, GetCurrentWeatherQuery>(); diff --git a/src/Weather.API/Features/GetCurrent/GetCurrentWeatherHandler.cs b/src/Weather.API/Features/GetCurrent/GetCurrentWeatherHandler.cs index 6d3b6de..5e788c0 100644 --- a/src/Weather.API/Features/GetCurrent/GetCurrentWeatherHandler.cs +++ b/src/Weather.API/Features/GetCurrent/GetCurrentWeatherHandler.cs @@ -1,15 +1,17 @@ using Ardalis.GuardClauses; +using SmallApiToolkit.Core.Extensions; +using SmallApiToolkit.Core.RequestHandlers; +using SmallApiToolkit.Core.Response; using Validot; using Weather.API.Domain.Abstractions; using Weather.API.Domain.Dtos; using Weather.API.Domain.Extensions; using Weather.API.Domain.Logging; using Weather.API.Domain.Resources; -using WeatherApi.Domain.Http; namespace Weather.API.Features.Weather.GetCurrent { - internal sealed class GetCurrentWeatherHandler : IRequestHandler + internal sealed class GetCurrentWeatherHandler : IHttpRequestHandler { private readonly IValidator _getCurrentWeatherQueryValidator; private readonly IValidator _currentWeatherValidator; diff --git a/src/Weather.API/Features/GetFavorites/ContainerConfigurationExtension.cs b/src/Weather.API/Features/GetFavorites/ContainerConfigurationExtension.cs index bc7c8c4..e0be391 100644 --- a/src/Weather.API/Features/GetFavorites/ContainerConfigurationExtension.cs +++ b/src/Weather.API/Features/GetFavorites/ContainerConfigurationExtension.cs @@ -1,10 +1,9 @@ using Microsoft.AspNetCore.Mvc; -using Weather.API.Domain.Abstractions; -using Weather.API.Domain.Extensions; -using Weather.API.Features.AddFavorites; +using SmallApiToolkit.Core.Extensions; +using SmallApiToolkit.Core.RequestHandlers; +using SmallApiToolkit.Core.Response; +using SmallApiToolkit.Extensions; using Weather.API.Features.Favorites.GetFavorites; -using Weather.API.Features.GetFavorites; -using WeatherApi.Domain.Http; namespace Weather.API.Features.GetFavorites { @@ -12,10 +11,10 @@ public static class ContainerConfigurationExtension { public static IEndpointRouteBuilder BuildGetFavoriteWeatherEndpoints(this IEndpointRouteBuilder endpointRouteBuilder) { - endpointRouteBuilder.MapGet("v1/favorites", - async ([FromServices] IRequestHandler handler, CancellationToken cancellationToken) => + endpointRouteBuilder.MapGet("favorites", + async ([FromServices] IHttpRequestHandler handler, CancellationToken cancellationToken) => await handler.SendAsync(EmptyRequest.Instance, cancellationToken)) - .Produces>() + .ProducesDataResponse() .WithName("GetFavorites") .WithTags("Getters"); @@ -24,6 +23,6 @@ await handler.SendAsync(EmptyRequest.Instance, cancellationToken)) public static IServiceCollection AddGetFavorites(this IServiceCollection serviceCollection) => serviceCollection - .AddScoped, GetFavoritesHandler>(); + .AddScoped, GetFavoritesHandler>(); } } diff --git a/src/Weather.API/Features/GetFavorites/GetFavoritesHandler.cs b/src/Weather.API/Features/GetFavorites/GetFavoritesHandler.cs index 9585338..f0b92c6 100644 --- a/src/Weather.API/Features/GetFavorites/GetFavoritesHandler.cs +++ b/src/Weather.API/Features/GetFavorites/GetFavoritesHandler.cs @@ -2,6 +2,9 @@ using AutoMapper; using FluentResults; using Microsoft.EntityFrameworkCore; +using SmallApiToolkit.Core.Extensions; +using SmallApiToolkit.Core.RequestHandlers; +using SmallApiToolkit.Core.Response; using Validot; using Weather.API.Domain.Abstractions; using Weather.API.Domain.Database.EFContext; @@ -11,11 +14,10 @@ using Weather.API.Domain.Logging; using Weather.API.Domain.Resources; using Weather.API.Features.GetFavorites; -using WeatherApi.Domain.Http; namespace Weather.API.Features.Favorites.GetFavorites { - internal sealed class GetFavoritesHandler : IRequestHandler + internal sealed class GetFavoritesHandler : IHttpRequestHandler { private readonly IValidator _locationValidator; private readonly IValidator _currentWeatherValidator; diff --git a/src/Weather.API/Features/GetForecast/ContainerConfigurationExtension.cs b/src/Weather.API/Features/GetForecast/ContainerConfigurationExtension.cs index d282585..9d0e4db 100644 --- a/src/Weather.API/Features/GetForecast/ContainerConfigurationExtension.cs +++ b/src/Weather.API/Features/GetForecast/ContainerConfigurationExtension.cs @@ -1,8 +1,9 @@ using Microsoft.AspNetCore.Mvc; +using SmallApiToolkit.Core.Extensions; +using SmallApiToolkit.Core.RequestHandlers; +using SmallApiToolkit.Extensions; using Validot; -using Weather.API.Domain.Abstractions; using Weather.API.Domain.Extensions; -using WeatherApi.Domain.Http; namespace Weather.API.Features.Weather.GetForecast { @@ -10,10 +11,10 @@ public static class ContainerConfigurationExtension { public static IEndpointRouteBuilder BuildGetForecastWeatherEndpoints(this IEndpointRouteBuilder endpointRouteBuilder) { - endpointRouteBuilder.MapGet("v1/forecast", - async (double latitude, double longitude, [FromServices] IRequestHandler handler, CancellationToken cancellationToken) => + endpointRouteBuilder.MapGet("forecast", + async (double latitude, double longitude, [FromServices] IHttpRequestHandler handler, CancellationToken cancellationToken) => await handler.SendAsync(new GetForecastWeatherQuery(latitude, longitude), cancellationToken)) - .Produces>() + .ProducesDataResponse() .WithName("GetForecastWeather") .WithTags("Getters"); @@ -21,7 +22,7 @@ await handler.SendAsync(new GetForecastWeatherQuery(latitude, longitude), cancel } public static IServiceCollection AddGetForecastWeather(this IServiceCollection serviceCollection) => serviceCollection - .AddScoped, GetForecastWeatherHandler>() + .AddScoped, GetForecastWeatherHandler>() .AddValidotSingleton, ForecastWeatherDtoSpecificationHolder, ForecastWeatherDto>() .AddValidotSingleton, GetForecastWeatherSpecificationHolder, GetForecastWeatherQuery>() .AddAutoMapper(typeof(ForecastProfile)); diff --git a/src/Weather.API/Features/GetForecast/GetForecastWeatherHandler.cs b/src/Weather.API/Features/GetForecast/GetForecastWeatherHandler.cs index 29efb07..fd25757 100644 --- a/src/Weather.API/Features/GetForecast/GetForecastWeatherHandler.cs +++ b/src/Weather.API/Features/GetForecast/GetForecastWeatherHandler.cs @@ -1,14 +1,16 @@ using Ardalis.GuardClauses; +using SmallApiToolkit.Core.Extensions; +using SmallApiToolkit.Core.RequestHandlers; +using SmallApiToolkit.Core.Response; using Validot; using Weather.API.Domain.Abstractions; using Weather.API.Domain.Extensions; using Weather.API.Domain.Logging; using Weather.API.Domain.Resources; -using WeatherApi.Domain.Http; namespace Weather.API.Features.Weather.GetForecast { - internal sealed class GetForecastWeatherHandler : IRequestHandler + internal sealed class GetForecastWeatherHandler : IHttpRequestHandler { private readonly IValidator _getForecastWeatherQueryValidator; private readonly IValidator _forecastWeatherValidator; diff --git a/src/Weather.API/Middleware/ExceptionMiddleware.cs b/src/Weather.API/Middleware/ExceptionMiddleware.cs deleted file mode 100644 index 434896a..0000000 --- a/src/Weather.API/Middleware/ExceptionMiddleware.cs +++ /dev/null @@ -1,56 +0,0 @@ -using Ardalis.GuardClauses; -using Newtonsoft.Json; -using System.Net; -using Weather.API.Domain.Logging; -using WeatherApi.Domain.Http; - -namespace Weather.API.Middleware -{ - public sealed class ExceptionMiddleware - { - private readonly RequestDelegate _next; - private readonly ILogger _logger; - - public ExceptionMiddleware(RequestDelegate next, ILogger logger) - { - _next = Guard.Against.Null(next); - _logger = Guard.Against.Null(logger); - } - - public async Task InvokeAsync(HttpContext context) - { - try - { - await _next(context); - } - catch (Exception generalEx) - { - _logger.LogError(LogEvents.GeneralError, generalEx, "Unexpected error occurred."); - await WriteResponseAsync(generalEx, context); - } - } - - private async Task WriteResponseAsync(Exception generalEx, HttpContext context) - { - var (responseCode, responseMessage) = ExtractFromException(generalEx); - context.Response.ContentType = "application/json"; - context.Response.StatusCode = (int)responseCode; - var jsonResult = CreateResponseJson(responseMessage); - await context.Response.WriteAsync(jsonResult); - } - - private string CreateResponseJson(string errorMessage) - { - var response = new DataResponse(); - response.Errors.Add(errorMessage); - return JsonConvert.SerializeObject(response); - } - - private (HttpStatusCode responseCode, string responseMessage) ExtractFromException(Exception generalEx) - => generalEx switch - { - TaskCanceledException taskCanceledException =>(HttpStatusCode.NoContent, taskCanceledException.Message), - _ => (HttpStatusCode.InternalServerError, "Generic error occurred on server. Check logs for more info.") - }; - } -} diff --git a/src/Weather.API/Program.cs b/src/Weather.API/Program.cs index ef48b6d..6d875a0 100644 --- a/src/Weather.API/Program.cs +++ b/src/Weather.API/Program.cs @@ -1,15 +1,16 @@ +using SmallApiToolkit.Extensions; +using SmallApiToolkit.Middleware; using Weather.API.Configuration; using Weather.API.Features.AddFavorites; using Weather.API.Features.DeleteFavorites; -using Weather.API.Features.Favorites.AddFavorites; -using Weather.API.Features.Favorites.GetFavorites; using Weather.API.Features.GetFavorites; using Weather.API.Features.Weather.GetCurrent; using Weather.API.Features.Weather.GetForecast; -using Weather.API.Middleware; var builder = WebApplication.CreateBuilder(args); +builder.AddLogging(LogLevel.Debug); + builder.Services.AddDomain(builder.Configuration); builder.Services .AddAddFavorites() @@ -32,9 +33,11 @@ app.UseHttpsRedirection(); app.UseMiddleware(); +app.UseMiddleware(); app .MapGroup("weather") + .MapVersionGroup(1) .BuildAddFavoriteWeatherEndpoints() .BuildGetFavoriteWeatherEndpoints() .BuildGetForecastWeatherEndpoints() diff --git a/src/Weather.API/Weather.API.csproj b/src/Weather.API/Weather.API.csproj index 8602621..6949aff 100644 --- a/src/Weather.API/Weather.API.csproj +++ b/src/Weather.API/Weather.API.csproj @@ -9,14 +9,16 @@ - + - - - + + + - + + + diff --git a/src/global.json b/src/global.json index e2138e0..7fa817c 100644 --- a/src/global.json +++ b/src/global.json @@ -1,5 +1,5 @@ { "sdk": { - "version": "8.0.200" + "version": "8.0.300" } } \ No newline at end of file