(feature): simplify patch request fields management for frontend validation like zod

This commit is contained in:
Maksym Sadovnychyy 2024-12-14 17:54:06 +01:00
parent 2e2036c90d
commit eaa610a853
5 changed files with 29 additions and 39 deletions

View File

@ -1945,22 +1945,7 @@ var response = new PagedResponse<User>(users, totalCount: 100, pageNumber: 1, pa
---
#### **3. `PatchField<T>`**
##### Summary
Represents a patch operation on a specific field or value, used for partial updates in Web APIs.
##### Usage
```csharp
var patchField = new PatchField<string> {
Operation = PatchOperation.Replace,
Value = "New Value"
};
```
---
#### **4. `PatchOperation`**
#### **3. `PatchOperation`**
##### Summary
Enumerates the types of patch operations that can be performed on a field or collection.
@ -2008,13 +1993,18 @@ Console.WriteLine($"Total Pages: {pagedResponse.TotalPages}");
### Partial Updates Using PatchField
```csharp
var patch = new PatchField<string> {
Operation = PatchOperation.Replace,
Value = "Updated Name"
var patch = new SomePatchRequestModel {
Username = "Updated Name"
Operations = new Dictionary<string, PatchOperation> {
{ "Username", PartchOperation.Replace }
}
};
// Deconstruct the patch field
var (operation, value) = patch;
var usernmae = patch.Username;
var operation = GetOperation(nameOf(patch.Username);
Console.WriteLine($"Operation: {operation}, Value: {value}");
```

View File

@ -1,17 +1,25 @@
using System.ComponentModel.DataAnnotations;
using System.Reflection;
using System.Reflection;
using System.ComponentModel.DataAnnotations;
using MaksIT.Core.Webapi.Models;
namespace MaksIT.Core.Abstractions.Webapi;
public abstract class PatchRequestModelBase : RequestModelBase, IValidatableObject {
public abstract class PatchRequestModelBase : RequestModelBase {
public Dictionary<string, PatchOperation> Operations = new Dictionary<string, PatchOperation>();
private bool HasNonNullPatchField => GetType()
.GetProperties(BindingFlags.Public | BindingFlags.Instance)
.Where(prop => prop.PropertyType.IsGenericType && prop.PropertyType.GetGenericTypeDefinition() == typeof(PatchField<>))
.Where(prop => prop.Name != nameof(Operations))
.Any(prop => prop.GetValue(this) != null);
public virtual IEnumerable<ValidationResult> Validate(ValidationContext validationContext) {
public PatchOperation GetOperation(string propertyName) {
return Operations[propertyName];
}
public override IEnumerable<ValidationResult> Validate(ValidationContext validationContext) {
if (!HasNonNullPatchField) {
yield return new ValidationResult("At least one patch field must be provided", new string[] { "PatchField" });
}

View File

@ -1,9 +1,13 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace MaksIT.Core.Abstractions.Webapi;
public abstract class RequestModelBase {
public abstract class RequestModelBase : IValidatableObject {
public virtual IEnumerable<ValidationResult> Validate(ValidationContext validationContext) {
return Enumerable.Empty<ValidationResult>();
}
}

View File

@ -8,7 +8,7 @@
<!-- NuGet package metadata -->
<PackageId>MaksIT.Core</PackageId>
<Version>1.2.2</Version>
<Version>1.2.3</Version>
<Authors>Maksym Sadovnychyy</Authors>
<Company>MAKS-IT</Company>
<Product>MaksIT.Core</Product>

View File

@ -1,12 +0,0 @@

namespace MaksIT.Core.Webapi.Models;
public class PatchField<T> {
public PatchOperation Operation { get; set; }
public T? Value { get; set; }
public void Deconstruct(out PatchOperation operation, out T? value) {
operation = Operation;
value = Value;
}
}