Files
Musify/backend/Musify.Api/Endpoints/UserEndpoints.cs
T
Admin 695f4378c6 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.
2026-07-05 21:04:15 +02:00

72 lines
2.3 KiB
C#

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;
namespace Musify.Api.Endpoints;
public static class UserEndpoints
{
public static IEndpointRouteBuilder MapUserEndpoints(this IEndpointRouteBuilder app)
{
var group = app.MapGroup("/users")
.WithTags("Users");
group.MapGet("/", GetUsers)
.WithName("GetUsers")
.WithSummary("Get Paginated Users.")
.Produces<PaginatedResponse<UserApplicationResponse>>();
group.MapGet("/{id}", GetUserById)
.WithName("GetUserById")
.WithSummary("Get A User By Id.")
.Produces<UserApplicationResponse>()
.Produces(StatusCodes.Status404NotFound);
group.MapPost("/", CreateUser)
.WithName("CreateUser")
.WithSummary("Create A New User.")
.AddEndpointFilter<ValidationFilter<CreateUserRequest>>()
.Produces<UserApplicationResponse>(StatusCodes.Status201Created)
.ProducesValidationProblem()
.Produces(StatusCodes.Status409Conflict);
return app;
}
private static async Task<IResult> GetUsers(
IMediator mediator,
CancellationToken cancellationToken,
string? usernameSearch,
int pageNumber = 1,
int pageSize = 10)
{
var result = await mediator.Send(new GetUsersQuery(pageNumber, pageSize, usernameSearch), cancellationToken);
return result.ToHttpResult();
}
private static async Task<IResult> GetUserById(
IMediator mediator,
long id,
CancellationToken cancellationToken)
{
var result = await mediator.Send(new GetUserByIdQuery(id), cancellationToken);
return result.ToHttpResult();
}
private static async Task<IResult> CreateUser(
IMediator mediator,
CreateUserRequest request,
CancellationToken cancellationToken)
{
var result = await mediator.Send(
new CreateUserCommand(request.Id, request.Name, request.FirstName, request.SecondName),
cancellationToken);
return result.ToCreatedResult(user => $"/users/{user.Id}");
}
}