Skip to content

Commit 8e94205

Browse files
committed
Merge branch 'feat/#223' into operations
2 parents 956f473 + 7d7add2 commit 8e94205

File tree

9 files changed

+102
-56
lines changed

9 files changed

+102
-56
lines changed

src/JsonApiDotNetCore/Configuration/JsonApiOptions.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,16 @@ namespace JsonApiDotNetCore.Configuration
1616
/// </summary>
1717
public class JsonApiOptions
1818
{
19+
/// <summary>
20+
/// Whether or not stack traces should be serialized in Error objects
21+
/// </summary>
22+
public static bool DisableErrorStackTraces { get; set; }
23+
24+
/// <summary>
25+
/// Whether or not source URLs should be serialized in Error objects
26+
/// </summary>
27+
public static bool DisableErrorSource { get; set; }
28+
1929
/// <summary>
2030
/// The base URL Namespace
2131
/// </summary>

src/JsonApiDotNetCore/Controllers/BaseJsonApiController.cs

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ public BaseJsonApiController(
104104

105105
public virtual async Task<IActionResult> GetAsync()
106106
{
107-
if (_getAll == null) throw new JsonApiException(405, "Get requests are not supported");
107+
if (_getAll == null) throw Exceptions.UnSupportedRequestMethod;
108108

109109
var entities = await _getAll.GetAsync();
110110

@@ -113,7 +113,7 @@ public virtual async Task<IActionResult> GetAsync()
113113

114114
public virtual async Task<IActionResult> GetAsync(TId id)
115115
{
116-
if (_getById == null) throw new JsonApiException(405, "Get by Id requests are not supported");
116+
if (_getById == null) throw Exceptions.UnSupportedRequestMethod;
117117

118118
var entity = await _getById.GetAsync(id);
119119

@@ -125,7 +125,7 @@ public virtual async Task<IActionResult> GetAsync(TId id)
125125

126126
public virtual async Task<IActionResult> GetRelationshipsAsync(TId id, string relationshipName)
127127
{
128-
if (_getRelationships == null) throw new JsonApiException(405, "Get Relationships requests are not supported");
128+
if (_getRelationships == null) throw Exceptions.UnSupportedRequestMethod;
129129

130130
var relationship = await _getRelationships.GetRelationshipsAsync(id, relationshipName);
131131
if (relationship == null)
@@ -136,7 +136,7 @@ public virtual async Task<IActionResult> GetRelationshipsAsync(TId id, string re
136136

137137
public virtual async Task<IActionResult> GetRelationshipAsync(TId id, string relationshipName)
138138
{
139-
if (_getRelationship == null) throw new JsonApiException(405, "Get Relationship requests are not supported");
139+
if (_getRelationship == null) throw Exceptions.UnSupportedRequestMethod;
140140

141141
var relationship = await _getRelationship.GetRelationshipAsync(id, relationshipName);
142142

@@ -145,7 +145,7 @@ public virtual async Task<IActionResult> GetRelationshipAsync(TId id, string rel
145145

146146
public virtual async Task<IActionResult> PostAsync([FromBody] T entity)
147147
{
148-
if (_create == null) throw new JsonApiException(405, "Post requests are not supported");
148+
if (_create == null) throw Exceptions.UnSupportedRequestMethod;
149149

150150
if (entity == null)
151151
return UnprocessableEntity();
@@ -160,7 +160,7 @@ public virtual async Task<IActionResult> PostAsync([FromBody] T entity)
160160

161161
public virtual async Task<IActionResult> PatchAsync(TId id, [FromBody] T entity)
162162
{
163-
if (_update == null) throw new JsonApiException(405, "Patch requests are not supported");
163+
if (_update == null) throw Exceptions.UnSupportedRequestMethod;
164164

165165
if (entity == null)
166166
return UnprocessableEntity();
@@ -175,7 +175,7 @@ public virtual async Task<IActionResult> PatchAsync(TId id, [FromBody] T entity)
175175

176176
public virtual async Task<IActionResult> PatchRelationshipsAsync(TId id, string relationshipName, [FromBody] List<DocumentData> relationships)
177177
{
178-
if (_updateRelationships == null) throw new JsonApiException(405, "Relationship Patch requests are not supported");
178+
if (_updateRelationships == null) throw Exceptions.UnSupportedRequestMethod;
179179

180180
await _updateRelationships.UpdateRelationshipsAsync(id, relationshipName, relationships);
181181

@@ -184,7 +184,7 @@ public virtual async Task<IActionResult> PatchRelationshipsAsync(TId id, string
184184

185185
public virtual async Task<IActionResult> DeleteAsync(TId id)
186186
{
187-
if (_delete == null) throw new JsonApiException(405, "Delete requests are not supported");
187+
if (_delete == null) throw Exceptions.UnSupportedRequestMethod;
188188

189189
var wasDeleted = await _delete.DeleteAsync(id);
190190

src/JsonApiDotNetCore/Extensions/IApplicationBuilderExtensions.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
1+
using JsonApiDotNetCore.Configuration;
12
using JsonApiDotNetCore.Middleware;
23
using Microsoft.AspNetCore.Builder;
4+
using Microsoft.AspNetCore.Hosting;
35

46
namespace JsonApiDotNetCore.Extensions
57
{
@@ -8,6 +10,14 @@ public static class IApplicationBuilderExtensions
810
{
911
public static IApplicationBuilder UseJsonApi(this IApplicationBuilder app, bool useMvc = true)
1012
{
13+
var environment = (IHostingEnvironment)app.ApplicationServices.GetService(typeof(IHostingEnvironment));
14+
15+
if(environment.IsProduction())
16+
{
17+
JsonApiOptions.DisableErrorStackTraces = true;
18+
JsonApiOptions.DisableErrorSource = true;
19+
}
20+
1121
app.UseMiddleware<RequestMiddleware>();
1222

1323
if (useMvc)

src/JsonApiDotNetCore/Formatters/JsonApiWriter.cs

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,6 @@ public async Task WriteAsync(OutputFormatterWriteContext context)
2626
if (context == null)
2727
throw new ArgumentNullException(nameof(context));
2828

29-
_logger?.LogInformation("Formatting response as JSONAPI");
30-
3129
var response = context.HttpContext.Response;
3230
using (var writer = context.WriterFactory(response.Body, Encoding.UTF8))
3331
{
@@ -40,9 +38,7 @@ public async Task WriteAsync(OutputFormatterWriteContext context)
4038
catch (Exception e)
4139
{
4240
_logger?.LogError(new EventId(), e, "An error ocurred while formatting the response");
43-
var errors = new ErrorCollection();
44-
errors.Add(new Error("400", e.Message));
45-
responseContent = errors.GetJson();
41+
responseContent = GetErrorResponse(e);
4642
response.StatusCode = 400;
4743
}
4844

@@ -51,9 +47,12 @@ public async Task WriteAsync(OutputFormatterWriteContext context)
5147
}
5248
}
5349

54-
private string GetResponseBody(object responseObject)
50+
private string GetResponseBody(object responseObject) => _serializer.Serialize(responseObject);
51+
private string GetErrorResponse(Exception e)
5552
{
56-
return _serializer.Serialize(responseObject);
57-
}
53+
var errors = new ErrorCollection();
54+
errors.Add(new Error(400, e.Message, ErrorMeta.FromException(e)));
55+
return errors.GetJson();
56+
}
5857
}
5958
}

src/JsonApiDotNetCore/Internal/Error.cs

Lines changed: 36 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
using System;
2+
using System.Diagnostics;
3+
using JsonApiDotNetCore.Configuration;
24
using Newtonsoft.Json;
35

46
namespace JsonApiDotNetCore.Internal
@@ -8,30 +10,40 @@ public class Error
810
public Error()
911
{ }
1012

11-
public Error(string status, string title)
13+
[Obsolete("Use Error constructors with int typed status")]
14+
public Error(string status, string title, ErrorMeta meta = null, string source = null)
1215
{
1316
Status = status;
1417
Title = title;
18+
Meta = meta;
19+
Source = source;
1520
}
1621

17-
public Error(int status, string title)
22+
public Error(int status, string title, ErrorMeta meta = null, string source = null)
1823
{
1924
Status = status.ToString();
2025
Title = title;
26+
Meta = meta;
27+
Source = source;
2128
}
2229

23-
public Error(string status, string title, string detail)
30+
[Obsolete("Use Error constructors with int typed status")]
31+
public Error(string status, string title, string detail, ErrorMeta meta = null, string source = null)
2432
{
2533
Status = status;
2634
Title = title;
2735
Detail = detail;
36+
Meta = meta;
37+
Source = source;
2838
}
2939

30-
public Error(int status, string title, string detail)
40+
public Error(int status, string title, string detail, ErrorMeta meta = null, string source = null)
3141
{
3242
Status = status.ToString();
3343
Title = title;
3444
Detail = detail;
45+
Meta = meta;
46+
Source = source;
3547
}
3648

3749
[JsonProperty("title")]
@@ -45,5 +57,25 @@ public Error(int status, string title, string detail)
4557

4658
[JsonIgnore]
4759
public int StatusCode => int.Parse(Status);
60+
61+
[JsonProperty("source")]
62+
public string Source { get; set; }
63+
64+
[JsonProperty("meta")]
65+
public ErrorMeta Meta { get; set; }
66+
67+
public bool ShouldSerializeMeta() => (JsonApiOptions.DisableErrorStackTraces == false);
68+
public bool ShouldSerializeSource() => (JsonApiOptions.DisableErrorSource == false);
69+
}
70+
71+
public class ErrorMeta
72+
{
73+
[JsonProperty("stackTrace")]
74+
public string[] StackTrace { get; set; }
75+
76+
public static ErrorMeta FromException(Exception e)
77+
=> new ErrorMeta {
78+
StackTrace = e.Demystify().ToString().Split(new[] { "\n"}, int.MaxValue, StringSplitOptions.RemoveEmptyEntries)
79+
};
4880
}
4981
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
namespace JsonApiDotNetCore.Internal
2+
{
3+
internal static class Exceptions
4+
{
5+
private const string DOCUMENTATION_URL = "https://json-api-dotnet.github.io/#/errors/";
6+
private static string BuildUrl(string title) => DOCUMENTATION_URL + title;
7+
8+
public static JsonApiException UnSupportedRequestMethod { get; }
9+
= new JsonApiException(405, "Request method is not supported.", BuildUrl(nameof(UnSupportedRequestMethod)));
10+
}
11+
}

src/JsonApiDotNetCore/Internal/JsonApiException.cs

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -13,30 +13,29 @@ public JsonApiException(ErrorCollection errorCollection)
1313
}
1414

1515
public JsonApiException(Error error)
16-
: base(error.Title)
17-
=> _errors.Add(error);
16+
: base(error.Title) => _errors.Add(error);
1817

1918
[Obsolete("Use int statusCode overload instead")]
20-
public JsonApiException(string statusCode, string message)
19+
public JsonApiException(string statusCode, string message, string source = null)
2120
: base(message)
22-
=> _errors.Add(new Error(statusCode, message, null));
21+
=> _errors.Add(new Error(statusCode, message, null, GetMeta(), source));
2322

2423
[Obsolete("Use int statusCode overload instead")]
25-
public JsonApiException(string statusCode, string message, string detail)
24+
public JsonApiException(string statusCode, string message, string detail, string source = null)
2625
: base(message)
27-
=> _errors.Add(new Error(statusCode, message, detail));
26+
=> _errors.Add(new Error(statusCode, message, detail, GetMeta(), source));
2827

29-
public JsonApiException(int statusCode, string message)
28+
public JsonApiException(int statusCode, string message, string source = null)
3029
: base(message)
31-
=> _errors.Add(new Error(statusCode, message, null));
30+
=> _errors.Add(new Error(statusCode, message, null, GetMeta(), source));
3231

33-
public JsonApiException(int statusCode, string message, string detail)
32+
public JsonApiException(int statusCode, string message, string detail, string source = null)
3433
: base(message)
35-
=> _errors.Add(new Error(statusCode, message, detail));
34+
=> _errors.Add(new Error(statusCode, message, detail, GetMeta(), source));
3635

3736
public JsonApiException(int statusCode, string message, Exception innerException)
3837
: base(message, innerException)
39-
=> _errors.Add(new Error(statusCode, message, innerException.Message));
38+
=> _errors.Add(new Error(statusCode, message, innerException.Message, GetMeta(innerException)));
4039

4140
public ErrorCollection GetError() => _errors;
4241

@@ -53,5 +52,8 @@ public int GetStatusCode()
5352

5453
return 500;
5554
}
55+
56+
private ErrorMeta GetMeta() => ErrorMeta.FromException(this);
57+
private ErrorMeta GetMeta(Exception e) => ErrorMeta.FromException(e);
5658
}
5759
}
Lines changed: 5 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,17 @@
11
using System;
2-
using System.Linq;
32

43
namespace JsonApiDotNetCore.Internal
54
{
65
public static class JsonApiExceptionFactory
76
{
8-
private const string JsonApiException = nameof(JsonApiException);
9-
private const string InvalidCastException = nameof(InvalidCastException);
10-
117
public static JsonApiException GetException(Exception exception)
128
{
13-
var exceptionType = exception.GetType().ToString().Split('.').Last();
14-
switch(exceptionType)
15-
{
16-
case JsonApiException:
17-
return (JsonApiException)exception;
18-
case InvalidCastException:
19-
return new JsonApiException(409, exception.Message);
20-
default:
21-
return new JsonApiException(500, exception.Message, GetExceptionDetail(exception.InnerException));
22-
}
23-
}
9+
var exceptionType = exception.GetType();
2410

25-
private static string GetExceptionDetail(Exception exception)
26-
{
27-
string detail = null;
28-
while(exception != null)
29-
{
30-
detail = $"{detail}{exception.Message}; ";
31-
exception = exception.InnerException;
32-
}
33-
return detail;
11+
if(exceptionType == typeof(JsonApiException))
12+
return (JsonApiException)exception;
13+
14+
return new JsonApiException(500, exceptionType.Name, exception);
3415
}
3516
}
3617
}

src/JsonApiDotNetCore/JsonApiDotNetCore.csproj

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
</PropertyGroup>
1717

1818
<ItemGroup>
19+
<PackageReference Include="Ben.Demystifier" Version="0.1.0" />
1920
<PackageReference Include="Microsoft.AspNetCore.Routing" Version="$(AspNetCoreVersion)" />
2021
<PackageReference Include="Microsoft.AspNetCore.Mvc" Version="$(AspNetCoreVersion)" />
2122
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="$(EFCoreVersion)" />
@@ -34,4 +35,4 @@
3435
<PackageReference Include="docfx.console" Version="2.33.0" />
3536
</ItemGroup>
3637

37-
</Project>
38+
</Project>

0 commit comments

Comments
 (0)