use RESTful style for GET & POST to child entity endpoints

This commit is contained in:
2025-05-21 07:40:09 +02:00
parent 108d7a2d5e
commit be33f30425
3 changed files with 31 additions and 19 deletions

View File

@@ -1,17 +1,17 @@
using Pilz.Data; using Pilz.Data;
using Pilz.Net.Api.Messages; using Pilz.Net.Api.Messages;
using Pilz.Net.Extensions;
namespace Pilz.Net.Api.Client; namespace Pilz.Net.Api.Client;
public abstract class BaseChildItemClient<T>(IApiClient client) : BaseClient<T>(client), IBaseChildItemClient<T> where T : IDataObject public abstract class BaseChildItemClient<T>(IApiClient client) : BaseClient<T>(client), IBaseChildItemClient<T> where T : IDataObject
{ {
public override string ApiEndpoint => ApiEndpointParent + ApiEndpointChild;
public abstract string ApiEndpointParent { get; }
public abstract string ApiEndpointChild { get; }
public virtual async Task<IEnumerable<T>> GetAll(int parentId) public virtual async Task<IEnumerable<T>> GetAll(int parentId)
{ {
return (await client.SendRequest<GeneralItemMessages<T>.Items>(ApiEndpoint, HttpMethod.Get, new ApiParameterCollection return (await client.SendRequest<GeneralItemMessages<T>.Items>($"{ApiEndpointParent}/{parentId}{ApiEndpointChild}", HttpMethod.Get)).EnsureOk().Items;
{
["parent"] = parentId,
})).EnsureOk().Items;
} }
public override async Task<T> Save(T item) public override async Task<T> Save(T item)
@@ -26,12 +26,8 @@ public abstract class BaseChildItemClient<T>(IApiClient client) : BaseClient<T>(
if (item.Id != 0) if (item.Id != 0)
return await Save(item); return await Save(item);
return (await client.SendRequest<GeneralItemMessages<T>.Item>( return (await client.SendRequest<GeneralItemMessages<T>.Item>(
ApiEndpoint, $"{ApiEndpointParent}/{parentId}{ApiEndpointChild}",
HttpMethod.Post, HttpMethod.Post,
GenerateUpdateMessage(item, true), GenerateUpdateMessage(item, true))).EnsureOk().Item;
new ApiParameterCollection
{
["parent"] = parentId,
})).EnsureOk().Item;
} }
} }

View File

@@ -19,6 +19,19 @@ public abstract class BaseChildItemHandler<TEntity, TParent, TUpdateMsg>(IApiSer
public TParent? Parent => parent ??= getParent(); public TParent? Parent => parent ??= getParent();
} }
/// <summary>
/// Gets the base route (endpoint) for the most API calls.
/// By default this defines the combo of <see cref="RouteParent"/> and <see cref="RouteChild"/>.
/// </summary>
public override string Route => RouteParent + RouteChild;
/// <summary>
/// Gets the base route of the parent entity.
/// </summary>
public abstract string RouteParent { get; }
/// <summary>
/// Gets the realtive base route of the child entity.
/// </summary>
public abstract string RouteChild { get; }
protected virtual bool RegisterGetAll => true; protected virtual bool RegisterGetAll => true;
protected virtual bool RegisterPost => true; protected virtual bool RegisterPost => true;
@@ -27,18 +40,18 @@ public abstract class BaseChildItemHandler<TEntity, TParent, TUpdateMsg>(IApiSer
base.Initialize(server); base.Initialize(server);
var t = GetType(); var t = GetType();
if (RegisterGetAll) if (RegisterGetAll)
server.RegisterHandler(t.GetMethod(nameof(GetAll))!.CreateDelegate(this), new(Route, "GET"), Debugger.IsAttached); server.RegisterHandler(t.GetMethod(nameof(GetAll))!.CreateDelegate(this), new(RouteParent + "/{pid}" + RouteChild, "GET"), Debugger.IsAttached);
if (RegisterPost) if (RegisterPost)
server.RegisterHandler(t.GetMethod(nameof(Post))!.CreateDelegate(this), new(Route, "POST"), Debugger.IsAttached); server.RegisterHandler(t.GetMethod(nameof(Post))!.CreateDelegate(this), new(RouteParent + "/{pid}" + RouteChild, "POST"), Debugger.IsAttached);
} }
public virtual ApiResult GetAll(int parent) public virtual ApiResult GetAll(int pid)
{ {
IQueryable<TEntity> list; IQueryable<TEntity> list;
if (parent != 0) if (pid != 0)
{ {
if (!server.Manager.Find(parent, out TParent? parentEntity)) if (!server.Manager.Find(pid, out TParent? parentEntity))
return ApiResult.NotFound(); return ApiResult.NotFound();
list = GetChilds(parentEntity).AsQueryable(); list = GetChilds(parentEntity).AsQueryable();
} }
@@ -48,9 +61,9 @@ public abstract class BaseChildItemHandler<TEntity, TParent, TUpdateMsg>(IApiSer
return SortEntities(list).ToList().Select(ToClient).ToItemsResult(); return SortEntities(list).ToList().Select(ToClient).ToItemsResult();
} }
public virtual ApiResult Post(int parent, TUpdateMsg msg, ApiRequestInfo req) public virtual ApiResult Post(int pid, TUpdateMsg msg, ApiRequestInfo req)
{ {
if (!server.Manager.Find(parent, out TParent? parentEntity)) if (!server.Manager.Find(pid, out TParent? parentEntity))
return ApiResult.NotFound(); return ApiResult.NotFound();
var entity = CreateNewEntity(msg, parentEntity); var entity = CreateNewEntity(msg, parentEntity);
var update = new ChildEntityUpdate(entity, () => parentEntity, msg, req); var update = new ChildEntityUpdate(entity, () => parentEntity, msg, req);
@@ -81,7 +94,7 @@ public abstract class BaseChildItemHandler<TEntity, TParent, TUpdateMsg>(IApiSer
protected override ApiResult? OnSave(EntityUpdate update) protected override ApiResult? OnSave(EntityUpdate update)
{ {
if (update.Entity.Id == 0 && update is ChildEntityUpdate updateEx && updateEx.Parent != null) if (update.Entity.Id == 0 && update is ChildEntityUpdate { Parent: not null } updateEx)
{ {
server.Manager.Save(updateEx.Parent, true); server.Manager.Save(updateEx.Parent, true);
return null; return null;

View File

@@ -17,6 +17,9 @@ public abstract class BaseHandler<TEntity, TUpdateMsg>(IApiServer server)
public ApiRequestInfo Request { get; } = reqest; public ApiRequestInfo Request { get; } = reqest;
} }
/// <summary>
/// Gets the base route (endpoint) for the most API calls.
/// </summary>
public abstract string Route { get; } public abstract string Route { get; }
protected virtual bool RegisterGet => true; protected virtual bool RegisterGet => true;
protected virtual bool RegisterPut => true; protected virtual bool RegisterPut => true;