refactor(api): OpenAPI response metadata, cached user sync, ProblemDetails

- Document every endpoint's responses (Produces<T>/status codes/validation)
  so the generated OpenAPI/Scalar docs carry response schemas and status codes
  instead of empty responses
- Cache recently-synced user ids (IMemoryCache, 15 min) in the JWT
  TokenValidated handler so user provisioning no longer hits the DB on every
  authenticated request
- Add ProblemDetails + UseExceptionHandler for consistent RFC7807 errors
- Add ToCreatedResult ErrorOr helper and use it in the create endpoints
- Normalize the playlists route to lowercase (/playlists)

Verified: booted the Api against RabbitMQ + Postgres in Docker and inspected
/openapi/v1.json — operations now expose response schemas/status codes and the
route is /playlists.

Build: 0 warnings, 0 errors.
This commit is contained in:
2026-07-05 21:04:15 +02:00
parent c4f5e6754c
commit 695f4378c6
7 changed files with 109 additions and 34 deletions
+12 -7
View File
@@ -1,5 +1,7 @@
using Mediator;
using Musify.Application.Users;
using Musify.Application.Users.Responses;
using Musify.Application.Shared;
using Musify.Api.DataTransferObjects.Users;
using Musify.Api.Extensions;
using Musify.Api.Filters;
@@ -15,16 +17,22 @@ public static class UserEndpoints
group.MapGet("/", GetUsers)
.WithName("GetUsers")
.WithSummary("Get Paginated Users.");
.WithSummary("Get Paginated Users.")
.Produces<PaginatedResponse<UserApplicationResponse>>();
group.MapGet("/{id}", GetUserById)
.WithName("GetUserById")
.WithSummary("Get A User By Id.");
.WithSummary("Get A User By Id.")
.Produces<UserApplicationResponse>()
.Produces(StatusCodes.Status404NotFound);
group.MapPost("/", CreateUser)
.WithName("CreateUser")
.WithSummary("Create A New User.")
.AddEndpointFilter<ValidationFilter<CreateUserRequest>>();
.AddEndpointFilter<ValidationFilter<CreateUserRequest>>()
.Produces<UserApplicationResponse>(StatusCodes.Status201Created)
.ProducesValidationProblem()
.Produces(StatusCodes.Status409Conflict);
return app;
}
@@ -58,9 +66,6 @@ public static class UserEndpoints
new CreateUserCommand(request.Id, request.Name, request.FirstName, request.SecondName),
cancellationToken);
if (result.IsError)
return result.ToHttpResult();
return Results.Created($"/users/{result.Value.Id}", result.Value);
return result.ToCreatedResult(user => $"/users/{user.Id}");
}
}