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>
/// 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>
/// <typeparam name="T">The payload type containing identifiers.</typeparam>
/// <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>
public async Task DeleteAsync<T>(T payload, CancellationToken cancel = default)
{
using (var request = new HttpRequestMessage(HttpMethod.Delete, ResourcePath)
{
Content = ReCClientHelpers.ToJsonContent(payload)
})
using (var resp = await Http.SendAsync(request, cancel))
var query = ReCClientHelpers.BuildQueryFromObject(payload);
using (var resp = await Http.DeleteAsync($"{ResourcePath}{query}", cancel))
{
await ReCClientHelpers.HandleResponseAsync(resp, Logger, Options.LogSuccessfulRequests, cancel).ConfigureAwait(false);
}

View File

@@ -6,7 +6,9 @@ using Microsoft.Extensions.Logging;
namespace ReC.Client.Api
{
/// <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>
public class CommonApi : BaseCrudApi
{
@@ -23,5 +25,23 @@ namespace ReC.Client.Api
#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>
/// Retrieves a profile by identifier.
/// Retrieves profiles, optionally filtered by identifier.
/// </summary>
/// <param name="id">The profile identifier.</param>
/// <param name="includeActions">Whether to include related actions.</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. Defaults to <see langword="true"/> to match the API default.</param>
/// <param name="cancel">A token to cancel the operation.</param>
/// <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));
return Http.GetAsync($"{ResourcePath}{query}", cancel);

View File

@@ -25,13 +25,17 @@ namespace ReC.Client.Api
}
/// <summary>
/// Invokes a ReC action for the specified profile.
/// Invokes a batch of RecActions for the specified profile.
/// </summary>
/// <param name="profileId">The profile identifier.</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>
/// <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;
using (content)
@@ -42,13 +46,13 @@ namespace ReC.Client.Api
}
/// <summary>
/// Invokes a ReC action for the specified profile.
/// Invokes a batch of RecActions for the specified profile.
/// </summary>
/// <param name="profileId">The profile identifier.</param>
/// <param name="batchId">Batch identifier.</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>
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);
}

View File

@@ -30,11 +30,26 @@ namespace ReC.Client.Api
/// <param name="id">Optional result identifier.</param>
/// <param name="actionId">Optional action 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>
/// <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);
}
}