Enhance API endpoints with response type annotations
CI / Backend (build + test) (push) Successful in 1m15s
CI / Frontend (lint + typecheck + build) (push) Successful in 30s

- Updated various API endpoints to include response type annotations using .Produces<T>() for better documentation and type safety.
- Enhanced activation, admin, user, config, and other endpoints to specify response types, improving clarity for frontend integration.
- Added new DTOs for structured responses in authentication and Telegram-related endpoints.
- Improved overall API schema generation to reflect these changes, ensuring consistency between backend and frontend types.
This commit is contained in:
Leonid Pershin
2026-07-02 12:56:03 +03:00
parent 8067be3c35
commit 8b92204733
15 changed files with 493 additions and 143 deletions
@@ -1,5 +1,6 @@
using PnvPanel.Api.Common;
using PnvPanel.Application.Common.Messaging;
using PnvPanel.Application.Configs;
using PnvPanel.Application.Configs.Create;
using PnvPanel.Application.Configs.Edit;
using PnvPanel.Application.Configs.GetConfigLink;
@@ -17,14 +18,14 @@ public static class ConfigEndpoints
{
var group = app.MapGroup("/api").WithTags("Configs").RequireAuthorization();
group.MapGet("/inbounds/available", ListAvailableInbounds);
group.MapGet("/configs", GetMyConfigs);
group.MapPost("/configs", CreateConfig);
group.MapPatch("/configs/{id:guid}", EditConfig);
group.MapPost("/configs/{id:guid}/rotate", RotateConfig);
group.MapDelete("/configs/{id:guid}", RevokeConfig);
group.MapGet("/configs/{id:guid}/link", GetConfigLink);
group.MapGet("/subscription", GetMySubscription);
group.MapGet("/inbounds/available", ListAvailableInbounds).Produces<IReadOnlyList<AvailableInboundDto>>();
group.MapGet("/configs", GetMyConfigs).Produces<GetMyConfigsResult>();
group.MapPost("/configs", CreateConfig).Produces<VpnConfigDto>();
group.MapPatch("/configs/{id:guid}", EditConfig).Produces<VpnConfigDto>();
group.MapPost("/configs/{id:guid}/rotate", RotateConfig).Produces<VpnConfigDto>();
group.MapDelete("/configs/{id:guid}", RevokeConfig).Produces(StatusCodes.Status204NoContent);
group.MapGet("/configs/{id:guid}/link", GetConfigLink).Produces<ConfigLinkResponseDto>();
group.MapGet("/subscription", GetMySubscription).Produces<MySubscriptionResponseDto>();
return app;
}
@@ -74,7 +75,7 @@ public static class ConfigEndpoints
return result.ToHttpResult();
var subscriptionUrl = $"{request.Scheme}://{request.Host}/sub/{result.Value.SubscriptionToken}";
return Results.Ok(new { connectionString = result.Value.ConnectionString, subscriptionUrl });
return Results.Ok(new ConfigLinkResponseDto(result.Value.ConnectionString, subscriptionUrl));
}
private static async Task<IResult> GetMySubscription(HttpRequest request, ISender sender, CancellationToken cancellationToken)
@@ -84,10 +85,14 @@ public static class ConfigEndpoints
return result.ToHttpResult();
var subscriptionUrl = $"{request.Scheme}://{request.Host}/sub/{result.Value.SubscriptionToken}";
return Results.Ok(new { subscriptionUrl });
return Results.Ok(new MySubscriptionResponseDto(subscriptionUrl));
}
}
public sealed record CreateConfigBody(Guid InboundId, string? Label, int? DeviceLimit);
public sealed record EditConfigBody(string? Label, int? DeviceLimit);
public sealed record ConfigLinkResponseDto(string ConnectionString, string SubscriptionUrl);
public sealed record MySubscriptionResponseDto(string SubscriptionUrl);