From 425dfe37ba0c4fc10c2bae33f88eefc266406dec Mon Sep 17 00:00:00 2001 From: Nano Taboada <87288+nanotaboada@users.noreply.github.com> Date: Thu, 2 Apr 2026 02:04:47 -0300 Subject: [PATCH] fix(api): return 200 OK on empty collection and ignore Id in AutoMapper (#425) Co-authored-by: Claude Sonnet 4.6 --- CHANGELOG.md | 3 +++ .../Controllers/PlayerController.cs | 22 ++++--------------- .../Mappings/PlayerMappingProfile.cs | 1 + .../Unit/PlayerControllerTests.cs | 7 +++--- 4 files changed, 12 insertions(+), 21 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d0b54c3..08fb74d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -48,6 +48,9 @@ This project uses famous football stadiums (A-Z) that hosted FIFA World Cup matc ### Fixed +- `GET /players` now returns `200 OK` with an empty list `[]` when no players exist, instead of `404 Not Found` (#425) +- AutoMapper `Player → PlayerResponseModel` profile now explicitly ignores the `Id` source member via `ForSourceMember`, making the exclusion intentional rather than implicit (#425) + ### Removed --- diff --git a/src/Dotnet.Samples.AspNetCore.WebApi/Controllers/PlayerController.cs b/src/Dotnet.Samples.AspNetCore.WebApi/Controllers/PlayerController.cs index 1bf26ca..69c7046 100644 --- a/src/Dotnet.Samples.AspNetCore.WebApi/Controllers/PlayerController.cs +++ b/src/Dotnet.Samples.AspNetCore.WebApi/Controllers/PlayerController.cs @@ -69,7 +69,7 @@ public async Task PostAsync([FromBody] PlayerRequestModel player) Title = "Conflict", Status = StatusCodes.Status409Conflict, Detail = $"Player with Squad Number '{player.SquadNumber}' already exists.", - Instance = HttpContext?.Request?.Path.ToString() + Instance = HttpContext?.Request?.Path.ToString(), } ); } @@ -92,29 +92,15 @@ public async Task PostAsync([FromBody] PlayerRequestModel player) /// Retrieves all Players /// /// OK - /// Not Found [HttpGet(Name = "Retrieve")] [ProducesResponseType(StatusCodes.Status200OK)] - [ProducesResponseType(StatusCodes.Status404NotFound)] public async Task GetAsync() { var players = await playerService.RetrieveAsync(); - if (players.Count > 0) - { - logger.LogInformation("GET /players retrieved"); - return TypedResults.Ok(players); - } - else - { - logger.LogWarning("GET /players not found"); - return TypedResults.Problem( - statusCode: StatusCodes.Status404NotFound, - title: NotFoundTitle, - detail: "No players were found.", - instance: HttpContext?.Request?.Path.ToString() - ); - } + logger.LogInformation("GET /players retrieved {Count} player(s)", players.Count); + + return TypedResults.Ok(players); } /// diff --git a/src/Dotnet.Samples.AspNetCore.WebApi/Mappings/PlayerMappingProfile.cs b/src/Dotnet.Samples.AspNetCore.WebApi/Mappings/PlayerMappingProfile.cs index 1d7ee76..f698d03 100644 --- a/src/Dotnet.Samples.AspNetCore.WebApi/Mappings/PlayerMappingProfile.cs +++ b/src/Dotnet.Samples.AspNetCore.WebApi/Mappings/PlayerMappingProfile.cs @@ -28,6 +28,7 @@ public PlayerMappingProfile() // Player → PlayerResponseModel CreateMap() + .ForSourceMember(source => source.Id, options => options.DoNotValidate()) .ForMember( destination => destination.FullName, options => diff --git a/test/Dotnet.Samples.AspNetCore.WebApi.Tests/Unit/PlayerControllerTests.cs b/test/Dotnet.Samples.AspNetCore.WebApi.Tests/Unit/PlayerControllerTests.cs index 72deea7..e4e6396 100644 --- a/test/Dotnet.Samples.AspNetCore.WebApi.Tests/Unit/PlayerControllerTests.cs +++ b/test/Dotnet.Samples.AspNetCore.WebApi.Tests/Unit/PlayerControllerTests.cs @@ -183,7 +183,7 @@ public async Task Get_Players_Existing_ReturnsPlayers() [Fact] [Trait("Category", "Unit")] - public async Task Get_Players_NonExisting_Returns404NotFound() + public async Task Get_Players_Empty_Returns200OkWithEmptyList() { // Arrange var (service, logger, validator) = PlayerMocks.InitControllerMocks(); @@ -196,8 +196,9 @@ public async Task Get_Players_NonExisting_Returns404NotFound() // Assert service.Verify(service => service.RetrieveAsync(), Times.Once); - var httpResult = result.Should().BeOfType().Subject; - httpResult.StatusCode.Should().Be(StatusCodes.Status404NotFound); + var httpResult = result.Should().BeOfType>>().Subject; + httpResult.StatusCode.Should().Be(StatusCodes.Status200OK); + httpResult.Value.Should().NotBeNull().And.BeEmpty(); } [Fact]