ZodSharp Integration
ZodSharp Integration
Section titled “ZodSharp Integration”Purview.Results.ZodSharp bridges ZodSharp
ValidationResult<T> values into results, so validation outcomes flow through the same result pipeline as every
other expected outcome instead of throwing.
Installation
Section titled “Installation”dotnet add package Purview.Results.ZodSharpWhy a bridge
Section titled “Why a bridge”ZodSharp validation never throws: Validate returns a ValidationResult<T> carrying the validated value on
success and every ValidationError on failure. That is already a result-shaped value, but it is not
Result<TValue, TError> — the failure type is fixed rather than chosen by the caller. ToResult closes that gap.
Quick start
Section titled “Quick start”return RepositoryReconciliationResultSchema .Validate(reconciliationResult) .ToResult<RepositoryReconciliationResult, ReconciliationError>(errors => new ReconciliationResultInvalid(reconciliationResult, errors) );ToResult names both type arguments explicitly — including the error type — because a union case does not
carry the union type that contains it:
.ToResult<RepositoryReconciliationResult, ReconciliationError>(...)When the success type differs from the validated type
Section titled “When the success type differs from the validated type”If the surrounding method’s success value is not the validated value, produce the failure with the generated
AsFailure<TValue>() helper instead, because the validated value cannot be carried forward:
var validated = ProviderConnectionIdSchema.Validate(providerConnectionId);
if (!validated.IsSuccess) return new ProviderConnectionInvalid(providerConnectionId, validated.Errors) .AsFailure<RepositoryReconciliationResult>();
return await ReconcileCoreAsync(validated.Value, repositories, cancellationToken);Carrying validation errors in the error value
Section titled “Carrying validation errors in the error value”IValidationErrorCarrier is implemented by an error value that carries ZodSharp validation errors, so an HTTP
layer can turn it into a validation problem without knowing the error type:
public readonly record struct TenantInputInvalid(TenantInput Input, ImmutableArray<ValidationError> Errors) : IValidationErrorCarrier{ public ImmutableArray<ValidationError> ValidationErrors => Errors;}IValidationErrorCarrier exposes a single ValidationErrors member, preserving each ValidationError’s code,
category, path and parameters.
ZodSharp Problem Details consumes the interface; without it, a host would have to map every validation-carrying error individually.
| Member | Purpose |
|---|---|
ValidationResult<TValue>.ToResult<TValue, TError>(Func<ImmutableArray<ValidationError>, TError> onFailure) | Success carries the validated value; failure carries the created error. onFailure runs only when validation failed, so a successful validation allocates no error |
IValidationErrorCarrier | Implemented by an error value that carries ZodSharp validation errors |
A factory returning a result rather than an error is deliberately not offered: for a lambda returning
Result<TValue, TError> the compiler prefers a Func<..., TError> parameter and would silently nest the results.
Naming the error type explicitly keeps the intent unambiguous.
Example
Section titled “Example”dotnet run --project src/examples/Examples.ZodExamples.Zod validates a [ZodSchema] TenantInput and turns the outcome into a Result<Tenant, TenantError>,
with the rejection carrying its reported ValidationErrors.
Related
Section titled “Related”- ZodSharp Problem Details — the ASP.NET Core rendering of an
IValidationErrorCarrierfailure. - Core Concepts — the result states the validated value flows into.