Skip to content

Commit

Permalink
Merge pull request #32 from PandaTechAM/development
Browse files Browse the repository at this point in the history
Naming convention has been added
  • Loading branch information
HaikAsatryan committed Jun 13, 2024
2 parents 598f5a6 + d3b07e6 commit 76d5778
Show file tree
Hide file tree
Showing 10 changed files with 195 additions and 148 deletions.
60 changes: 44 additions & 16 deletions Readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@

## Introduction

ResponseCrafter is a comprehensive NuGet package for .NET 8+, specifically designed for enhanced exception handling and
logging in ASP.NET applications. This package simplifies the process of handling standard and custom exceptions by
**Pandatech.ResponseCrafter** is a comprehensive NuGet package for .NET 8+, specifically designed to enhance exception
handling and logging in ASP.NET Core applications. This package simplifies managing standard and custom exceptions by
crafting detailed error responses suitable for both development and production environments.

## Features
Expand All @@ -12,13 +12,14 @@ crafting detailed error responses suitable for both development and production e
exceptions.
* **Detailed Error Responses:** Generates verbose error messages, including stack traces for in-depth debugging in
development environments.
* **Environment-Sensitive Logging:** Offers a class `PandaExceptionHandler` which can be configured for message verbosity.
In production environments, only the exception type and message are logged. In development environments, the entire
exception is logged, including the stack trace.
* **Frontend-Friendly Error Messages:** Encourages the use of snake_case in error messages, facilitating easier
integration with frontend localization systems.
* **Organized/Readable and standardized error responses:** Provides a standardized error response format for all
exceptions, making it easier for frontend applications to parse and display error messages. The error response format is shown below:
* **Environment-Sensitive Logging:** Provides flexible logging and response behavior based on visibility settings (`Public` or `Private`):
- **Private:** All exceptions are sent to the client as defined, and 4xx errors are logged as warnings while 5xx errors are logged as errors.
- **Public:** 4xx exceptions are sent to the client as defined, while 5xx errors are concealed with a generic message. Logging remains the same as in `Private`.
* **Frontend-Friendly Error Messages:** Supports converting error messages to your desired case convention, facilitating
easier integration with frontend localization systems.
* **Standardized Error Responses:** Provides a standardized error response format, making it easier for frontend
applications to parse and display error messages. The error response format is shown below:

```json
{
"TraceId": "0HMVFE0A284AM:00000001",
Expand All @@ -31,7 +32,6 @@ crafting detailed error responses suitable for both development and production e
},
"Message": "the_request_was_invalid_or_cannot_be_otherwise_served."
}

````

## Installation
Expand All @@ -46,23 +46,51 @@ Install-Package ResponseCrafter

### 1. Setup Exception Handlers:

**Add** `AddResponseCrafter` in program.cs and in configuration set `"ResponseCrafterVisibility"` to `"Public"` or `"Private"`.
**Add** `AddResponseCrafter` in `program.cs` bby providing an optional naming convention, and
configure `ResponseCrafterVisibility` in your settings.

```csharp
var builder = WebApplication.CreateBuilder(args);

// Basic setup
builder.AddResponseCrafter();

// Setup with a specific naming convention
builder.AddResponseCrafter(NamingConvention.ToSnakeCase);

