diff --git a/DocumentOperator.API/Controllers/ZugferdController.cs b/DocumentOperator.API/Controllers/ZugferdController.cs
index a5761a3..bcaabb6 100644
--- a/DocumentOperator.API/Controllers/ZugferdController.cs
+++ b/DocumentOperator.API/Controllers/ZugferdController.cs
@@ -89,8 +89,9 @@ public class ZugferdController(IMediator mediator) : ControllerBase
/// Supports multipart/form-data file upload.
///
/// The PDF file to extract ZUGFeRD from
+ /// if true, 'file' (returns XML file directly); otherwise output format: 'json' (default, returns metadata + XML content)
/// Cancellation token
- /// ZUGFeRD XML content and metadata
+ /// ZUGFeRD XML content and metadata (JSON) or XML file (application/xml)
/// ZUGFeRD XML extracted successfully
/// Invalid input (file missing, not a PDF, or corrupted)
/// PDF contains no ZUGFeRD XML
@@ -98,12 +99,14 @@ public class ZugferdController(IMediator mediator) : ControllerBase
[HttpPost("extract")]
[Consumes("multipart/form-data")]
[ProducesResponseType(typeof(ZugferdExtractionResult), StatusCodes.Status200OK)]
+ [ProducesResponseType(typeof(FileContentResult), StatusCodes.Status200OK)]
[ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status400BadRequest)]
[ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status404NotFound)]
[ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status500InternalServerError)]
public async Task ExtractZugferdFromFile(
IFormFile file,
- CancellationToken cancellationToken)
+ [FromQuery] bool asFile = true,
+ CancellationToken cancellationToken = default)
{
// Use IFormFile stream directly (no intermediate byte[] conversion)
using var pdfStream = file.OpenReadStream();
@@ -112,6 +115,13 @@ public class ZugferdController(IMediator mediator) : ControllerBase
var command = new ExtractZugferdCommand { PdfStream = pdfStream };
var result = await mediator.Send(command, cancellationToken);
+ // Return as file or JSON based on format parameter
+ if (asFile)
+ {
+ byte[] xmlBytes = System.Text.Encoding.UTF8.GetBytes(result.XmlContent);
+ return File(xmlBytes, "application/xml", result.FileName);
+ }
+
return Ok(result);
}
@@ -120,8 +130,9 @@ public class ZugferdController(IMediator mediator) : ControllerBase
/// Supports Base64-encoded PDF via JSON payload.
///
/// Request containing Base64-encoded PDF
+ /// Output format: 'json' (default, returns metadata + XML content) or 'file' (returns XML file directly)
/// Cancellation token
- /// ZUGFeRD XML content and metadata
+ /// ZUGFeRD XML content and metadata (JSON) or XML file (application/xml)
/// ZUGFeRD XML extracted successfully
/// Invalid input (Base64 format error, not a PDF, or corrupted)
/// PDF contains no ZUGFeRD XML
@@ -129,12 +140,14 @@ public class ZugferdController(IMediator mediator) : ControllerBase
[HttpPost("extract")]
[Consumes("application/json")]
[ProducesResponseType(typeof(ZugferdExtractionResult), StatusCodes.Status200OK)]
+ [ProducesResponseType(typeof(FileContentResult), StatusCodes.Status200OK)]
[ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status400BadRequest)]
[ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status404NotFound)]
[ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status500InternalServerError)]
public async Task ExtractZugferdFromBase64(
[FromBody] ExtractZugferdRequest request,
- CancellationToken cancellationToken)
+ [FromQuery] string format = "json",
+ CancellationToken cancellationToken = default)
{
// Convert Base64 to stream (wrap in try-catch to throw BadRequestException)
byte[] pdfBytes;
@@ -153,6 +166,13 @@ public class ZugferdController(IMediator mediator) : ControllerBase
var command = new ExtractZugferdCommand { PdfStream = pdfStream };
var result = await mediator.Send(command, cancellationToken);
+ // Return as file or JSON based on format parameter
+ if (format.Equals("file", StringComparison.OrdinalIgnoreCase))
+ {
+ byte[] xmlBytes = System.Text.Encoding.UTF8.GetBytes(result.XmlContent);
+ return File(xmlBytes, "application/xml", result.FileName);
+ }
+
return Ok(result);
}
}