Skip to content

Commit 685814a

Browse files
committed
- Improve configuration support for Defeault Json Processing now with Enum Flags to make enabling/disabling the GraphQL Json Defaults much easier.
- Update README with info on the improved configuration support of the default Json processing features.
1 parent 1c05804 commit 685814a

File tree

6 files changed

+108
-36
lines changed

6 files changed

+108
-36
lines changed

FlurlGraphQL.Newtonsoft/FlurlGraphQL.Newtonsoft.csproj

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,9 @@
55
(because it had big issues using netstandard prior to .NET Framework 4.7) -->
66
<TargetFrameworks>net461;netstandard2.0;net6.0</TargetFrameworks>
77
<ImplicitUsings>disable</ImplicitUsings>
8-
<Version>2.0.2</Version>
9-
<AssemblyVersion>2.0.2</AssemblyVersion>
10-
<FileVersion>2.0.2</FileVersion>
8+
<Version>2.0.3</Version>
9+
<AssemblyVersion>2.0.3</AssemblyVersion>
10+
<FileVersion>2.0.3</FileVersion>
1111
<Authors>BBernard / CajunCoding</Authors>
1212
<Company>CajunCoding</Company>
1313
<Description>Newtonsoft JSON Supportt for FlurlGraphQL v2.0+ -- A GraphQL client extensions for Flurl.Http - lightweight, simplified, asynchronous, fluent GraphQL client API extensions for the amazing Flurl Http library!</Description>
@@ -18,11 +18,12 @@
1818
<RepositoryUrl>https://github.com/cajuncoding/FlurlGraphQL</RepositoryUrl>
1919
<PackageReleaseNotes>
2020
Release Notes:
21+
- Improve configuration support for Defeault Json Processing now with Enum Flags to make enabling/disabling the GraphQL Json Defaults much easier.
22+
23+
Prior Release Notes:
2124
- Improve handling of Enums so that automatic processing as SCREAMING_CASE is handled now without the need to have [EnumMember("")] attributes on every enum value when the names match.
2225
- Improve handling of GraphQL Serialization to now automatically use CamelCase for System.Text.Json &amp; Newtonsoft.Json; it was already being handled when de-serializing but not when serializing.
2326
- Added new methods to help streamline the configuration of Json Serializer options/settings; a simple action/lambda can now be used to set Json Serialization Options/Settings.
24-
25-
Prior Release Notes:
2627
- Fix issue with incorrect deserialization when using wrapper convenience class GraphQLEdge&lt;T&gt;.
2728
- Newtonsoft JSON Compatibility implementation for FlurlGraphQL v2.0 using the all new Flurl v4.0+.
2829
</PackageReleaseNotes>

