Refactor API methods for improved query handling

Updated `DeleteAsync` in `BaseCrudApi.cs` to serialize payloads into query strings to align with API expectations.

Added `UpdateAsync` to `CommonApi.cs` for payload-based updates, overriding inherited CRUD helpers to match the API's behavior.

Enhanced `GetAsync` in `ProfileApi.cs` to support optional profile filtering and default `includeActions` to `true`.

Refactored `InvokeAsync` in `RecActionApi.cs` to use `long` for `profileId`, support nullable `references`, and handle batches of RecActions.

Extended `GetAsync` in `ResultApi.cs` with new optional filters (`batchId`, `includeAction`, `includeProfile`, `lastBatch`) and updated query-building logic.
This commit is contained in:
2026-05-20 09:22:41 +02:00
parent 5239c2f071
commit d37eda0d6d
5 changed files with 54 additions and 17 deletions

View File

@@ -88,7 +88,8 @@ namespace ReC.Client.Api
} }
/// <summary> /// <summary>
/// Deletes resources with identifiers supplied in the payload. /// Deletes resources with identifiers supplied in the payload. The payload is serialized into
/// the query string because the API binds delete payloads from the URL query.
/// </summary> /// </summary>
/// <typeparam name="T">The payload type containing identifiers.</typeparam> /// <typeparam name="T">The payload type containing identifiers.</typeparam>
/// <param name="payload">The payload to send.</param> /// <param name="payload">The payload to send.</param>
@@ -96,11 +97,8 @@ namespace ReC.Client.Api
/// <exception cref="ReCApiException">Thrown when the API responds with a non-success status code.</exception> /// <exception cref="ReCApiException">Thrown when the API responds with a non-success status code.</exception>
public async Task DeleteAsync<T>(T payload, CancellationToken cancel = default) public async Task DeleteAsync<T>(T payload, CancellationToken cancel = default)
{ {
using (var request = new HttpRequestMessage(HttpMethod.Delete, ResourcePath) var query = ReCClientHelpers.BuildQueryFromObject(payload);
{ using (var resp = await Http.DeleteAsync($"{ResourcePath}{query}", cancel))
Content = ReCClientHelpers.ToJsonContent(payload)
})
using (var resp = await Http.SendAsync(request, cancel))
{ {
await ReCClientHelpers.HandleResponseAsync(resp, Logger, Options.LogSuccessfulRequests, cancel).ConfigureAwait(false); await ReCClientHelpers.HandleResponseAsync(resp, Logger, Options.LogSuccessfulRequests, cancel).ConfigureAwait(false);
} }

View File

@@ -6,7 +6,9 @@ using Microsoft.Extensions.Logging;
namespace ReC.Client.Api namespace ReC.Client.Api
{ {
/// <summary> /// <summary>
/// Provides access to common object endpoints. /// Provides access to common object endpoints. The Common API binds update and delete
/// payloads from the body / query string (no id route segment), so the inherited CRUD
/// helpers from <see cref="BaseCrudApi"/> are hidden with overloads that match the API.
/// </summary> /// </summary>
public class CommonApi : BaseCrudApi public class CommonApi : BaseCrudApi
{ {
@@ -23,5 +25,23 @@ namespace ReC.Client.Api
#endif #endif
{ {
} }
/// <summary>
/// Updates an object via the Common update procedure. The identifier is expected to be
/// part of <paramref name="payload"/> rather than the URL.
/// </summary>
/// <typeparam name="T">The payload type.</typeparam>
/// <param name="payload">The payload to send.</param>
/// <param name="cancel">A token to cancel the operation.</param>
/// <exception cref="ReCApiException">Thrown when the API responds with a non-success status code.</exception>
public async Task UpdateAsync<T>(T payload, CancellationToken cancel = default)
{
using (var content = ReCClientHelpers.ToJsonContent(payload))
using (var resp = await Http.PutAsync(ResourcePath, content, cancel))
{
await ReCClientHelpers.HandleResponseAsync(resp, Logger, Options.LogSuccessfulRequests, cancel).ConfigureAwait(false);
}
}
} }
} }

View File

@@ -25,13 +25,13 @@ namespace ReC.Client.Api
} }
/// <summary> /// <summary>
/// Retrieves a profile by identifier. /// Retrieves profiles, optionally filtered by identifier.
/// </summary> /// </summary>
/// <param name="id">The profile identifier.</param> /// <param name="id">Optional profile identifier filter. When <see langword="null"/>, all profiles are returned.</param>
/// <param name="includeActions">Whether to include related actions.</param> /// <param name="includeActions">Whether to include related actions. Defaults to <see langword="true"/> to match the API default.</param>
/// <param name="cancel">A token to cancel the operation.</param> /// <param name="cancel">A token to cancel the operation.</param>
/// <returns>The HTTP response message.</returns> /// <returns>The HTTP response message.</returns>
public Task<HttpResponseMessage> GetAsync(long id, bool includeActions = false, CancellationToken cancel = default) public Task<HttpResponseMessage> GetAsync(long? id = null, bool includeActions = true, CancellationToken cancel = default)
{ {
var query = ReCClientHelpers.BuildQuery(("Id", id), ("IncludeActions", includeActions)); var query = ReCClientHelpers.BuildQuery(("Id", id), ("IncludeActions", includeActions));
return Http.GetAsync($"{ResourcePath}{query}", cancel); return Http.GetAsync($"{ResourcePath}{query}", cancel);

View File

@@ -25,13 +25,17 @@ namespace ReC.Client.Api
} }
/// <summary> /// <summary>
/// Invokes a ReC action for the specified profile. /// Invokes a batch of RecActions for the specified profile.
/// </summary> /// </summary>
/// <param name="profileId">The profile identifier.</param> /// <param name="profileId">The profile identifier.</param>
/// <param name="references">Optional reference values to pass through to all result records.</param> /// <param name="references">Optional reference values to pass through to all result records.</param>
/// <param name="cancellationToken">A token to cancel the operation.</param> /// <param name="cancellationToken">A token to cancel the operation.</param>
/// <exception cref="ReCApiException">Thrown when the API responds with a non-success status code.</exception> /// <exception cref="ReCApiException">Thrown when the API responds with a non-success status code.</exception>
public async Task InvokeAsync(int profileId, InvokeReferences references, CancellationToken cancellationToken = default) #if NETFRAMEWORK
public async Task InvokeAsync(long profileId, InvokeReferences references = null, CancellationToken cancellationToken = default)
#else
public async Task InvokeAsync(long profileId, InvokeReferences? references = null, CancellationToken cancellationToken = default)
#endif
{ {
var content = references != null ? ReCClientHelpers.ToJsonContent(references) : null; var content = references != null ? ReCClientHelpers.ToJsonContent(references) : null;
using (content) using (content)
@@ -42,13 +46,13 @@ namespace ReC.Client.Api
} }
/// <summary> /// <summary>
/// Invokes a ReC action for the specified profile. /// Invokes a batch of RecActions for the specified profile.
/// </summary> /// </summary>
/// <param name="profileId">The profile identifier.</param> /// <param name="profileId">The profile identifier.</param>
/// <param name="batchId">Batch identifier.</param> /// <param name="batchId">Batch identifier.</param>
/// <param name="cancellationToken">A token to cancel the operation.</param> /// <param name="cancellationToken">A token to cancel the operation.</param>
/// <exception cref="ReCApiException">Thrown when the API responds with a non-success status code.</exception> /// <exception cref="ReCApiException">Thrown when the API responds with a non-success status code.</exception>
public Task InvokeAsync(int profileId, string batchId, CancellationToken cancellationToken = default) public Task InvokeAsync(long profileId, string batchId, CancellationToken cancellationToken = default)
{ {
return InvokeAsync(profileId, new InvokeReferences() { BatchId = batchId }, cancellationToken); return InvokeAsync(profileId, new InvokeReferences() { BatchId = batchId }, cancellationToken);
} }

