Skip to content

Commit 97abafd

Browse files
committed
Fix issues in Error Handling not identifying GraphQL Server errors correctly in all cases, and therefore not propagating the full details returned by the Server. We now check all response contents (if available) if it looks like Json and then interrogate it for the existence of an errors property and parse all details if possible. Also fixed issue not processing the error path variables correctly (int vs long return values); we now handle all possible numeric types.
1 parent df3cae6 commit 97abafd

File tree

4 files changed

+39
-23
lines changed

4 files changed

+39
-23
lines changed

FlurlGraphQL.Querying/Flurl/FlurlGraphQLException.cs

Lines changed: 26 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using System;
22
using System.Collections.Generic;
3+
using System.Diagnostics;
34
using System.Linq;
45
using System.Net;
56
using System.Text;
@@ -11,13 +12,17 @@ public class FlurlGraphQLException : Exception
1112
{
1213
private readonly string _errorMessage = null;
1314

14-
public FlurlGraphQLException(string message, string graphqlQuery, object graphQLResponsePayload = null, HttpStatusCode httpStatusCode = HttpStatusCode.BadRequest, Exception innerException = null)
15-
: base(message, innerException)
15+
public FlurlGraphQLException(
16+
string message,
17+
string graphqlQuery,
18+
object graphQLResponsePayload = null,
19+
HttpStatusCode httpStatusCode = HttpStatusCode.BadRequest,
20+
Exception innerException = null
21+
) : base(message, innerException)
1622
{
1723
Query = graphqlQuery;
1824
HttpStatusCode = httpStatusCode;
1925

20-
//TODO: Verify if string is the optimal way to handle this vs Json JObject, etc.
2126
switch (graphQLResponsePayload)
2227
{
2328
case string jsonString: ErrorResponseContent = jsonString; break;
@@ -27,13 +32,18 @@ public FlurlGraphQLException(string message, string graphqlQuery, object graphQL
2732

2833
//Because this may be a result from a non-200-OK request response we attempt to inspect the response payload and possibly parse out
2934
// error details that may be available in the Error Response Content (but not already parsed and available (e.g. when GraphQL responds with 400-BadRequest).
30-
GraphQLErrors = ParseGraphQLErrorsFromPayload(ErrorResponseContent);
35+
GraphQLErrors = ParseGraphQLErrorsFromPayloadSafely(ErrorResponseContent);
3136

3237
_errorMessage = BuildErrorMessage(message, GraphQLErrors, innerException);
3338
}
3439

35-
public FlurlGraphQLException(IReadOnlyList<GraphQLError> graphqlErrors, string graphqlQuery, string graphqlResponsePayloadContent = null, HttpStatusCode httpStatusCode = HttpStatusCode.BadRequest, Exception innerException = null)
36-
: base(string.Empty, innerException)
40+
public FlurlGraphQLException(
41+
IReadOnlyList<GraphQLError> graphqlErrors,
42+
string graphqlQuery,
43+
string graphqlResponsePayloadContent = null,
44+
HttpStatusCode httpStatusCode = HttpStatusCode.BadRequest,
45+
Exception innerException = null
46+
) : base(string.Empty, innerException)
3747
{
3848
GraphQLErrors = graphqlErrors;
3949
Query = graphqlQuery;
@@ -62,7 +72,7 @@ protected string GetMessageInternal()
6272
: _errorMessage;
6373
}
6474

65-
protected static IReadOnlyList<GraphQLError> ParseGraphQLErrorsFromPayload(string errorResponseContent)
75+
protected static IReadOnlyList<GraphQLError> ParseGraphQLErrorsFromPayloadSafely(string errorResponseContent)
6676
{
6777
if (errorResponseContent.TryParseJObject(out var errorJson))
6878
{
@@ -83,8 +93,8 @@ protected static string BuildErrorMessage(string message, IReadOnlyList<GraphQLE
8393

8494
var errorMessages = graphqlErrors.Select(e =>
8595
{
86-
var locations = string.Join("; ", e.Locations.Select(l => $"At={l.Line},{l.Column}"));
87-
var locationText = !string.IsNullOrEmpty(locations) ? $" [{locations}]" : null;
96+
var concatenatedLocations = string.Join("; ", e.Locations?.Select(l => $"At={l.Line},{l.Column}") ?? Enumerable.Empty<string>());
97+
var locationText = !string.IsNullOrEmpty(concatenatedLocations) ? $" [{concatenatedLocations}]" : null;
8898

8999
var path = BuildGraphQLPath(e);
90100
var pathText = path != null ? $" [For={path}]" : null;
@@ -112,9 +122,9 @@ protected static string BuildGraphQLPath(GraphQLError graphqlError)
112122
bool isFirst = true;
113123
foreach (var p in graphqlError.Path)
114124
{
115-
if (p is int pathIndex)
125+
if (IsNumeric(p))
116126
{
117-
stringBuilder.Append("[").Append(pathIndex).Append("]");
127+
stringBuilder.Append("[").Append(p).Append("]");
118128
}
119129
else if (p is string pathString)
120130
{
@@ -127,5 +137,10 @@ protected static string BuildGraphQLPath(GraphQLError graphqlError)
127137

128138
return stringBuilder.ToString();
129139
}
140+
141+
protected static bool IsNumeric(object obj) =>
142+
obj is sbyte || obj is byte || obj is short || obj is ushort
143+
|| obj is int || obj is uint || obj is long || obj is ulong
144+
|| obj is float || obj is double || obj is decimal;
130145
}
131146
}

FlurlGraphQL.Querying/Flurl/FlurlGraphQLRequest.cs

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -356,17 +356,18 @@ protected async Task<FlurlGraphQLResponse> ExecuteRequestWithExceptionHandling(F
356356
}
357357
catch (FlurlHttpException httpException)
358358
{
359-
var httpStatusCode = (HttpStatusCode?)httpException?.StatusCode;
359+
var responseHttpStatusCode = (HttpStatusCode?)httpException?.StatusCode;
360360
var errorContent = await httpException.GetResponseStringSafelyAsync().ConfigureAwait(false);
361361

362-
if (httpStatusCode is HttpStatusCode.BadRequest)
363-
throw new FlurlGraphQLException(
364-
$"[{(int)HttpStatusCode.BadRequest}-{HttpStatusCode.BadRequest}] The GraphQL server returned a bad request response for the query."
365-
+ " This is likely caused by a malformed, or non-parsable query; validate the query syntax, operation name, arguments, etc."
366-
+ " to ensure that the query is valid.", this.GraphQLQuery, errorContent, httpStatusCode.Value, httpException
367-
);
368-
else
362+
if (!errorContent.IsDuckTypedJson())
369363
throw;
364+
365+
var httpStatusCode = responseHttpStatusCode ?? HttpStatusCode.BadRequest;
366+
throw new FlurlGraphQLException(
367+
$"[{(int)httpStatusCode}-{httpStatusCode}] The GraphQL server returned an error response for the query."
368+
+ " This is likely caused by a malformed/non-parsable query, or a Schema validation issue; please validate the query syntax, operation name, and arguments"
369+
+ " to ensure that the query is valid.", this.GraphQLQuery, errorContent, httpStatusCode, httpException
370+
);
370371
}
371372
}
372373

FlurlGraphQL.Querying/FlurlGraphQL.Querying.csproj

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@
22

33
<PropertyGroup>
44
<TargetFrameworks>netstandard2.0;netstandard2.1</TargetFrameworks>
5-
<Version>1.3.1</Version>
6-
<AssemblyVersion>1.3.1</AssemblyVersion>
7-
<FileVersion>1.3.1</FileVersion>
5+
<Version>1.3.2</Version>
6+
<AssemblyVersion>1.3.2</AssemblyVersion>
7+
<FileVersion>1.3.2</FileVersion>
88
<Authors>BBernard / CajunCoding</Authors>
99
<Company>CajunCoding</Company>
1010
<Description>GraphQL client extensions for Flurl.Http -- lightweight, simplified, asynchronous, fluent GraphQL client API extensions for the amazing Flurl Http library!</Description>

FlurlGraphQL.Querying/NewtonsoftJson/NewtonsoftJsonExtensions.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ namespace FlurlGraphQL.Querying
77
{
88
internal static class NewtonsoftJsonExtensions
99
{
10-
public static bool TryParseJObject(this string jsonText, out JToken json)
10+
public static bool TryParseJObject(this string jsonText, out JObject json)
1111
{
1212
try
1313
{

0 commit comments

Comments
 (0)