diff --git a/src/Tgstation.Server.Host/Authority/Core/AuthorityBase.cs b/src/Tgstation.Server.Host/Authority/Core/AuthorityBase.cs
index 898c701eb8..f0e39151a3 100644
--- a/src/Tgstation.Server.Host/Authority/Core/AuthorityBase.cs
+++ b/src/Tgstation.Server.Host/Authority/Core/AuthorityBase.cs
@@ -53,6 +53,16 @@ namespace Tgstation.Server.Host.Authority.Core
new ErrorMessageResponse(),
HttpFailureResponse.Unauthorized);
+ ///
+ /// Generates a type .
+ ///
+ /// The of the .
+ /// A new, errored .
+ protected static AuthorityResponse Gone()
+ => new(
+ new ErrorMessageResponse(),
+ HttpFailureResponse.Gone);
+
///
/// Generates a type .
///
@@ -73,6 +83,17 @@ namespace Tgstation.Server.Host.Authority.Core
new ErrorMessageResponse(),
HttpFailureResponse.NotFound);
+ ///
+ /// Generates a type .
+ ///
+ /// The of the .
+ /// The .
+ /// A new, errored .
+ protected static AuthorityResponse Conflict(ErrorCode errorCode)
+ => new(
+ new ErrorMessageResponse(errorCode),
+ HttpFailureResponse.Conflict);
+
///
/// Initializes a new instance of the class.
///
diff --git a/src/Tgstation.Server.Host/Authority/Core/AuthorityResponse{TResult}.cs b/src/Tgstation.Server.Host/Authority/Core/AuthorityResponse{TResult}.cs
index 44376f488c..9c2cfd295c 100644
--- a/src/Tgstation.Server.Host/Authority/Core/AuthorityResponse{TResult}.cs
+++ b/src/Tgstation.Server.Host/Authority/Core/AuthorityResponse{TResult}.cs
@@ -13,10 +13,16 @@ namespace Tgstation.Server.Host.Authority.Core
public sealed class AuthorityResponse : AuthorityResponse
{
///
- [MemberNotNullWhen(true, nameof(Result))]
- [MemberNotNullWhen(true, nameof(SuccessResponse))]
+ [MemberNotNullWhen(true, nameof(IsNoContent))]
public override bool Success => base.Success;
+ ///
+ /// Checks if a the is a no content result. Only set on .
+ ///
+ [MemberNotNullWhen(false, nameof(Result))]
+ [MemberNotNullWhen(false, nameof(Result))]
+ public bool? IsNoContent => Success ? Result == null : null;
+
///
/// The success .
///
@@ -47,5 +53,13 @@ namespace Tgstation.Server.Host.Authority.Core
Result = result ?? throw new ArgumentNullException(nameof(result));
SuccessResponse = httpResponse;
}
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// This generates an HTTP 204 response.
+ public AuthorityResponse()
+ {
+ }
}
}
diff --git a/src/Tgstation.Server.Host/Authority/Core/GraphQLAuthorityInvoker{TAuthority}.cs b/src/Tgstation.Server.Host/Authority/Core/GraphQLAuthorityInvoker{TAuthority}.cs
index 794bd467ef..a25a04e278 100644
--- a/src/Tgstation.Server.Host/Authority/Core/GraphQLAuthorityInvoker{TAuthority}.cs
+++ b/src/Tgstation.Server.Host/Authority/Core/GraphQLAuthorityInvoker{TAuthority}.cs
@@ -13,11 +13,12 @@ namespace Tgstation.Server.Host.Authority.Core
/// Throws a for errored s.
///
/// The potentially errored .
- static void ThrowGraphQLErrorIfNecessary(AuthorityResponse authorityResponse)
+ /// If an error should be raised for and failures.
+ static void ThrowGraphQLErrorIfNecessary(AuthorityResponse authorityResponse, bool errorOnMissing)
{
if (authorityResponse.Success
- || authorityResponse.FailureResponse.Value == HttpFailureResponse.NotFound
- || authorityResponse.FailureResponse.Value == HttpFailureResponse.Gone)
+ || ((authorityResponse.FailureResponse.Value == HttpFailureResponse.NotFound
+ || authorityResponse.FailureResponse.Value == HttpFailureResponse.Gone) && !errorOnMissing))
return;
var fallbackString = authorityResponse.FailureResponse.ToString()!;
@@ -39,33 +40,41 @@ namespace Tgstation.Server.Host.Authority.Core
ArgumentNullException.ThrowIfNull(authorityInvoker);
var authorityResponse = await authorityInvoker(Authority);
- ThrowGraphQLErrorIfNecessary(authorityResponse);
+ ThrowGraphQLErrorIfNecessary(authorityResponse, true);
}
///
- async ValueTask IGraphQLAuthorityInvoker.Invoke(Func>> authorityInvoker)
+ async ValueTask IGraphQLAuthorityInvoker.InvokeAllowMissing(Func>> authorityInvoker)
where TApiModel : default
{
ArgumentNullException.ThrowIfNull(authorityInvoker);
var authorityResponse = await authorityInvoker(Authority);
- ThrowGraphQLErrorIfNecessary(authorityResponse);
+ ThrowGraphQLErrorIfNecessary(authorityResponse, false);
return authorityResponse.Result;
}
///
- async ValueTask IGraphQLAuthorityInvoker.InvokeTransformable(Func>> authorityInvoker)
+ async ValueTask IGraphQLAuthorityInvoker.InvokeTransformableAllowMissing(Func>> authorityInvoker)
where TApiModel : default
{
ArgumentNullException.ThrowIfNull(authorityInvoker);
var authorityResponse = await authorityInvoker(Authority);
- ThrowGraphQLErrorIfNecessary(authorityResponse);
+ ThrowGraphQLErrorIfNecessary(authorityResponse, false);
var result = authorityResponse.Result;
if (result == null)
return default;
return result.ToApi();
}
+
+ ///
+ ValueTask IGraphQLAuthorityInvoker.Invoke(Func>> authorityInvoker)
+ => ((IGraphQLAuthorityInvoker)this).InvokeAllowMissing(authorityInvoker)!;
+
+ ///
+ ValueTask IGraphQLAuthorityInvoker.InvokeTransformable(Func>> authorityInvoker)
+ => ((IGraphQLAuthorityInvoker)this).InvokeTransformableAllowMissing(authorityInvoker)!;
}
}
diff --git a/src/Tgstation.Server.Host/Authority/Core/RestAuthorityInvoker{TAuthority}.cs b/src/Tgstation.Server.Host/Authority/Core/RestAuthorityInvoker{TAuthority}.cs
index 83911ecb56..680dc98a4e 100644
--- a/src/Tgstation.Server.Host/Authority/Core/RestAuthorityInvoker{TAuthority}.cs
+++ b/src/Tgstation.Server.Host/Authority/Core/RestAuthorityInvoker{TAuthority}.cs
@@ -14,18 +14,22 @@ namespace Tgstation.Server.Host.Authority.Core
where TAuthority : IAuthority
{
///
- /// Create an for a given successfuly API .
+ /// Create an for a given successfuly.
///
/// The to use.
- /// The resulting from the .
+ /// A transforming the from the into the .
/// The .
/// An for the .
/// The result returned in the .
/// The REST API result model built from .
- static IActionResult CreateSuccessfulActionResult(ApiController controller, TApiModel result, AuthorityResponse authorityResponse)
+ static IActionResult CreateSuccessfulActionResult(ApiController controller, Func resultTransformer, AuthorityResponse authorityResponse)
where TApiModel : notnull
{
+ if (authorityResponse.IsNoContent!.Value)
+ return controller.NoContent();
+
var successResponse = authorityResponse.SuccessResponse;
+ var result = resultTransformer(authorityResponse.Result!);
return successResponse switch
{
HttpSuccessResponse.Ok => controller.Json(result),
@@ -95,8 +99,7 @@ namespace Tgstation.Server.Host.Authority.Core
if (erroredResult != null)
return erroredResult;
- var result = authorityResponse.Result!;
- return CreateSuccessfulActionResult(controller, result, authorityResponse);
+ return CreateSuccessfulActionResult(controller, result => result, authorityResponse);
}
///
@@ -110,9 +113,7 @@ namespace Tgstation.Server.Host.Authority.Core
if (erroredResult != null)
return erroredResult;
- var result = authorityResponse.Result!;
- var apiModel = result.ToApi();
- return CreateSuccessfulActionResult(controller, apiModel, authorityResponse);
+ return CreateSuccessfulActionResult(controller, result => result.ToApi(), authorityResponse);
}
}
}
diff --git a/src/Tgstation.Server.Host/Authority/IGraphQLAuthorityInvoker{TAuthority}.cs b/src/Tgstation.Server.Host/Authority/IGraphQLAuthorityInvoker{TAuthority}.cs
index eb179caf9b..edface219a 100644
--- a/src/Tgstation.Server.Host/Authority/IGraphQLAuthorityInvoker{TAuthority}.cs
+++ b/src/Tgstation.Server.Host/Authority/IGraphQLAuthorityInvoker{TAuthority}.cs
@@ -27,7 +27,7 @@ namespace Tgstation.Server.Host.Authority
/// The resulting of the return value.
/// The returning a resulting in the .
/// A resulting in the generated for the resulting .
- ValueTask Invoke(Func>> authorityInvoker)
+ ValueTask InvokeAllowMissing(Func>> authorityInvoker)
where TResult : TApiModel
where TApiModel : notnull;
@@ -39,7 +39,31 @@ namespace Tgstation.Server.Host.Authority
/// The for converting s to s.
/// The returning a resulting in the .
/// A resulting in the generated for the resulting .
- ValueTask InvokeTransformable(Func>> authorityInvoker)
+ ValueTask InvokeTransformableAllowMissing(Func>> authorityInvoker)
+ where TResult : notnull, IApiTransformable
+ where TApiModel : notnull
+ where TTransformer : ITransformer, new();
+
+ ///
+ /// Invoke a method and get the non-nullable result.
+ ///
+ /// The .
+ /// The resulting of the return value.
+ /// The returning a resulting in the .
+ /// A resulting in the generated for the resulting .
+ ValueTask Invoke(Func>> authorityInvoker)
+ where TResult : TApiModel
+ where TApiModel : notnull;
+
+ ///
+ /// Invoke a method and get the non-nullable result.
+ ///
+ /// The .
+ /// The resulting of the return value.
+ /// The for converting s to s.
+ /// The returning a resulting in the .
+ /// A resulting in the generated for the resulting .
+ ValueTask InvokeTransformable(Func>> authorityInvoker)
where TResult : notnull, IApiTransformable
where TApiModel : notnull
where TTransformer : ITransformer, new();