FlurlGraphQL.Newtonsoft/FlurlGraphQLNewtonsoftJsonSerializer.cs

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -38,23 +38,31 @@ public static JsonSerializerSettings CreateDefaultSerializerSettings(JsonSeriali
3838
//Default Options are used as fallback...
3939
: JsonConvert.DefaultSettings?.Invoke() ?? new JsonSerializerSettings();
4040

41+
var defaultJsonConfig = FlurlGraphQLConfig.DefaultConfig;
42+
4143
//For compatibility with FlurlGraphQL v1 behavior using Newtonsoft.Json it is case-insensitive by default but does not use Camel Case.
4244
//This is also helpful since GraphQL Json (and Json in general) use CamelCase and nearly always mismatch C# Naming Pascal Case standards of C# Class Models, etc...
4345
//NOTE: WE are operating on a copy of the original Json Settings so this does NOT mutate the core/original settings from Flurl or those specified for the GraphQL request, etc.
44-
graphqlJsonSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
45-
46-
var graphqlConfig = FlurlGraphQLConfig.DefaultConfig;
46+
if (defaultJsonConfig.IsJsonProcessingFlagEnabled(JsonDefaults.EnableCamelCaseSerialization))
47+
graphqlJsonSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
4748

4849
//For compatibility with FlurlGraphQL v1 behavior (using Newtonsoft.Json) we need to provide support for String to Enum conversion along with support for enum annotations
4950
// via [EnumMember(Value ="CustomName")] annotation (compatible with Newtonsoft.Json). In addition, we now also support [Description("CustomName")] annotation for
5051
// easier syntax that is arguably more intuitive to use.
51-
//NOTE: For performance we KNOW we need ot add this if original options were not provided (e.g. null)
52-
if (originalJsonSettings is null || !originalJsonSettings.Converters.OfType<StringEnumConverter>().Any())
53-
graphqlJsonSettings.Converters.Add(
54-
graphqlConfig.EnableAutomaticHandlingOfEnumsAsScreamingCaseStrings
55-
? new StringEnumConverter(namingStrategy: new FlurlGraphQLNewtonsoftJsonScreamingCaseNamingStrategy(), allowIntegerValues: true)
56-
: new StringEnumConverter()
57-
);
52+
if (defaultJsonConfig.IsJsonProcessingFlagEnabled(JsonDefaults.EnableStringEnumHandling))
53+
{
54+
//NOTE: For performance we KNOW we need to add this if the original options were not provided (e.g. null)...
55+
if (originalJsonSettings is null || !originalJsonSettings.Converters.OfType<StringEnumConverter>().Any())
56+
{
57+
//To simplify working with GraphQL Enums (e.g. with HotChocolate .NET) the Json should use SCREAMING_CASE for the values.
58+
//You can customize/override this with [EnumMember()] attributes, but this simplifies when the names should simply match!
59+
graphqlJsonSettings.Converters.Add(
60+
defaultJsonConfig.IsJsonProcessingFlagEnabled(JsonDefaults.EnableScreamingCaseEnums)
61+
? new StringEnumConverter(namingStrategy: new FlurlGraphQLNewtonsoftJsonScreamingCaseNamingStrategy(), allowIntegerValues: true)
62+
: new StringEnumConverter()
63+
);
64+
}
65+
}
5866

5967
return graphqlJsonSettings;
6068
}

