diff --git a/API/API.csproj b/API/API.csproj index dda2eff..71218b9 100644 --- a/API/API.csproj +++ b/API/API.csproj @@ -7,6 +7,8 @@ + + runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/API/Controllers/ErrorController.cs b/API/Controllers/ErrorController.cs index 4d1ec2c..479fc1a 100644 --- a/API/Controllers/ErrorController.cs +++ b/API/Controllers/ErrorController.cs @@ -4,6 +4,7 @@ using Microsoft.AspNetCore.Mvc; namespace API.Controllers { [Route("errors/{code}")] + [ApiExplorerSettings(IgnoreApi = true)] public class ErrorController : BaseApiController { public IActionResult Error(int code) diff --git a/API/Controllers/ProductsController.cs b/API/Controllers/ProductsController.cs index 1cde49e..86a09d5 100644 --- a/API/Controllers/ProductsController.cs +++ b/API/Controllers/ProductsController.cs @@ -4,6 +4,7 @@ using Core.Interfaces; using Core.Specifications; using API.Dtos; using AutoMapper; +using API.Errors; namespace API.Controllers { @@ -31,10 +32,13 @@ namespace API.Controllers } [HttpGet("{id}")] + [ProducesResponseType(StatusCodes.Status200OK)] + [ProducesResponseType(typeof(ApiResponse), StatusCodes.Status404NotFound)] public async Task> GetProduct(int id) { var spec = new ProductsWithTypesAndBrandsSpecification(id); var product = await _productsRepo.GetEntityWithSpec(spec); + if (product == null) return NotFound(new ApiResponse(404)); return _mapper.Map(product); } diff --git a/API/Controllers/WeatherForecastController.cs b/API/Controllers/WeatherForecastController.cs index b879c25..76603ca 100644 --- a/API/Controllers/WeatherForecastController.cs +++ b/API/Controllers/WeatherForecastController.cs @@ -4,6 +4,7 @@ namespace API.Controllers; [ApiController] [Route("[controller]")] +[ApiExplorerSettings(IgnoreApi = true)] public class WeatherForecastController : ControllerBase { private static readonly string[] Summaries = new[] diff --git a/API/Errors/ApiValidationErrorReponse.cs b/API/Errors/ApiValidationErrorReponse.cs deleted file mode 100644 index a9bb644..0000000 --- a/API/Errors/ApiValidationErrorReponse.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace API.Errors -{ - public class ApiValidationErrorReponse - { - - } -} \ No newline at end of file diff --git a/API/Errors/ApiValidationErrorResponse.cs b/API/Errors/ApiValidationErrorResponse.cs new file mode 100644 index 0000000..5f6027e --- /dev/null +++ b/API/Errors/ApiValidationErrorResponse.cs @@ -0,0 +1,11 @@ +namespace API.Errors +{ + public class ApiValidationErrorResponse : ApiResponse + { + public ApiValidationErrorResponse() : base(400) + { + } + + public IEnumerable Errors { get; set; } + } +} \ No newline at end of file diff --git a/API/Extensions/ApplicationServicesExtensions.cs b/API/Extensions/ApplicationServicesExtensions.cs new file mode 100644 index 0000000..532ef9f --- /dev/null +++ b/API/Extensions/ApplicationServicesExtensions.cs @@ -0,0 +1,32 @@ +using API.Errors; +using Core.Interfaces; +using Infrastructure.Data; +using Microsoft.AspNetCore.Mvc; + +namespace API.Extensions +{ + public static class ApplicationServicesExtensions + { + public static IServiceCollection AddApplicationServices(this IServiceCollection services) + { + services.AddScoped(); + services.AddScoped(typeof(IGenericRepository<>), (typeof(GenericRepository<>))); + services.Configure(options => + options.InvalidModelStateResponseFactory = actionContext => + { + var errors = actionContext.ModelState + .Where(e => e.Value.Errors.Count > 0) + .SelectMany(x => x.Value.Errors) + .Select(x => x.ErrorMessage).ToArray(); + + var errorRepsponse = new ApiValidationErrorResponse + { + Errors = errors + }; + + return new BadRequestObjectResult(errorRepsponse); + }); + return services; + } + } +} \ No newline at end of file diff --git a/API/Extensions/SwaggerServiceExtensions.cs b/API/Extensions/SwaggerServiceExtensions.cs new file mode 100644 index 0000000..1d8d41c --- /dev/null +++ b/API/Extensions/SwaggerServiceExtensions.cs @@ -0,0 +1,25 @@ +using Microsoft.OpenApi.Models; + +namespace API.Extensions +{ + public static class SwaggerServiceExtensions + { + public static IServiceCollection AddSwaggerDocumentation(this IServiceCollection services) + { + services.AddSwaggerGen(c => + { + c.SwaggerDoc("v1", new OpenApiInfo { Title = "WebAPIv5", Version = "v1" }); + }); + + return services; + } + + public static IApplicationBuilder UseSwaggerDocumentation(this IApplicationBuilder app) + { + app.UseSwagger(); + app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "WebAPIv5 v1")); + + return app; + } + } +} \ No newline at end of file diff --git a/API/Startup.cs b/API/Startup.cs index ca0b28a..6fe1c3a 100644 --- a/API/Startup.cs +++ b/API/Startup.cs @@ -1,9 +1,8 @@ +using API.Extensions; using API.Helpers; using API.Middleware; -using Core.Interfaces; using Infrastructure.Data; using Microsoft.EntityFrameworkCore; -using Microsoft.OpenApi.Models; namespace API { @@ -21,14 +20,11 @@ namespace API { services.AddControllers(); + services.AddApplicationServices(); + services.AddSwaggerDocumentation(); services.AddDbContext(x => x.UseSqlite(_config.GetConnectionString("DefaultConnection"))); - services.AddScoped(); - services.AddScoped(typeof(IGenericRepository<>), (typeof(GenericRepository<>))); services.AddAutoMapper(typeof(MappingProfiles)); - services.AddSwaggerGen(c => - { - c.SwaggerDoc("v1", new OpenApiInfo { Title = "WebAPIv5", Version = "v1" }); - }); + } // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. @@ -36,12 +32,6 @@ namespace API { app.UseMiddleware(); - if (env.IsDevelopment()) - { - app.UseSwagger(); - app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "WebAPIv5 v1")); - } - app.UseStatusCodePagesWithReExecute("/errors/{0}"); app.UseHttpsRedirection(); @@ -50,6 +40,7 @@ namespace API app.UseStaticFiles(); app.UseAuthorization(); + app.UseSwaggerDocumentation(); app.UseEndpoints(endpoints => {