Skip to content

Commit

Permalink
feat(ProblemDetails): Allow filtering properties (Detail, ExceptionDe…
Browse files Browse the repository at this point in the history
…tails) for response ProblemDetails response. Resolves khellang#194
  • Loading branch information
jafin committed Aug 17, 2023
1 parent 64f209d commit 5ac55a0
Show file tree
Hide file tree
Showing 5 changed files with 50 additions and 5 deletions.
5 changes: 5 additions & 0 deletions samples/ProblemDetails.Sample/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,11 @@ private void ConfigureProblemDetails(ProblemDetailsOptions options)
// Only include exception details in a development environment. There's really no need
// to set this as it's the default behavior. It's just included here for completeness :)
options.IncludeExceptionDetails = (ctx, ex) => Environment.IsDevelopment();
options.IncludePropsFilter = (context, exception) => new IncludeProblemDetailProps()
{
Detail = true,
ExceptionDetails = true
};

// Custom mapping function for FluentValidation's ValidationException.
options.MapFluentValidationException();
Expand Down
15 changes: 12 additions & 3 deletions src/ProblemDetails/DeveloperProblemDetailsExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,22 @@ namespace Hellang.Middleware.ProblemDetails
{
internal static class DeveloperProblemDetailsExtensions
{
public static MvcProblemDetails WithExceptionDetails(this MvcProblemDetails problem, string propertyName, Exception error, IEnumerable<ExceptionDetails> details)
public static MvcProblemDetails WithExceptionDetails(this MvcProblemDetails problem, string propertyName, Exception error, IEnumerable<ExceptionDetails> details, IncludeProblemDetailProps includeProps)
{
problem.Title ??= TypeNameHelper.GetTypeDisplayName(error.GetType());
problem.Extensions[propertyName] = GetErrors(details).ToList();

if (includeProps.ExceptionDetails)
{
problem.Extensions[propertyName] = GetErrors(details).ToList();
}

problem.Status ??= StatusCodes.Status500InternalServerError;
problem.Instance ??= GetHelpLink(error);
problem.Detail ??= error.Message;
if (includeProps.Detail)
{
problem.Detail ??= error.Message;
}

return problem;
}

Expand Down
19 changes: 19 additions & 0 deletions src/ProblemDetails/IncludeProblemDetailProps.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
namespace Hellang.Middleware.ProblemDetails
{
/// <summary>
/// Properties to include in ProblemDetails.
/// By default, all properties are false and will not be included.
/// </summary>
public class IncludeProblemDetailProps
{
/// <summary>
/// Include the Exception Details Stack
/// </summary>
public bool ExceptionDetails { get; set; }

/// <summary>
/// Include the Detail summary property
/// </summary>
public bool Detail { get; set; }
}
}
8 changes: 6 additions & 2 deletions src/ProblemDetails/ProblemDetailsFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -61,12 +61,16 @@ public ProblemDetailsFactory(
}
}

if (Options.IncludeExceptionDetails(context, error))
var includePropsFilter = Options.IncludePropsFilter?.Invoke(context, error);

if (Options.IncludeExceptionDetails(context, error) || includePropsFilter is not null)
{
try
{
includePropsFilter ??= new IncludeProblemDetailProps{ExceptionDetails = true, Detail = true};
// Instead of returning a new object, we mutate the existing problem so users keep all details.
return result.WithExceptionDetails(Options.ExceptionDetailsPropertyName, error, DetailsProvider.GetDetails(error));
return result.WithExceptionDetails(Options.ExceptionDetailsPropertyName, error,
DetailsProvider.GetDetails(error), includePropsFilter);
}
catch (Exception e)
{
Expand Down
8 changes: 8 additions & 0 deletions src/ProblemDetails/ProblemDetailsOptions.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc.Formatters;
using Microsoft.Extensions.FileProviders;
Expand Down Expand Up @@ -64,6 +65,13 @@ public ProblemDetailsOptions()
/// </summary>
public Func<HttpContext, Exception, bool> IncludeExceptionDetails { get; set; } = null!;

/// <summary>
/// Configure which properties to include in the problem details response.
/// By default all fields are excluded.
/// This can be used as an alternative to <see cref="IncludeExceptionDetails"/> when specific fields are needed.
/// </summary>
public Func<HttpContext, Exception, IncludeProblemDetailProps>? IncludePropsFilter { get; set; } = null!;

/// <summary>
/// The property name to use for traceId
/// This defaults to <see cref="DefaultTraceIdPropertyName"/> (<c>traceId</c>).
Expand Down

0 comments on commit 5ac55a0

Please sign in to comment.