FlurlGraphQL/FlurlGraphQL.csproj

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,9 @@
44
<!--NOTE: Just as with the base Flurl.Http.Newtonsoft library and Microsofts recommendation we now support net6 for the latest projects, but also netstandard2.1 which has proper Async streaming support,
55
in addition to netstandard2.0 + net461 for legacy support (because netstandard2.0 it had API compatibility issues prior to .NET Framework 4.7.x -->
66
<TargetFrameworks>net461;netstandard2.0;netstandard2.1;net6.0;</TargetFrameworks>
7-
<Version>2.0.4</Version>
8-
<AssemblyVersion>2.0.4</AssemblyVersion>
9-
<FileVersion>2.0.4</FileVersion>
7+
<Version>2.0.5</Version>
8+
<AssemblyVersion>2.0.5</AssemblyVersion>
9+
<FileVersion>2.0.5</FileVersion>
1010
<Authors>BBernard / CajunCoding</Authors>
1111
<Company>CajunCoding</Company>
1212
<Description>GraphQL client extensions for Flurl.Http -- lightweight, simplified, asynchronous, fluent GraphQL client API extensions for the amazing Flurl Http library!</Description>
@@ -17,11 +17,12 @@
1717
<RepositoryUrl>https://github.com/cajuncoding/FlurlGraphQL</RepositoryUrl>
1818
<PackageReleaseNotes>
1919
Release Notes:
20+
- Improve configuration support for Defeault Json Processing now with Enum Flags to make enabling/disabling the GraphQL Json Defaults much easier.
21+
22+
Prior Release Notes:
2023
- Improve handling of Enums so that automatic processing as SCREAMING_CASE is handled now without the need to have [EnumMember("")] attributes on every enum value when the names match.
2124
- Improve handling of GraphQL Serialization to now automatically use CamelCase for System.Text.Json &amp; Newtonsoft.Json; it was already being handled when de-serializing but not when serializing.
2225
- Added new methods to help streamline the configuration of Json Serializer options/settings; a simple action/lambda can now be used to set Json Serialization Options/Settings.
23-
24-
Prior Release Notes:
2526
- Fix bug resulting in incorrect Exceptions when automatically enumerating (as IAsyncEnumerable) Connection Pages when a request returns with no results (NextPage = false &amp; EndCursor = null).
2627
- Fix issue with incorrect deserialization when using wrapper convenience class GraphQLEdge&lt;T&gt;.
2728
- Implement full support for Flurl v4.0+

FlurlGraphQL/FlurlGraphQL/FlurlGraphQLConfig.cs

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,26 @@
33

44
namespace FlurlGraphQL
55
{
6+
[Flags]
7+
public enum JsonDefaults
8+
{
9+
None = 0, // No settings enabled
10+
EnableStringEnumHandling = 1 << 0,
11+
EnableScreamingCaseEnums = 1 << 1,
12+
/// <summary>
13+
/// This ONLY applies to System.Text.Json. Case-insensitive matching cannot be disabled with Newtonsoft.Json.
14+
/// </summary>
15+
EnableCaseInsensitiveJsonHandling = 1 << 2,
16+
EnableCamelCaseSerialization = 1 << 3,
17+
// Combine all to simplify the Common Case!
18+
EnableAll = EnableStringEnumHandling | EnableScreamingCaseEnums | EnableCaseInsensitiveJsonHandling | EnableCamelCaseSerialization
19+
}
20+
621
public interface IFlurlGraphQLConfig
722
{
823
string PersistedQueryPayloadFieldName { get; }
9-
bool EnableAutomaticHandlingOfEnumsAsScreamingCaseStrings { get; }
24+
JsonDefaults JsonProcessingDefaults { get; }
25+
bool IsJsonProcessingFlagEnabled(JsonDefaults jsonFlag);
1026
FlurlGraphQLConfig Clone();
1127
}
1228

@@ -16,7 +32,9 @@ public sealed class FlurlGraphQLConfig : IFlurlGraphQLConfig
1632

1733
public string PersistedQueryPayloadFieldName { get; set; } = DefaultPersistedQueryFieldName;
1834

19-
public bool EnableAutomaticHandlingOfEnumsAsScreamingCaseStrings { get; set; } = true;
35+
public JsonDefaults JsonProcessingDefaults { get; set; } = JsonDefaults.EnableAll;
36+
37+
public bool IsJsonProcessingFlagEnabled(JsonDefaults jsonFlag) => JsonProcessingDefaults.HasFlag(jsonFlag);
2038

2139
public static IFlurlGraphQLConfig DefaultConfig { get; private set; } = new FlurlGraphQLConfig();
2240

@@ -27,7 +45,7 @@ private FlurlGraphQLConfig()
2745
public FlurlGraphQLConfig Clone() => new FlurlGraphQLConfig()
2846
{
2947
PersistedQueryPayloadFieldName = this.PersistedQueryPayloadFieldName,
30-
EnableAutomaticHandlingOfEnumsAsScreamingCaseStrings = this.EnableAutomaticHandlingOfEnumsAsScreamingCaseStrings
48+
JsonProcessingDefaults = this.JsonProcessingDefaults
3149
};
3250

3351
/// <summary>

FlurlGraphQL/FlurlGraphQL/JsonProcessing/FlurlGraphQLSystemTextJsonSerializer.cs

Lines changed: 18 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -33,31 +33,38 @@ public static JsonSerializerOptions CreateDefaultSerializerOptions(JsonSerialize
3333
? new JsonSerializerOptions(originalJsonOptions)
3434
: new JsonSerializerOptions();
3535

36+
37+
var defaultJsonConfig = FlurlGraphQLConfig.DefaultConfig;
38+
3639
//For compatibility with FlurlGraphQL v1 behavior (using Newtonsoft.Json) we always enable case-insensitive Field Matching with System.Text.Json.
3740
//This is also helpful since GraphQL Json (and Json in general) use CamelCase and nearly always mismatch C# Naming Pascal Case standards of C# Class Models, etc...
3841
//NOTE: WE are operating on a copy of the original Json Settings so this does NOT mutate the core/original settings from Flurl or those specified for the GraphQL request, etc.
39-
graphqlJsonOptions.PropertyNameCaseInsensitive = true;
42+
if(defaultJsonConfig.IsJsonProcessingFlagEnabled(JsonDefaults.EnableCaseInsensitiveJsonHandling))
43+
graphqlJsonOptions.PropertyNameCaseInsensitive = true;
4044

4145
//For compatibility when actually serializing we still need to enforce CamelCase (as noted above for parsing/de-serializing) because most JSON frameworks
4246
// (e.g. HotChocolate for .NET) the GraphQL json is generally expected to be in camelCase format otherwise parsing on the GraphQL Server side may fail.
4347
//This is likely a critical element missed by many developers so we enable it by default here to streamline and simplify working with GraphQL.
44-
graphqlJsonOptions.PropertyNamingPolicy = JsonNamingPolicy.CamelCase;
45-
46-
var graphqlConfig = FlurlGraphQLConfig.DefaultConfig;
48+
if (defaultJsonConfig.IsJsonProcessingFlagEnabled(JsonDefaults.EnableCamelCaseSerialization))
49+
graphqlJsonOptions.PropertyNamingPolicy = JsonNamingPolicy.CamelCase;
4750

4851
//For compatibility with FlurlGraphQL v1 behavior (using Newtonsoft.Json) we need to provide support for String to Enum conversion along with support for enum annotations
4952
// via [EnumMember(Value ="CustomName")] annotation (compatible with Newtonsoft.Json). In addition, we now also support [Description("CustomName")] annotation for
5053
// easier syntax that is arguably more intuitive to use.
51-
//NOTE: For performance we KNOW we need ot add this if original options were not provided (e.g. null)
52-
if (originalJsonOptions is null || !originalJsonOptions.Converters.OfType<JsonStringEnumMemberConverter>().Any())
53-
graphqlJsonOptions.Converters.Add(new JsonStringEnumMemberConverter(
54+
if (defaultJsonConfig.IsJsonProcessingFlagEnabled(JsonDefaults.EnableStringEnumHandling))
55+
{
56+
//NOTE: For performance we KNOW we need to add this if the original options were not provided (e.g. null)...
57+
if (originalJsonOptions is null || !originalJsonOptions.Converters.OfType<JsonStringEnumMemberConverter>().Any())
58+
{
5459
//To simplify working with GraphQL Enums (e.g. with HotChocolate .NET) the Json should use SCREAMING_CASE for the values.
5560
//You can customize/override this with [EnumMember()] attributes, but this simplifies when the names should simply match!
56-
namingPolicy: graphqlConfig.EnableAutomaticHandlingOfEnumsAsScreamingCaseStrings
61+
var namingPolicy = defaultJsonConfig.IsJsonProcessingFlagEnabled(JsonDefaults.EnableScreamingCaseEnums)
5762
? new FlurlGraphQLSystemTextJsonScreamingCaseNamingPolicy()
58-
: null,
59-
allowIntegerValues: true
60-
));
63+
: null;
64+
65+
graphqlJsonOptions.Converters.Add(new JsonStringEnumMemberConverter(namingPolicy, allowIntegerValues: true));
66+
}
67+
}
6168

6269
return graphqlJsonOptions;
6370
}

README.md

Lines changed: 39 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,20 @@ To use this in your project, add the [FlurlGraphQL](https://www.nuget.org/packag
120120
To use this in your project with `Newtonsoft.Json` processing then add the add the [FlurlGraphQL.Newtonsoft](https://www.nuget.org/packages/FlurlGraphQL.Newtonsoft/) NuGet package to your project.
121121

122122
## Release Notes:
123+
### v2.0.5
124+
- Improve configuration support for Defeault Json Processing now with Enum Flags to make enabling/disabling the GraphQL Json Defaults much easier.
125+
126+
### v2.0.4
127+
- Improve handling of Enums so that automatic processing as SCREAMING_CASE is handled now without the need to have [EnumMember("")] attributes on every enum value when the names match.
128+
- Improve handling of GraphQL Serialization to now automatically use CamelCase for System.Text.Json &amp; Newtonsoft.Json; it was already being handled when de-serializing but not when serializing.
129+
- Added new methods to help streamline the configuration of Json Serializer options/settings; a simple action/lambda can now be used to set Json Serialization Options/Settings.
130+
131+
### v.2.0.3
132+
- Fix bug resulting in incorrect Exceptions when automatically enumerating (as IAsyncEnumerable) Connection Pages when a request returns with no results (NextPage = false &amp; EndCursor = null).
133+
134+
### v2.0.2
135+
- Fix issue with incorrect deserialization when using wrapper convenience class GraphQLEdge&lt;T&gt;.
136+
123137
### v2.0.1
124138
- Fix issue with incorrect deserialization when using wrapper convenience class GraphQLEdge&lt;T&gt;
125139

@@ -649,17 +663,39 @@ catch(FlurlGraphQLException graphqlException)
649663
```
650664

651665
## Need direct control over the Json Serialization Settings?
652-
Now with version 2.0 we dynamically inherit and implement all the settings from the base/core Flurl request!
666+
Now with version 2.0 we dynamically inherit and implement all the settings from the base/core Flurl request!
667+
In general, there is no need to explicitly set the settings for only GraphQL requests anymore, however you may continue to do so.
668+
669+
NOTE: However to streamlinea and simplify the most common Json serialization issues we still enforce some Json processing defaults via
670+
the `JsonDefaults` enum flags that can be set on the default configuration using the `JsonProcessingDefaults` property:
671+
- `EnableStringEnumHandling` -- Ensures that Enum String conversion is automatically handled as GraphQL uses sring enum values.
672+
- `EnableScreamingCaseEnums` -- Ensures that Enum strings are automatically converted to SCREAMING_CASE as is the default for GraphQL enums (e.g. HotChocolate GraphQL Server).
673+
- This has no effect if the above `EnableStringEnumHandling` is disabled; unless you manually implement the screaming case naming policies/strategy (e.g. `FlurlGraphQLSystemTextJsonScreamingCaseNamingPolicy`).
674+
- `EnableCamelCaseSerialization` -- Ensures that the Json serialization is compatible with GraphQL JSON conventions which use camelCase and are usually case sensitive (e.g. HotChocolate GraphQL Server).
675+
- `EnableCaseInsensitiveJsonHandling` -- Ensures that Json de-serialziation is not case sensitive because C# conventions for `PascalCase` will nearly always fail due to JSON conventions for `camelCase`.
676+
- NOTE: This *ONLY* applies to `System.Text.Json` because case-insensitive matching cannot be disabled with `Newtonsoft.Json`.
677+
- `EnableAll` -- a convenience flag used by default to ensure all of the above are enabled to greatly simplify the common pitfalls for Json handlingw between C# & GraphQL.
653678

654-
Therefore there is no need to explicitly set the settings for only GraphQL requests anymore, however you may continue to do so.
655679

656680
We still provide support to manually control the Json serializer settings specifically for individual GraphQL request processing.
657681

658682
*NOTE: These settings will impact both how the initial query paylaod is serialized before being sent to the GraphQL server
659683
and how the response is parsed when being de-serailized back into your model.*
660684

661685
```csharp
686+
//Control how default Json Options/Settings are initialzied (for either System.Text.Json or Newtonsoft)
687+
//NOTE: If Enabled, these global GraphQL Defaults will be enforced on any settings specified, even at the Request level.
688+
FlurlGraphQLConfig.ConfigureDefaults(config =>
689+
{
690+
config.JsonProcessingDefaults = JsonDefaults.EnableAll;
691+
//Or Disable all default value enforcement so the system will use the Json Settings exactly as you specify in Flurl (or in Newtonsoft default configuration)
692+
config.JsonProssingDefaults = JsonDefaults.None;
693+
//Or some custom combination: this will remove Case-insensitivity, and CamelCase serialization....
694+
config.JsonProssingDefaults = JsonDefaults.EnableStringEnumHandling | EnableScreamingCaseEnums;
695+
});
696+
662697
//Override the Json Serialization Settings per request...
698+
//NOTE: The above Defaults will be enforced on any settings you specify if enabled in the FlurlGraphQLConfig...
663699
var json = await "https://graphql-star-wars.azurewebsites.net/api/graphql"
664700
.WithGraphQLQuery("...")
665701
.UseGraphQLSystemTextJson(new JsonSerializerOptions() //<== System.Text.Json Options!
@@ -677,6 +713,7 @@ and how the response is parsed when being de-serailized back into your model.*
677713
.ReceiveGraphQLRawSystemTextJsonResponse();
678714

679715
//OR for Newtonsoft.Json then you need to use the following for each request...
716+
//NOTE: The above Defaults will be enforced on any settings you specify if enabled in the FlurlGraphQLConfig...
680717
var json = await "https://graphql-star-wars.azurewebsites.net/api/graphql"
681718
.WithGraphQLQuery("...")
682719
.UseGraphQLNewtonsoftJson(new JsonSerializerSettings() //<== Newtonsof.Json Settings!

0 commit comments

Comments
 (0)