Skip to content

Lightweight result wrapper and validation toolkit for C#. Brings clean Result<T> handling and extensible validation with custom attributes.

License

Notifications You must be signed in to change notification settings

HBartosch/Routya.ResultKit

Repository files navigation

CI CI NuGet NuGet .NET Standard Supports Nested Validation

πŸ“¦ Routya.ResultKit

**Lightweight result wrapper, validation and transformation toolkit for C# **
Brings clean Result<T> handling and extensible validation with custom attributes.


✨ Features

  • βœ… Consistent Result<T> response pattern
  • βœ… One-line .Validate() extension for request models
  • βœ… .Transform() extension for clean and safe object/result projection
  • βœ… Rich built-in and custom validation attributes
  • βœ… Works great with System.ComponentModel.Annotations
  • βœ… Validation for nested objects

πŸ“₯ Installation

dotnet add package Routya.ResultKit --version 1.0.2

πŸš€ Quick Start

1. Define Your Request Model (with Custom Validation)

using Routya.ResultKit.Attributes;
using System.ComponentModel.DataAnnotations;

  private enum UserRole { Admin, User, Guest }

    private class TestModel
    {
        [Required]
        public string Name { get; set; }

        [EmailAddress]
        public string Email { get; set; }

        [Range(18, 120)]
        public int Age { get; set; }

        [StringEnum(typeof(UserRole))]
        public string Role { get; set; }

        [Required]
        public string Password { get; set; }

        [Compare("Password")]
        public string ConfirmPassword { get; set; }

        public decimal MinPurchase { get; set; }

        [GreaterThan("MinPurchase")]
        public decimal MaxPurchase { get; set; }
    }

2. Validate and Return

app.MapPost("/users", (CreateUserRequest request) =>
{
    var validationResult = request.Validate();

    if (!validationResult.Success)
        return Results.BadRequest(validationResult);

    return Results.Ok(Result.Ok(new { Id = 1 }));
});

βœ… Successful Response Example

{
	"Success": true,
	"Data": {
		"Name": "Henry",
		"Email": "henry@example.com",
		"Age": 30,
		"Role": "Admin",
		"Password": "abc123",
		"ConfirmPassword": "abc123",
		"MinPurchase": 100.0,
		"MaxPurchase": 200.0
	},
	"Error": null
}

❌ Validation Error Response Example

{
	"Success": false,
	"Data": null,
	"Error": {
		"Title": "Validation Failed",
		"Status": 400,
		"Extensions": {
			"errors": {
				"Name": [
					"The Name field is required."
				],
				"Email": [
					"The Email field is not a valid e-mail address."
				],
				"Age": [
					"The field Age must be between 18 and 120."
				],
				"Role": [
					"Role must be one of: Admin, User, Guest"
				],
				"ConfirmPassword": [
					"'ConfirmPassword' and 'Password' do not match."
				],
				"MaxPurchase": [
					"MaxPurchase must be greater than MinPurchase"
				]
			}
		}
	}
}

πŸ› οΈ Built-in Validation Attributes

Routya.ResultKit includes powerful validation attributes ready to use:

Attribute Purpose
[GreaterThan("OtherProp")] Ensure a property is greater than another
[LessThan("OtherProp")] Ensure a property is less than another
[RequiredIf("OtherProp", "Value")] Conditionally require a property
[RequiredIfEmpty("OtherProp")] Require a property if another is empty
[StringEnum(typeof(EnumType))] Ensure a string matches an Enum name
[MatchRegex("pattern")] Validate a string against a regex
[MinItems(count)] Validate minimum items in a collection
[MaxItems(count)] Validate maximum items in a collection
[ValidStartEndDateRange("Start", "End")] Validate that StartDate is before EndDate (This is a class level attribute)
[ValidDateTimeOffsetRange("End")] Validate DateTimeOffset ranges
[ValidDateTimeRange("End")] Validate DateTime ranges


πŸ” Transforming Models

Use .Transform(...) to reshape validated models or result data into domain entities or response objects β€” cleanly and safely.


βœ… Example 1: Basic Object Transformation

var request = "Hello";

var greeting = request.Transform(str => new Greeting
{
    Message = str,
    Length = str.Length
});
public class Greeting
{
    public string Message { get; set; }
    public int Length { get; set; }
}

βœ… Example 2: Full Validate β†’ Transform β†’ Result Flow

var result = request.Validate()
    .Transform(req => new CreateUserCommand
    {
        Name = req.Name,
        Email = req.Email,
        Role = Enum.Parse<UserRole>(req.Role, ignoreCase: true)
    });

βœ… Example 3: Transforming Result Output

var result = Result.Ok(user)
    .Transform(u => new UserResponse
    {
        Id = u.Id,
        Name = u.Name
    });

🧠 Why Use Transform(...)?

Benefit Description
βœ… Fluent Clean chaining after .Validate()
βœ… Safe When using Result it only transforms data if result is successful
βœ… Expressive Encourages intentional mapping logic
βœ… Lightweight Zero dependencies, pure functional mapping

πŸ” Bonus: Works with Both Objects and Result

TOut Transform<TIn, TOut>(this TIn input, Func<TIn, TOut> selector)

Result<TOut> Transform<TIn, TOut>(this Result<TIn> result, Func<TIn, TOut> selector)

About

Lightweight result wrapper and validation toolkit for C#. Brings clean Result<T> handling and extensible validation with custom attributes.

Topics

Resources

License

Contributing

Security policy

Stars

Watchers

Forks

Sponsor this project

Languages