{"id":32492888,"url":"https://github.com/fkucukkara/result-pattern","last_synced_at":"2026-07-08T12:31:01.855Z","repository":{"id":318000092,"uuid":"1069621870","full_name":"fkucukkara/result-pattern","owner":"fkucukkara","description":"A comprehensive demonstration of the Result Pattern.","archived":false,"fork":false,"pushed_at":"2025-10-04T12:55:03.000Z","size":35,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2025-10-04T13:09:55.703Z","etag":null,"topics":["clean-code","csharp","netcore","playground-project","result-pattern"],"latest_commit_sha":null,"homepage":"","language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/fkucukkara.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-10-04T09:46:31.000Z","updated_at":"2025-10-04T12:55:07.000Z","dependencies_parsed_at":"2025-10-04T13:20:00.121Z","dependency_job_id":null,"html_url":"https://github.com/fkucukkara/result-pattern","commit_stats":null,"previous_names":["fkucukkara/result-pattern"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/fkucukkara/result-pattern","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fkucukkara%2Fresult-pattern","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fkucukkara%2Fresult-pattern/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fkucukkara%2Fresult-pattern/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fkucukkara%2Fresult-pattern/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/fkucukkara","download_url":"https://codeload.github.com/fkucukkara/result-pattern/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fkucukkara%2Fresult-pattern/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":35265380,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-07-08T02:00:06.796Z","response_time":61,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["clean-code","csharp","netcore","playground-project","result-pattern"],"created_at":"2025-10-27T11:56:34.898Z","updated_at":"2026-07-08T12:31:01.849Z","avatar_url":"https://github.com/fkucukkara.png","language":"C#","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Result Pattern Demo \n\nA comprehensive demonstration of the **Result Pattern** in .NET 10, showing how to handle errors gracefully without throwing exceptions in a real-world ASP.NET Core Minimal API.\n\n## What is the Result Pattern?\n\nThe Result pattern is a functional programming approach that makes failures explicit in method signatures. Instead of throwing exceptions, you return a Result object that represents either success or failure, making error handling predictable and performant.\n\n## Key Benefits\n\n- **Performance**: No exception overhead for expected failures\n- **Explicit Error Handling**: Errors are part of method signatures, making them impossible to ignore\n- **Predictable**: Clear success/failure paths with no hidden control flow\n- **Clean Code**: No scattered try-catch blocks throughout your application\n- **Composable**: Results can be chained and transformed easily\n- **Type Safety**: Compile-time guarantees about error handling\n\n## Core Implementation\n\n### Result Types\n\n```csharp\n// Non-generic Result for operations without return values\nResult operationResult = Result.Success();\nResult failureResult = Result.Failure(\"Something went wrong\");\n\n// Generic Result\u003cT\u003e for operations that return values\nResult\u003cUser\u003e userResult = Result\u003cUser\u003e.Success(user);\nResult\u003cUser\u003e notFoundResult = Result\u003cUser\u003e.Failure(\"User not found\");\n```\n\n### Basic Usage\n\n```csharp\npublic async Task\u003cResult\u003cUser\u003e\u003e GetUserAsync(int id)\n{\n    if (id \u003c= 0)\n        return Result\u003cUser\u003e.Failure(\"Invalid user ID\");\n    \n    var user = await _repository.GetByIdAsync(id);\n    return user is not null \n        ? Result\u003cUser\u003e.Success(user)\n        : Result\u003cUser\u003e.Failure(\"User not found\");\n}\n\n// Using the result\nvar result = await GetUserAsync(123);\nif (result.IsSuccess)\n{\n    Console.WriteLine($\"Found user: {result.Value.Name}\");\n}\nelse\n{\n    Console.WriteLine($\"Error: {result.Error}\");\n}\n```\n\n### HTTP Response Extensions\n\nThe demo includes custom extensions to convert Results to appropriate HTTP responses:\n\n```csharp\n// Converts Result\u003cT\u003e to HTTP responses with proper status codes\nreturn result.ToHttpResponse(); // 200 OK or 400 Bad Request\n\n// For operations that can return 404 Not Found\nreturn result.ToHttpResponseWithNotFound(); // 200 OK, 400 Bad Request, or 404 Not Found\n```\n\n## API Endpoints\n\nThe demo includes a complete User management API demonstrating the Result pattern in action:\n\n### User Operations\n- **GET** `/api/users/{id}` - Get user by ID\n  - Returns 200 with user data on success\n  - Returns 404 when user not found\n  - Returns 400 for invalid ID (≤ 0)\n\n- **POST** `/api/users` - Create new user\n  - Returns 200 with created user on success\n  - Returns 400 for validation errors (duplicate email, invalid age)\n\n- **PUT** `/api/users/{id}` - Update user\n  - Returns 200 with updated user on success\n  - Returns 404 when user not found\n  - Returns 400 for validation errors\n\n- **DELETE** `/api/users/{id}` - Delete user\n  - Returns 200 on successful deletion\n  - Returns 404 when user not found\n\n### Request/Response Models\n\n**Create User Request:**\n```json\n{\n  \"name\": \"John Doe\",\n  \"email\": \"john@example.com\",\n  \"age\": 30\n}\n```\n\n**Update User Request:**\n```json\n{\n  \"name\": \"John Updated\",\n  \"age\": 31\n}\n```\n\n**User Response:**\n```json\n{\n  \"id\": 123,\n  \"name\": \"John Doe\",\n  \"email\": \"john@example.com\",\n  \"age\": 30\n}\n```\n\n**Error Response:**\n```json\n{\n  \"message\": \"Email already exists\"\n}\n```\n\n## Running the Demo\n\n1. **Clone the repository**\n   ```bash\n   git clone \u003crepository-url\u003e\n   cd result-pattern-101\n   ```\n\n2. **Build and run the application**\n   ```bash\n   # From the root directory\n   dotnet build\n   dotnet run --project src/ResultPattern.API\n   ```\n\n3. **Access the API**\n   - API will be available at: `https://localhost:7055`\n   - Swagger documentation: `https://localhost:7055/openapi/v1.json`\n   - Use the provided `API.http` file for testing requests\n\n## Testing the API\n\nThe project includes an `API.http` file with comprehensive test cases covering:\n\n- ✅ **Success scenarios**: Valid operations that work as expected\n- ❌ **Failure scenarios**: Invalid inputs, not found cases, and validation errors\n- 🔍 **Edge cases**: Boundary conditions and error handling\n\n### Quick Test Sequence\n\n1. **Create a user**: `POST /api/users` with valid data\n2. **Get the user**: `GET /api/users/1` to retrieve the created user\n3. **Update the user**: `PUT /api/users/1` with new data\n4. **Try invalid operations**: Test error cases like invalid IDs or duplicate emails\n5. **Delete the user**: `DELETE /api/users/1`\n\n## Example Flows\n\n### Creating a User (Success)\n\n**Request:**\n```bash\nPOST /api/users\nContent-Type: application/json\n\n{\n  \"name\": \"John Doe\",\n  \"email\": \"john@example.com\",\n  \"age\": 30\n}\n```\n\n**Response (200 OK):**\n```json\n{\n  \"id\": 1,\n  \"name\": \"John Doe\",\n  \"email\": \"john@example.com\",\n  \"age\": 30\n}\n```\n\n### Creating a User (Validation Error)\n\n**Request:**\n```bash\nPOST /api/users\nContent-Type: application/json\n\n{\n  \"name\": \"Jane Smith\",\n  \"email\": \"john@example.com\",  // Duplicate email\n  \"age\": 25\n}\n```\n\n**Response (400 Bad Request):**\n```json\n{\n  \"message\": \"Email already exists\"\n}\n```\n\n### Getting a User (Not Found)\n\n**Request:**\n```bash\nGET /api/users/999\n```\n\n**Response (404 Not Found):**\n```json\n{\n  \"message\": \"User not found\"\n}\n```\n\n## Project Structure\n\n```\nresult-pattern-101/\n├── ResultPattern.sln                # Solution file\n├── global.json                      # .NET SDK configuration\n├── Directory.Build.props            # Centralized build properties\n└── src/\n    └── ResultPattern.API/\n        ├── ResultPattern.API.csproj # Project file (.NET 10)\n        ├── API.http                 # HTTP test requests\n        ├── Program.cs               # Application entry point \u0026 Minimal API setup\n        ├── appsettings.json         # Configuration\n        ├── appsettings.Development.json # Development configuration\n        ├── Common/\n        │   └── Result.cs            # Core Result pattern implementation\n        ├── Extensions/\n        │   └── ResultExtensions.cs  # HTTP response extensions\n        ├── Models/\n        │   └── ApiModels.cs         # Request/Response models\n        ├── Services/\n        │   ├── UserRepository.cs    # Data access using Result pattern\n        │   └── UserService.cs       # Business logic using Result pattern\n    └── Properties/\n        └── launchSettings.json      # Launch configuration\n```\n\n## Key Implementation Files\n\n### 🎯 **Common/Result.cs**\nCore Result pattern implementation featuring:\n- Generic and non-generic Result types\n- Implicit conversion operators\n- Fluent API for creating success/failure results\n\n### 🔌 **Extensions/ResultExtensions.cs**\nHTTP response extensions that convert Results to appropriate HTTP status codes:\n- `ToHttpResponse()` - 200 OK or 400 Bad Request\n- `ToHttpResponseWithNotFound()` - 200 OK, 400 Bad Request, or 404 Not Found\n\n### 🏢 **Services/UserService.cs**\nBusiness logic layer demonstrating:\n- Input validation using the Result pattern\n- Async operations with Result return types\n- Composition of multiple Result-based operations\n\n### 💾 **Services/UserRepository.cs**\nData access layer showing:\n- In-memory storage with Result-based operations\n- Async database simulation\n- Common data access patterns with Results\n\n### 🌐 **Program.cs**\nASP.NET Core Minimal API setup featuring:\n- Dependency injection configuration\n- Route mapping with Result-to-HTTP conversion\n- Clean separation of concerns\n\n## Result Pattern Benefits Demonstrated\n\n### 1. **Performance** \nNo exception overhead for expected failures like \"user not found\" or validation errors.\n\n### 2. **Explicit Error Handling**\nMethod signatures clearly indicate what can go wrong:\n```csharp\nTask\u003cResult\u003cUser\u003e\u003e GetUserByIdAsync(int id)  // Can fail\nTask\u003cResult\u003e DeleteUserAsync(int id)         // Can fail\n```\n\n### 3. **Predictable Control Flow**\nNo hidden exceptions - all error paths are explicit and handled at the call site.\n\n### 4. **Clean API Design**\nHTTP endpoints automatically return appropriate status codes based on Result state.\n\n### 5. **Composability**\nResults can be chained and transformed easily without nested try-catch blocks.\n\n## Advanced Patterns\n\nThe demo showcases several advanced Result pattern techniques:\n\n- **Repository Pattern Integration**: Data access layer returns Results\n- **Service Layer Composition**: Business logic combines multiple Result operations\n- **HTTP Response Mapping**: Automatic conversion from Results to HTTP responses\n- **Validation Integration**: Input validation using the Result pattern\n- **Async/Await Support**: Full async support throughout the pipeline\n\n## Best Practices Demonstrated\n\n✅ **Use Results for expected failures** (validation, not found, business rule violations)  \n✅ **Keep exception handling for unexpected failures** (network issues, database connectivity)  \n✅ **Make error messages user-friendly and actionable**  \n✅ **Use appropriate HTTP status codes based on Result state**  \n✅ **Leverage implicit conversions for clean code**  \n✅ **Compose Results using extension methods**  \n\nThe Result pattern provides a clean, performant, and predictable way to handle errors in modern .NET applications, making your code more robust and maintainable.\n\n## License\n[![MIT License](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)\n\nThis project is licensed under the MIT License, which allows you to freely use, modify, and distribute the code. See the [`LICENSE`](LICENSE) file for full details.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffkucukkara%2Fresult-pattern","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ffkucukkara%2Fresult-pattern","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffkucukkara%2Fresult-pattern/lists"}