Delete File Handler
This page provides complete examples for implementing the Delete File backend handler. The deletefile endpoint removes files from your storage system when users delete attachments from forms.
What is Delete File?
deletefile is the backend endpoint that:
- Receives a file identifier to delete
- Removes the file from your storage system
- Returns confirmation of deletion success
- Handles cleanup of associated metadata
Complete Delete File Implementation
Choose your backend language:
- C# / .NET
- PHP
Controllers/FormsPublicController.cs
public class FileRequestDto
{
public string FileId { get; set; }
}
[HttpPost("deletefile")]
[AllowAnonymous]
public async Task<IActionResult> DeleteFile([FromBody] FileRequestDto request)
{
var fileStorageService = GetFileStorageService();
if (fileStorageService == null)
throw new InvalidOperationException("File storage provider not configured.");
bool result = false;
var response = new HandlerResponse();
if (!string.IsNullOrEmpty(request.FileId))
{
// Parse file identifier (format: "bucket-name:path/to/file.pdf")
string[] parts = request.FileId.Split(':');
string bucketName = parts[0];
string filePath = parts[1];
// Delete file from storage
if (await fileStorageService.DeleteFileFromBucket(filePath, bucketName))
{
// Update response to reflect successful deletion
response.Set(HandlerResponse.LinkedFiles, new List<string>());
result = true;
_logger.LogInformation(
"File deleted successfully: {FileId}",
request.FileId
);
}
else
{
_logger.LogWarning(
"Failed to delete file: {FileId}",
request.FileId
);
}
}
response.Set(HandlerResponse.LinkedFileDeleteSuccess, result);
return Ok(await response.Get());
}
controllers/FormsPublicController.php
<?php
class FormsPublicController {
public function deleteFile(Request $request) {
$fileId = $request->input('fileId');
if (empty($fileId)) {
return response()->json([
'linkedFileDeleteSuccess' => false,
'error' => 'File ID is required'
], 400);
}
$fileStorageService = $this->getFileStorageService();
if (!$fileStorageService) {
throw new Exception('File storage provider not configured.');
}
$result = false;
// Parse file identifier (format: "bucket-name:path/to/file.pdf")
$parts = explode(':', $fileId, 2);
if (count($parts) === 2) {
$bucketName = $parts[0];
$filePath = $parts[1];
// Delete file from storage
if ($fileStorageService->deleteFileFromBucket($filePath, $bucketName)) {
$result = true;
Log::info("File deleted successfully: {$fileId}");
} else {
Log::warning("Failed to delete file: {$fileId}");
}
}
return response()->json([
'linkedFiles' => [],
'linkedFileDeleteSuccess' => $result
]);
}
private function getFileStorageService() {
return app('file.storage');
}
}
?>
Request Structure
{
"fileId": "bucket-name:tenant/forms/2026/01/27/document.pdf"
}
Key Fields:
- fileId - The file identifier returned from the upload endpoint
Response Structure
{
"linkedFiles": [],
"linkedFileDeleteSuccess": true
}
Response Fields:
- linkedFileDeleteSuccess - Boolean indicating if deletion was successful
- linkedFiles - Empty array after successful deletion
Storage Implementation Examples
S3 Storage
C# - Delete File from S3
public async Task<bool> DeleteFromS3(string filePath, string bucketName)
{
try
{
var s3Client = new AmazonS3Client(/* credentials */);
var deleteRequest = new DeleteObjectRequest
{
BucketName = bucketName,
Key = filePath
};
var response = await s3Client.DeleteObjectAsync(deleteRequest);
return response.HttpStatusCode == System.Net.HttpStatusCode.NoContent;
}
catch (AmazonS3Exception ex)
{
_logger.LogError(ex, "S3 delete failed for {FilePath}", filePath);
return false;
}
}
Local File Storage
C# - Delete File from Local Storage
public Task<bool> DeleteFromLocal(string filePath, string bucketName)
{
try
{
var fullPath = Path.Combine(_uploadDirectory, bucketName, filePath);
if (File.Exists(fullPath))
{
File.Delete(fullPath);
return Task.FromResult(true);
}
return Task.FromResult(false);
}
catch (Exception ex)
{
_logger.LogError(ex, "Local file delete failed for {FilePath}", filePath);
return Task.FromResult(false);
}
}
Azure Blob Storage
C# - Delete File from Azure Blob Storage
public async Task<bool> DeleteFromAzure(string filePath, string containerName)
{
try
{
var blobClient = new BlobContainerClient(
_connectionString,
containerName
);
var blob = blobClient.GetBlobClient(filePath);
var response = await blob.DeleteIfExistsAsync();
return response.Value;
}
catch (Exception ex)
{
_logger.LogError(ex, "Azure blob delete failed for {FilePath}", filePath);
return false;
}
}
Security Considerations
Authorization Check
Always verify the user has permission to delete the file:
C# - Check Delete Permission
private async Task<bool> CanUserDeleteFile(string userId, string fileId)
{
// Check if file belongs to user's forms/records
var fileRecord = await _context.Files
.Where(f => f.FileId == fileId)
.FirstOrDefaultAsync();
if (fileRecord == null)
return false;
// Verify ownership or permission
return fileRecord.UserId == userId ||
await _authService.HasPermission(userId, "files.delete");
}
Soft Delete Option
Consider implementing soft delete instead of hard delete:
C# - Soft Delete Implementation
public async Task<bool> SoftDeleteFile(string fileId)
{
var fileRecord = await _context.Files
.Where(f => f.FileId == fileId)
.FirstOrDefaultAsync();
if (fileRecord == null)
return false;
fileRecord.DeletedAt = DateTime.UtcNow;
fileRecord.DeletedBy = GetCurrentUserId();
await _context.SaveChangesAsync();
return true;
}
Cleanup Associated Metadata
Remember to clean up database records:
C# - Cleanup File Metadata
private async Task CleanupFileMetadata(string fileId)
{
// Remove file reference from database
var fileRecord = await _context.Files
.Where(f => f.FileId == fileId)
.FirstOrDefaultAsync();
if (fileRecord != null)
{
_context.Files.Remove(fileRecord);
await _context.SaveChangesAsync();
}
}
Error Handling
Handle common deletion errors:
C# - Complete Error Handling Example
public async Task<IActionResult> DeleteFile([FromBody] FileRequestDto request)
{
try
{
if (string.IsNullOrEmpty(request.FileId))
{
return BadRequest(new {
linkedFileDeleteSuccess = false,
error = "File ID is required"
});
}
// Check authorization
if (!await CanUserDeleteFile(GetCurrentUserId(), request.FileId))
{
return Unauthorized(new {
linkedFileDeleteSuccess = false,
error = "You don't have permission to delete this file"
});
}
// Perform deletion
bool deleted = await DeleteFileFromStorage(request.FileId);
if (deleted)
{
await CleanupFileMetadata(request.FileId);
}
return Ok(new {
linkedFiles = new List<string>(),
linkedFileDeleteSuccess = deleted
});
}
catch (Exception ex)
{
_logger.LogError(ex, "Error deleting file");
return StatusCode(500, new {
linkedFileDeleteSuccess = false,
error = "Failed to delete file"
});
}
}
Next Steps
- Upload Files Handler - Upload new files
- Download File Handler - Download files
- Get Linked File Handler - Retrieve file data