diff --git a/API/Controllers/BaseApiController.cs b/API/Controllers/BaseApiController.cs new file mode 100644 index 0000000..79e3af0 --- /dev/null +++ b/API/Controllers/BaseApiController.cs @@ -0,0 +1,11 @@ +using Microsoft.AspNetCore.Mvc; + +namespace API.Controllers +{ + [ApiController] + [Route("api/[controller]")] + public class BaseApiController : ControllerBase + { + + } +} \ No newline at end of file diff --git a/API/Controllers/BuggyController.cs b/API/Controllers/BuggyController.cs new file mode 100644 index 0000000..6504349 --- /dev/null +++ b/API/Controllers/BuggyController.cs @@ -0,0 +1,47 @@ +using API.Errors; +using Infrastructure.Data; +using Microsoft.AspNetCore.Mvc; + +namespace API.Controllers +{ + public class BuggyController : BaseApiController + { + private readonly StoreContext _context; + public BuggyController(StoreContext context) + { + _context = context; + } + + [HttpGet("notfound")] + public ActionResult GetNotFoundRequest() + { + var thing = _context.Products.Find(42); + if (thing == null) + { + return NotFound(new ApiResponse(404)); + } + + return Ok(); + } + + [HttpGet("servererror")] + public ActionResult GetServerError() + { + var thing = _context.Products.Find(42); + var thingToReturn = thing.ToString(); + return Ok(); + } + + [HttpGet("badrequest")] + public ActionResult GetBadRequest() + { + return BadRequest(new ApiResponse(400)); + } + + [HttpGet("badrequest/{id}")] + public ActionResult GetNotFoundRequest(int id) + { + return Ok(); + } + } +} \ No newline at end of file diff --git a/API/Controllers/ErrorController.cs b/API/Controllers/ErrorController.cs new file mode 100644 index 0000000..4d1ec2c --- /dev/null +++ b/API/Controllers/ErrorController.cs @@ -0,0 +1,14 @@ +using API.Errors; +using Microsoft.AspNetCore.Mvc; + +namespace API.Controllers +{ + [Route("errors/{code}")] + public class ErrorController : BaseApiController + { + public IActionResult Error(int code) + { + return new ObjectResult(new ApiResponse(code)); + } + } +} \ No newline at end of file diff --git a/API/Controllers/ProductsController.cs b/API/Controllers/ProductsController.cs index fcd46f9..1cde49e 100644 --- a/API/Controllers/ProductsController.cs +++ b/API/Controllers/ProductsController.cs @@ -7,9 +7,7 @@ using AutoMapper; namespace API.Controllers { - [ApiController] - [Route("api/[controller]")] - public class ProductsController : ControllerBase + public class ProductsController : BaseApiController { private readonly IGenericRepository _productsRepo; private readonly IGenericRepository _productBrandRepo; diff --git a/API/Errors/ApiException.cs b/API/Errors/ApiException.cs new file mode 100644 index 0000000..70a2cde --- /dev/null +++ b/API/Errors/ApiException.cs @@ -0,0 +1,12 @@ +namespace API.Errors +{ + public class ApiException : ApiResponse + { + public ApiException(int statusCode, string message = null, string details = null) : base(statusCode, message) + { + Details = details; + } + + public string Details { get; set; } + } +} \ No newline at end of file diff --git a/API/Errors/ApiResponse.cs b/API/Errors/ApiResponse.cs new file mode 100644 index 0000000..8d59c3d --- /dev/null +++ b/API/Errors/ApiResponse.cs @@ -0,0 +1,31 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace API.Errors +{ + public class ApiResponse + { + public ApiResponse(int statusCode, string message = null) + { + StatusCode = statusCode; + Message = message ?? GetDefaultMessageForStatusCode(statusCode); + } + + public int StatusCode { get; set; } + public string Message { get; set; } + + private string GetDefaultMessageForStatusCode(int statusCode) + { + return statusCode switch + { + 400 => "A bad request, you have made", + 401 => "Authorized, you are not", + 404 => "Resource found, it was not", + 500 => "Errors are the path to the dark side. Errors lead to anger. Anger leads to hate. Hate leads to career change", + _ => null + }; + } + } +} \ No newline at end of file diff --git a/API/Middleware/ExceptionMiddleware.cs b/API/Middleware/ExceptionMiddleware.cs new file mode 100644 index 0000000..8c2bca7 --- /dev/null +++ b/API/Middleware/ExceptionMiddleware.cs @@ -0,0 +1,39 @@ +using System.Net; +using System.Text.Json; +using API.Errors; + +namespace API.Middleware +{ + public class ExceptionMiddleware + { + private readonly RequestDelegate _next; + private readonly ILogger _logger; + private readonly IHostEnvironment _env; + public ExceptionMiddleware(RequestDelegate next, ILogger logger, IHostEnvironment env) + { + _env = env; + _logger = logger; + _next = next; + } + + public async Task InvokeAsync(HttpContext context) + { + try + { + await _next(context); + } + catch (Exception ex) + { + _logger.LogError(ex, ex.Message); + context.Response.ContentType = "application/json"; + context.Response.StatusCode = (int)HttpStatusCode.InternalServerError; + var response = _env.IsDevelopment() + ? new ApiException((int)HttpStatusCode.InternalServerError, ex.Message, ex.StackTrace.ToString()) + : new ApiException((int)HttpStatusCode.InternalServerError); + var options = new JsonSerializerOptions{PropertyNamingPolicy = JsonNamingPolicy.CamelCase}; + var json = JsonSerializer.Serialize(response, options); + await context.Response.WriteAsync(json); + } + } + } +} \ No newline at end of file diff --git a/API/Startup.cs b/API/Startup.cs index 8d9d6fc..ca0b28a 100644 --- a/API/Startup.cs +++ b/API/Startup.cs @@ -1,4 +1,5 @@ using API.Helpers; +using API.Middleware; using Core.Interfaces; using Infrastructure.Data; using Microsoft.EntityFrameworkCore; @@ -33,16 +34,20 @@ namespace API // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { + app.UseMiddleware(); + if (env.IsDevelopment()) { - app.UseDeveloperExceptionPage(); app.UseSwagger(); app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "WebAPIv5 v1")); } + app.UseStatusCodePagesWithReExecute("/errors/{0}"); + app.UseHttpsRedirection(); app.UseRouting(); + app.UseStaticFiles(); app.UseAuthorization(); diff --git a/API/wwwroot/images/products/boot-ang1.png b/API/wwwroot/images/products/boot-ang1.png new file mode 100644 index 0000000..5039e6b Binary files /dev/null and b/API/wwwroot/images/products/boot-ang1.png differ diff --git a/API/wwwroot/images/products/boot-ang2.png b/API/wwwroot/images/products/boot-ang2.png new file mode 100644 index 0000000..22e0a79 Binary files /dev/null and b/API/wwwroot/images/products/boot-ang2.png differ diff --git a/API/wwwroot/images/products/boot-core1.png b/API/wwwroot/images/products/boot-core1.png new file mode 100644 index 0000000..e5261b3 Binary files /dev/null and b/API/wwwroot/images/products/boot-core1.png differ diff --git a/API/wwwroot/images/products/boot-core2.png b/API/wwwroot/images/products/boot-core2.png new file mode 100644 index 0000000..62dbd5e Binary files /dev/null and b/API/wwwroot/images/products/boot-core2.png differ diff --git a/API/wwwroot/images/products/boot-redis1.png b/API/wwwroot/images/products/boot-redis1.png new file mode 100644 index 0000000..a38ef38 Binary files /dev/null and b/API/wwwroot/images/products/boot-redis1.png differ diff --git a/API/wwwroot/images/products/glove-code1.png b/API/wwwroot/images/products/glove-code1.png new file mode 100644 index 0000000..5ceb39a Binary files /dev/null and b/API/wwwroot/images/products/glove-code1.png differ diff --git a/API/wwwroot/images/products/glove-code2.png b/API/wwwroot/images/products/glove-code2.png new file mode 100644 index 0000000..b108ece Binary files /dev/null and b/API/wwwroot/images/products/glove-code2.png differ diff --git a/API/wwwroot/images/products/glove-react1.png b/API/wwwroot/images/products/glove-react1.png new file mode 100644 index 0000000..3387102 Binary files /dev/null and b/API/wwwroot/images/products/glove-react1.png differ diff --git a/API/wwwroot/images/products/glove-react2.png b/API/wwwroot/images/products/glove-react2.png new file mode 100644 index 0000000..17f097f Binary files /dev/null and b/API/wwwroot/images/products/glove-react2.png differ diff --git a/API/wwwroot/images/products/hat-core1.png b/API/wwwroot/images/products/hat-core1.png new file mode 100644 index 0000000..c8c6924 Binary files /dev/null and b/API/wwwroot/images/products/hat-core1.png differ diff --git a/API/wwwroot/images/products/hat-react1.png b/API/wwwroot/images/products/hat-react1.png new file mode 100644 index 0000000..5f44e3d Binary files /dev/null and b/API/wwwroot/images/products/hat-react1.png differ diff --git a/API/wwwroot/images/products/hat-react2.png b/API/wwwroot/images/products/hat-react2.png new file mode 100644 index 0000000..9a4c09b Binary files /dev/null and b/API/wwwroot/images/products/hat-react2.png differ diff --git a/API/wwwroot/images/products/sb-ang1.png b/API/wwwroot/images/products/sb-ang1.png new file mode 100644 index 0000000..a8ebd7f Binary files /dev/null and b/API/wwwroot/images/products/sb-ang1.png differ diff --git a/API/wwwroot/images/products/sb-ang2.png b/API/wwwroot/images/products/sb-ang2.png new file mode 100644 index 0000000..ccb6190 Binary files /dev/null and b/API/wwwroot/images/products/sb-ang2.png differ diff --git a/API/wwwroot/images/products/sb-core1.png b/API/wwwroot/images/products/sb-core1.png new file mode 100644 index 0000000..e6fc4b6 Binary files /dev/null and b/API/wwwroot/images/products/sb-core1.png differ diff --git a/API/wwwroot/images/products/sb-core2.png b/API/wwwroot/images/products/sb-core2.png new file mode 100644 index 0000000..f9c37a0 Binary files /dev/null and b/API/wwwroot/images/products/sb-core2.png differ diff --git a/API/wwwroot/images/products/sb-react1.png b/API/wwwroot/images/products/sb-react1.png new file mode 100644 index 0000000..84917c3 Binary files /dev/null and b/API/wwwroot/images/products/sb-react1.png differ diff --git a/API/wwwroot/images/products/sb-ts1.png b/API/wwwroot/images/products/sb-ts1.png new file mode 100644 index 0000000..eae0387 Binary files /dev/null and b/API/wwwroot/images/products/sb-ts1.png differ