refactor(application): centralize API envelope creation and command mapping

This commit is contained in:
2026-10-10 11:18:21 +02:00
parent b3b52a8c48
commit 1fbcc2d197
5 changed files with 61 additions and 46 deletions

View File

@@ -0,0 +1,49 @@
using DigitalData.TaskFlow.Domain.Common;
using DigitalData.TaskFlow.Domain.Enums;
namespace DigitalData.TaskFlow.Application.Common.Factories;
/// <summary>
/// Creates standard API envelope instances with centralized meta code/message handling.
/// </summary>
public static class ApiEnvelopeFactory
{
/// <summary>
/// Creates a successful or business-result response envelope.
/// </summary>
/// <typeparam name="T">Payload type.</typeparam>
/// <param name="data">Payload data.</param>
/// <param name="code">Business result code.</param>
/// <param name="message">Optional custom message. If not supplied, a default message is resolved from <paramref name="code"/>.</param>
/// <returns>Response envelope containing meta and payload.</returns>
public static ApiEnvelope<T> Create<T>(T data, MetaCode code = MetaCode.Ok, string? message = null)
{
return new ApiEnvelope<T>
{
Meta =
[
new MetaEntry
{
Code = (int)code,
Message = message ?? ResolveDefaultMessage(code)
}
],
Data = data
};
}
private static string ResolveDefaultMessage(MetaCode code)
{
return code switch
{
MetaCode.Ok => "OK",
MetaCode.NoOpenWorkflows => "Keine offenen Workflows",
MetaCode.NoAccess => "Kein Zugriff",
MetaCode.InvalidRequest => "Ungultiger Request",
MetaCode.InternalError => "Interner Fehler",
MetaCode.NotFound => "Vorgang nicht gefunden",
MetaCode.AlreadyClosed => "Vorgang bereits abgeschlossen",
_ => "Interner Fehler"
};
}
}

View File

@@ -1,4 +1,6 @@
using AutoMapper;
using DigitalData.TaskFlow.Application.Features.Workflows.Commands.CloseWorkflow;
using DigitalData.TaskFlow.Domain.Closing;
namespace DigitalData.TaskFlow.Application.Common.Mappings;
@@ -12,5 +14,6 @@ public sealed class ApplicationMappingProfile : Profile
/// </summary>
public ApplicationMappingProfile()
{
CreateMap<CloseWorkflowCommand, CloseWorkflowDecision>();
}
}

View File

@@ -1,7 +1,7 @@
using DigitalData.TaskFlow.Application.Common.Factories;
using DigitalData.TaskFlow.Application.Common.Interfaces;
using DigitalData.TaskFlow.Domain.Common;
using DigitalData.TaskFlow.Domain.Documents;
using DigitalData.TaskFlow.Domain.Enums;
using FluentValidation;
using MediatR;
@@ -44,17 +44,6 @@ public sealed class GetDocumentQueryHandler(IDocumentRepository documentReposito
{
var document = await documentRepository.GetAsync(request.Id, cancellationToken);
return new ApiEnvelope<DocumentBinaryResult>
{
Meta =
[
new MetaEntry
{
Code = (int)MetaCode.Ok,
Message = "OK"
}
],
Data = document
};
return ApiEnvelopeFactory.Create(document);
}
}

View File

@@ -1,7 +1,8 @@
using DigitalData.TaskFlow.Application.Common.Interfaces;
using DigitalData.TaskFlow.Application.Common.Factories;
using AutoMapper;
using DigitalData.TaskFlow.Domain.Closing;
using DigitalData.TaskFlow.Domain.Common;
using DigitalData.TaskFlow.Domain.Enums;
using FluentValidation;
using MediatR;
@@ -56,7 +57,7 @@ public sealed class CloseWorkflowCommandValidator : AbstractValidator<CloseWorkf
/// <summary>
/// Handles <see cref="CloseWorkflowCommand"/> requests.
/// </summary>
public sealed class CloseWorkflowCommandHandler(IWorkflowRepository workflowRepository)
public sealed class CloseWorkflowCommandHandler(IWorkflowRepository workflowRepository, IMapper mapper)
: IRequestHandler<CloseWorkflowCommand, ApiEnvelope<CloseWorkflowResult>>
{
/// <summary>
@@ -67,12 +68,7 @@ public sealed class CloseWorkflowCommandHandler(IWorkflowRepository workflowRepo
/// <returns>Closing result envelope.</returns>
public async Task<ApiEnvelope<CloseWorkflowResult>> Handle(CloseWorkflowCommand request, CancellationToken cancellationToken)
{
var decision = new CloseWorkflowDecision
{
ClosingMethodId = request.ClosingMethodId,
Comment = request.Comment,
RejectionReasonId = request.RejectionReasonId
};
var decision = mapper.Map<CloseWorkflowDecision>(request);
var result = await workflowRepository.CloseAsync(
request.WisagId,
@@ -81,17 +77,6 @@ public sealed class CloseWorkflowCommandHandler(IWorkflowRepository workflowRepo
decision,
cancellationToken);
return new ApiEnvelope<CloseWorkflowResult>
{
Meta =
[
new MetaEntry
{
Code = (int)MetaCode.Ok,
Message = "OK"
}
],
Data = result
};
return ApiEnvelopeFactory.Create(result);
}
}

View File

@@ -1,6 +1,6 @@
using DigitalData.TaskFlow.Application.Common.Factories;
using DigitalData.TaskFlow.Application.Common.Interfaces;
using DigitalData.TaskFlow.Domain.Common;
using DigitalData.TaskFlow.Domain.Enums;
using DigitalData.TaskFlow.Domain.Workflows;
using FluentValidation;
using MediatR;
@@ -44,17 +44,6 @@ public sealed class GetWorkflowsQueryHandler(IWorkflowRepository workflowReposit
{
var data = await workflowRepository.GetAsync(request.WisagId, cancellationToken);
return new ApiEnvelope<WorkflowSourcesResponse>
{
Meta =
[
new MetaEntry
{
Code = (int)MetaCode.Ok,
Message = "OK"
}
],
Data = data
};
return ApiEnvelopeFactory.Create(data);
}
}