Remove NotFoundException; services return null on lookup miss
A missing record isn't exceptional — services now return null (logged at Info) instead of throwing, and endpoints map null to 404. Agent and import toolsets route not-found through their existing OrNotFound result pattern rather than a caught exception.
This commit is contained in:
@@ -74,7 +74,8 @@ public class BeatService(
|
||||
];
|
||||
}
|
||||
|
||||
public async Task<Beat> CreateAsync(Guid chapterId, CreateBeatRequest request, CancellationToken ct = default)
|
||||
/// <summary>Null when no chapter has this id — a lookup miss is expected, not exceptional.</summary>
|
||||
public async Task<Beat?> CreateAsync(Guid chapterId, CreateBeatRequest request, CancellationToken ct = default)
|
||||
{
|
||||
Guard.Default(chapterId, nameof(chapterId));
|
||||
Guard.Null(request, nameof(request));
|
||||
@@ -85,8 +86,8 @@ public class BeatService(
|
||||
var chapter = await db.Chapters.FirstOrDefaultAsync(c => c.Id == chapterId, ct);
|
||||
if (chapter is null)
|
||||
{
|
||||
logger.LogWarning("Rejected beat creation: chapter {ChapterId} not found", chapterId);
|
||||
throw new NotFoundException(nameof(Chapter), chapterId);
|
||||
logger.LogInformation("Rejected beat creation: chapter {ChapterId} not found", chapterId);
|
||||
return null;
|
||||
}
|
||||
|
||||
await ValidateReferencesAsync(chapter, request.CharacterId, request.SceneId, ct);
|
||||
@@ -131,10 +132,10 @@ public class BeatService(
|
||||
var chapter = await db.Chapters.FirstOrDefaultAsync(c => c.Id == beat.ChapterId, ct);
|
||||
if (chapter is null)
|
||||
{
|
||||
// The beat's own chapter should always exist via the FK — this is an
|
||||
// invariant failing, not a caller mistake, so it stays exceptional.
|
||||
// The beat's own chapter should always exist via the FK — an invariant
|
||||
// failing, not a caller mistake, but still not found so still just null.
|
||||
logger.LogError("Beat {BeatId} references chapter {ChapterId} which does not exist", id, beat.ChapterId);
|
||||
throw new NotFoundException(nameof(Chapter), beat.ChapterId);
|
||||
return null;
|
||||
}
|
||||
|
||||
await ValidateReferencesAsync(chapter, request.CharacterId, request.SceneId, ct);
|
||||
@@ -178,7 +179,8 @@ public class BeatService(
|
||||
/// Renumbers a chapter's beats to match the order given. Sending the whole list beats
|
||||
/// patching sort orders one at a time, which is fiddly to get right from a drag handle.
|
||||
/// </summary>
|
||||
public async Task<IReadOnlyList<Beat>> ReorderAsync(
|
||||
/// <summary>Null when the chapter carries a beat id it does not own — a lookup miss is expected, not exceptional.</summary>
|
||||
public async Task<IReadOnlyList<Beat>?> ReorderAsync(
|
||||
Guid chapterId, ReorderBeatsRequest request, CancellationToken ct = default)
|
||||
{
|
||||
Guard.Default(chapterId, nameof(chapterId));
|
||||
@@ -192,8 +194,8 @@ public class BeatService(
|
||||
var missing = request.BeatIds.Where(id => beats.All(b => b.Id != id)).ToList();
|
||||
if (missing.Count > 0)
|
||||
{
|
||||
logger.LogWarning("Reorder for chapter {ChapterId} referenced missing beat {BeatId}", chapterId, missing[0]);
|
||||
throw new NotFoundException(nameof(Beat), missing[0]);
|
||||
logger.LogInformation("Reorder for chapter {ChapterId} referenced missing beat {BeatId}", chapterId, missing[0]);
|
||||
return null;
|
||||
}
|
||||
|
||||
// Listed beats take the order given; anything omitted keeps its relative position
|
||||
|
||||
Reference in New Issue
Block a user