var app = builder.Build();
app.UseResponseCrafter();
app.Run();
```

Configure visibility in your `appsettings.json`:

```json
{
"ResponseCrafterVisibility": "Public"
}
```

Supported naming conventions:

```csharp
public enum NamingConvention
{
Default = 0,
ToSnakeCase = 1,
ToPascalCase = 2,
ToCamelCase = 3,
ToKebabCase = 4,
ToTitleCase = 5,
ToHumanCase = 6
}
```

### 2. Define Custom Exceptions:

* Create a custom exception class that inherits from `ApiException` or use already created ones:

* Utilize `ErrorDetails` records for specific error messages related to API requests.
Create custom exception classes that inherit from `ApiException` or use the predefined ones. Use `ErrorDetails` records
for
specific error messages related to API requests.

### 3. Configure Middleware:

Expand All @@ -74,9 +102,9 @@ app.UseResponseCrafter();

### 4. Logging and Error Responses:

* Automatically logs warnings or errors and provides crafted responses base on the exception type.
The package automatically logs warnings or errors and provides crafted responses based on the exception type.

## Custom Exception Already Created
## Custom HTTP Exception Already Created

* `BadRequestException`
* `UnauthorizedException`
Expand Down
3 changes: 2 additions & 1 deletion ResponseCrafter.sln.DotSettings
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<s:Boolean x:Key="/Default/UserDictionary/Words/=Dtos/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Dtos/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=gridify/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>
8 changes: 6 additions & 2 deletions src/ResponseCrafter/Enums/NamingConvention.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@ namespace ResponseCrafter.Enums;
public enum NamingConvention
{
Default = 0,
SnakeCaseLower = 1,
SnakeCaseUpper = 2
ToSnakeCase = 1,
ToPascalCase = 2,
ToCamelCase = 3,
ToKebabCase = 4,
ToTitleCase = 5,
ToHumanCase = 6
}
47 changes: 0 additions & 47 deletions src/ResponseCrafter/Extensions/NamingConventionExtensions.cs

This file was deleted.

28 changes: 28 additions & 0 deletions src/ResponseCrafter/Extensions/StringExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
using Humanizer;
using ResponseCrafter.Enums;
using ResponseCrafter.Options;

namespace ResponseCrafter.Extensions;

public static class StringExtensions
{
public static string ConvertCase(this string message, NamingConvention namingConvention)
{
return namingConvention switch
{
NamingConvention.Default => message,
NamingConvention.ToSnakeCase => message.Underscore(),
NamingConvention.ToPascalCase => message.Underscore().Pascalize(),
NamingConvention.ToCamelCase => message.Underscore().Camelize(),
NamingConvention.ToKebabCase => message.Underscore().Kebaberize(),
NamingConvention.ToTitleCase => message.Underscore().Titleize(),
NamingConvention.ToHumanCase => message.Underscore().Humanize(),
_ => message
};
}

internal static string ConvertCase(this string message, NamingConventionOptions option)
{
return message.ConvertCase(option.NamingConvention);
}
}
27 changes: 9 additions & 18 deletions src/ResponseCrafter/Extensions/WebApplicationExtensions.cs
Original file line number Diff line number Diff line change
@@ -1,36 +1,27 @@
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;
using ResponseCrafter.Enums;
using ResponseCrafter.Options;

namespace ResponseCrafter.Extensions;

public static class WebApplicationExtensions
{
public static WebApplicationBuilder AddResponseCrafter(this WebApplicationBuilder builder, NamingConvention? namingConvention = null)
public static WebApplicationBuilder AddResponseCrafter(this WebApplicationBuilder builder,
NamingConvention namingConvention = NamingConvention.Default)
{
builder.Services.AddSingleton(new NamingConventionOptions { NamingConvention = namingConvention });
builder.Services.AddExceptionHandler<PandaExceptionHandler>();

switch (namingConvention)
{
case null:
case NamingConvention.Default:
builder.Services.AddSingleton<Func<string, string>>(NamingConventionExtensions.Default);
break;
case NamingConvention.SnakeCaseLower:
builder.Services.AddSingleton<Func<string, string>>(NamingConventionExtensions.ToSnakeCaseLowerNamingConvention);
break;
case NamingConvention.SnakeCaseUpper:
builder.Services.AddSingleton<Func<string, string>>(NamingConventionExtensions.ToSnakeCaseUpperNamingConvention);
break;
default:
throw new ArgumentOutOfRangeException(nameof(namingConvention), namingConvention, null);
}


return builder;
}

public static WebApplication UseResponseCrafter(this WebApplication app)
{
app.UseExceptionHandler(_ => { }); //the lambda parameter is not needed it is just .net 8 bug which might be fixed in the future
app.UseExceptionHandler(_ =>
{
}); //the lambda parameter is not needed it is just .net 8 bug which might be fixed in the future

return app;
}
Expand Down
8 changes: 8 additions & 0 deletions src/ResponseCrafter/Options/NamingConventionOptions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
using ResponseCrafter.Enums;

namespace ResponseCrafter.Options;

public class NamingConventionOptions
{
public NamingConvention NamingConvention { get; set; }
}
Loading

0 comments on commit 76d5778

Please sign in to comment.