View File

@@ -30,11 +30,26 @@ namespace ReC.Client.Api
/// <param name="id">Optional result identifier.</param> /// <param name="id">Optional result identifier.</param>
/// <param name="actionId">Optional action identifier.</param> /// <param name="actionId">Optional action identifier.</param>
/// <param name="profileId">Optional profile identifier.</param> /// <param name="profileId">Optional profile identifier.</param>
/// <param name="batchId">Optional batch identifier.</param>
/// <param name="includeAction">Whether to include the related action. Defaults to <see langword="true"/> to match the API default.</param>
/// <param name="includeProfile">Whether to include the related profile. Defaults to <see langword="false"/> to match the API default.</param>
/// <param name="lastBatch">When <see langword="true"/>, restricts results to those belonging to the most recent batch matching the other filters.</param>
/// <param name="cancel">A token to cancel the operation.</param> /// <param name="cancel">A token to cancel the operation.</param>
/// <returns>The HTTP response message.</returns> /// <returns>The HTTP response message.</returns>
public Task<HttpResponseMessage> GetAsync(long? id = null, long? actionId = null, long? profileId = null, CancellationToken cancel = default) #if NETFRAMEWORK
public Task<HttpResponseMessage> GetAsync(long? id = null, long? actionId = null, long? profileId = null, string batchId = null, bool includeAction = true, bool includeProfile = false, bool lastBatch = false, CancellationToken cancel = default)
#else
public Task<HttpResponseMessage> GetAsync(long? id = null, long? actionId = null, long? profileId = null, string? batchId = null, bool includeAction = true, bool includeProfile = false, bool lastBatch = false, CancellationToken cancel = default)
#endif
{ {
var query = ReCClientHelpers.BuildQuery(("Id", id), ("ActionId", actionId), ("ProfileId", profileId)); var query = ReCClientHelpers.BuildQuery(
("Id", id),
("ActionId", actionId),
("ProfileId", profileId),
("BatchId", batchId),
("IncludeAction", includeAction),
("IncludeProfile", includeProfile),
("LastBatch", lastBatch));
return Http.GetAsync($"{ResourcePath}{query}", cancel); return Http.GetAsync($"{ResourcePath}{query}", cancel);
} }
} }