diff --git a/src/HotChocolate/AspNetCore/src/AspNetCore/Extensions/HotChocolateAspNetCoreServiceCollectionExtensions.Http.cs b/src/HotChocolate/AspNetCore/src/AspNetCore/Extensions/HotChocolateAspNetCoreServiceCollectionExtensions.Http.cs
index 36711cf8aeb..d1db7111f30 100644
--- a/src/HotChocolate/AspNetCore/src/AspNetCore/Extensions/HotChocolateAspNetCoreServiceCollectionExtensions.Http.cs
+++ b/src/HotChocolate/AspNetCore/src/AspNetCore/Extensions/HotChocolateAspNetCoreServiceCollectionExtensions.Http.cs
@@ -3,7 +3,6 @@
using HotChocolate.AspNetCore;
using HotChocolate.AspNetCore.Serialization;
using HotChocolate.Execution.Configuration;
-using HotChocolate.Execution.Serialization;
using HotChocolate.Utilities;
// ReSharper disable once CheckNamespace
@@ -114,14 +113,14 @@ public static partial class HotChocolateAspNetCoreServiceCollectionExtensions
/// The .
///
///
- /// The JSON result formatter options
+ /// The HTTP response formatter options
///
///
/// Returns the so that configuration can be chained.
///
public static IServiceCollection AddHttpResponseFormatter(
this IServiceCollection services,
- JsonResultFormatterOptions options)
+ HttpResponseFormatterOptions options)
{
services.RemoveAll();
services.AddSingleton(new DefaultHttpResponseFormatter(options));
diff --git a/src/HotChocolate/AspNetCore/src/AspNetCore/HttpTransportVersion.cs b/src/HotChocolate/AspNetCore/src/AspNetCore/HttpTransportVersion.cs
new file mode 100644
index 00000000000..ee38bf3aebe
--- /dev/null
+++ b/src/HotChocolate/AspNetCore/src/AspNetCore/HttpTransportVersion.cs
@@ -0,0 +1,22 @@
+namespace HotChocolate.AspNetCore;
+
+///
+/// Represents the GraphQL over HTTP transport version.
+///
+public enum HttpTransportVersion
+{
+ ///
+ /// Represents the latest released transport specification.
+ ///
+ Latest = 0,
+
+ ///
+ /// Represents the legacy specification version which will be cut off at 2025-01-01T00:00:00Z.
+ ///
+ Legacy = 1,
+
+ ///
+ /// Represents the GraphQL over HTTP spec version with the commit on 2023-01-27.
+ ///
+ Draft20230127 = 2
+}
diff --git a/src/HotChocolate/AspNetCore/src/AspNetCore/Serialization/DefaultHttpResponseFormatter.cs b/src/HotChocolate/AspNetCore/src/AspNetCore/Serialization/DefaultHttpResponseFormatter.cs
index 0188ad4dbc1..52c371f389a 100644
--- a/src/HotChocolate/AspNetCore/src/AspNetCore/Serialization/DefaultHttpResponseFormatter.cs
+++ b/src/HotChocolate/AspNetCore/src/AspNetCore/Serialization/DefaultHttpResponseFormatter.cs
@@ -1,4 +1,3 @@
-using System.Net;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Text.Encodings.Web;
@@ -22,9 +21,12 @@ namespace HotChocolate.AspNetCore.Serialization;
///
public class DefaultHttpResponseFormatter : IHttpResponseFormatter
{
- private readonly JsonResultFormatter _jsonFormatter;
- private readonly MultiPartResultFormatter _multiPartFormatter;
- private readonly EventStreamResultFormatter _eventStreamResultFormatter;
+ private readonly FormatInfo _defaultFormat;
+ private readonly FormatInfo _graphqlResponseFormat;
+ private readonly FormatInfo _multiPartFormat;
+ private readonly FormatInfo _eventStreamFormat;
+ private readonly FormatInfo _legacyFormat;
+
///
/// Creates a new instance of .
@@ -42,9 +44,16 @@ public class DefaultHttpResponseFormatter : IHttpResponseFormatter
public DefaultHttpResponseFormatter(
bool indented = false,
JavaScriptEncoder? encoder = null)
- : this(new JsonResultFormatterOptions { Indented = indented, Encoder = encoder })
- {
- }
+ : this(
+ new HttpResponseFormatterOptions
+ {
+ Json = new JsonResultFormatterOptions
+ {
+ Indented = indented,
+ Encoder = encoder
+ }
+ })
+ { }
///
/// Creates a new instance of .
@@ -52,11 +61,31 @@ public class DefaultHttpResponseFormatter : IHttpResponseFormatter
///
/// The JSON result formatter options
///
- public DefaultHttpResponseFormatter(JsonResultFormatterOptions options)
+ public DefaultHttpResponseFormatter(HttpResponseFormatterOptions options)
{
- _jsonFormatter = new JsonResultFormatter(options);
- _multiPartFormatter = new MultiPartResultFormatter(_jsonFormatter);
- _eventStreamResultFormatter = new EventStreamResultFormatter(options);
+ var jsonFormatter = new JsonResultFormatter(options.Json);
+ var multiPartFormatter = new MultiPartResultFormatter(jsonFormatter);
+ var eventStreamResultFormatter = new EventStreamResultFormatter(options.Json);
+
+ _graphqlResponseFormat = new FormatInfo(
+ ContentType.GraphQLResponse,
+ ResponseContentType.GraphQLResponse,
+ jsonFormatter);
+ _legacyFormat = new FormatInfo(
+ ContentType.Json,
+ ResponseContentType.Json,
+ jsonFormatter);
+ _multiPartFormat = new FormatInfo(
+ ContentType.MultiPartMixed,
+ ResponseContentType.MultiPartMixed,
+ multiPartFormatter);
+ _eventStreamFormat = new FormatInfo(
+ ContentType.EventStream,
+ ResponseContentType.EventStream,
+ eventStreamResultFormatter);
+ _defaultFormat = options.HttpTransportVersion is HttpTransportVersion.Legacy
+ ? _legacyFormat
+ : _graphqlResponseFormat;
}
public GraphQLRequestFlags CreateRequestFlags(
@@ -119,7 +148,9 @@ public DefaultHttpResponseFormatter(JsonResultFormatterOptions options)
HttpStatusCode? proposedStatusCode,
CancellationToken cancellationToken)
{
- if (!TryGetFormatter(result, acceptMediaTypes, out var format))
+ var format = TryGetFormatter(result, acceptMediaTypes);
+
+ if (format is null)
{
// we should not hit this point except if a middleware did not validate the
// GraphQL request flags which would indicate that there is no way to execute
@@ -276,46 +307,33 @@ public DefaultHttpResponseFormatter(JsonResultFormatterOptions options)
throw ThrowHelper.Formatter_ResponseContentTypeNotSupported(format.ContentType);
}
- private bool TryGetFormatter(
+ private FormatInfo? TryGetFormatter(
IExecutionResult result,
- AcceptMediaType[] acceptMediaTypes,
- out FormatInfo formatInfo)
+ AcceptMediaType[] acceptMediaTypes)
{
- formatInfo = default;
+ var length = acceptMediaTypes.Length;
// if the request does not specify the accept header then we will
// use the `application/graphql-response+json` response content-type,
// which is the new response content-type.
- if (acceptMediaTypes.Length == 0)
+ if (length == 0)
{
if (result.Kind is SingleResult)
{
- formatInfo = new FormatInfo(
- ContentType.GraphQLResponse,
- ResponseContentType.GraphQLResponse,
- _jsonFormatter);
- return true;
+ return _defaultFormat;
}
if (result.Kind is DeferredResult or BatchResult)
{
- formatInfo = new FormatInfo(
- ContentType.MultiPartMixed,
- ResponseContentType.MultiPartMixed,
- _multiPartFormatter);
- return true;
+ return _multiPartFormat;
}
if (result.Kind is SubscriptionResult)
{
- formatInfo = new FormatInfo(
- ContentType.EventStream,
- ResponseContentType.EventStream,
- _eventStreamResultFormatter);
- return true;
+ return _eventStreamFormat;
}
- return false;
+ return null;
}
// if the request specifies at least one accept media-type we will
@@ -328,150 +346,112 @@ public DefaultHttpResponseFormatter(JsonResultFormatterOptions options)
_ => ResultKind.Stream
};
+ ref var start = ref MemoryMarshal.GetArrayDataReference(acceptMediaTypes);
+
// if we just have one accept header we will try to determine which formatter to take.
// we should only be unable to find a match if there was a previous validation skipped.
- if (acceptMediaTypes.Length == 1)
+ if (length == 1)
{
- var mediaType = acceptMediaTypes[0];
+ var mediaType = start;
if (resultKind is ResultKind.Single &&
mediaType.Kind is ApplicationGraphQL or AllApplication or All)
{
- formatInfo = new FormatInfo(
- ContentType.GraphQLResponse,
- ResponseContentType.GraphQLResponse,
- _jsonFormatter);
- return true;
+ return _graphqlResponseFormat;
}
if (resultKind is ResultKind.Single &&
mediaType.Kind is ApplicationJson)
{
- formatInfo = new FormatInfo(
- ContentType.Json,
- ResponseContentType.Json,
- _jsonFormatter);
- return true;
+ return _legacyFormat;
}
if (resultKind is ResultKind.Stream or ResultKind.Single &&
mediaType.Kind is MultiPartMixed or AllMultiPart or All)
{
- formatInfo = new FormatInfo(
- ContentType.MultiPartMixed,
- ResponseContentType.MultiPartMixed,
- _multiPartFormatter);
- return true;
+ return _multiPartFormat;
}
if (mediaType.Kind is EventStream)
{
- formatInfo = new FormatInfo(
- ContentType.EventStream,
- ResponseContentType.EventStream,
- _eventStreamResultFormatter);
- return true;
+ return _eventStreamFormat;
}
- return false;
+ return null;
}
// if we have more than one specified accept media-type we will try to find the best for
// our GraphQL result.
- ref var searchSpace = ref MemoryMarshal.GetReference(acceptMediaTypes.AsSpan());
- var success = false;
+ ref var end = ref Unsafe.Add(ref start, length);
+ FormatInfo? possibleFormat = null;
- for (var i = 0; i < acceptMediaTypes.Length; i++)
+ while (Unsafe.IsAddressLessThan(ref start, ref end))
{
- var mediaType = Unsafe.Add(ref searchSpace, i);
-
if (resultKind is ResultKind.Single &&
- mediaType.Kind is ApplicationGraphQL or AllApplication or All)
+ start.Kind is ApplicationGraphQL or AllApplication or All)
{
- formatInfo = new FormatInfo(
- ContentType.GraphQLResponse,
- ResponseContentType.GraphQLResponse,
- _jsonFormatter);
- return true;
+ return _graphqlResponseFormat;
}
if (resultKind is ResultKind.Single &&
- mediaType.Kind is ApplicationJson)
+ start.Kind is ApplicationJson)
{
// application/json is a legacy response content-type.
// We will create a formatInfo but keep on validating for
// a better suited format.
- formatInfo = new FormatInfo(
- ContentType.Json,
- ResponseContentType.Json,
- _jsonFormatter);
- success = true;
+ possibleFormat = _legacyFormat;
}
if (resultKind is ResultKind.Stream or ResultKind.Single &&
- mediaType.Kind is MultiPartMixed or AllMultiPart or All)
+ start.Kind is MultiPartMixed or AllMultiPart or All)
{
// if the result is a stream we consider this a perfect match and
// will use this format.
if (resultKind is ResultKind.Stream)
{
- formatInfo = new FormatInfo(
- ContentType.MultiPartMixed,
- ResponseContentType.MultiPartMixed,
- _multiPartFormatter);
- return true;
+ possibleFormat = _multiPartFormat;
}
// if the format is a event-stream or not set we will create a
// multipart/mixed formatInfo for the current result but also keep
// on validating for a better suited format.
- if (formatInfo.Kind is not ResponseContentType.Json)
+ if (possibleFormat?.Kind is not ResponseContentType.Json)
{
- formatInfo = new FormatInfo(
- ContentType.MultiPartMixed,
- ResponseContentType.MultiPartMixed,
- _multiPartFormatter);
- success = true;
+ possibleFormat = _multiPartFormat;
}
}
- if (mediaType.Kind is EventStream or All)
+ if (start.Kind is EventStream or All)
{
// if the result is a subscription we consider this a perfect match and
// will use this format.
if (resultKind is ResultKind.Stream)
{
- formatInfo = new FormatInfo(
- ContentType.EventStream,
- ResponseContentType.EventStream,
- _eventStreamResultFormatter);
- return true;
+ possibleFormat = _eventStreamFormat;
}
- // if the result is stream it means that we did not yet validated a
+ // if the result is stream it means that we did not yet validate a
// multipart content-type and thus will create a format for the case that it
// is not specified;
// or we have a single result but there is no format yet specified
// we will create a text/event-stream formatInfo for the current result
// but also keep on validating for a better suited format.
- if (formatInfo.Kind is ResponseContentType.Unknown)
+ if (possibleFormat?.Kind is ResponseContentType.Unknown)
{
- formatInfo = new FormatInfo(
- ContentType.MultiPartMixed,
- ResponseContentType.MultiPartMixed,
- _multiPartFormatter);
- success = true;
+ possibleFormat = _multiPartFormat;
}
}
+
+ start = ref Unsafe.Add(ref start, 1);
}
- return success;
+ return possibleFormat;
}
///
/// Representation of a resolver format, containing the formatter and the content type.
///
- protected readonly struct FormatInfo
+ protected sealed class FormatInfo
{
///
/// Initializes a new instance of .
diff --git a/src/HotChocolate/AspNetCore/src/AspNetCore/Serialization/HttpResponseFormatterOptions.cs b/src/HotChocolate/AspNetCore/src/AspNetCore/Serialization/HttpResponseFormatterOptions.cs
new file mode 100644
index 00000000000..4e3190fa79b
--- /dev/null
+++ b/src/HotChocolate/AspNetCore/src/AspNetCore/Serialization/HttpResponseFormatterOptions.cs
@@ -0,0 +1,19 @@
+using HotChocolate.Execution.Serialization;
+
+namespace HotChocolate.AspNetCore.Serialization;
+
+///
+/// Represents the GraphQL over HTTP formatter options.
+///
+public struct HttpResponseFormatterOptions
+{
+ ///
+ /// Gets or sets the GraphQL over HTTP transport version.
+ ///
+ public HttpTransportVersion HttpTransportVersion { get; set; }
+
+ ///
+ /// Gets or sets the JSON result formatter options.
+ ///
+ public JsonResultFormatterOptions Json { get; set; }
+}
diff --git a/src/HotChocolate/AspNetCore/test/AspNetCore.Tests/GraphQLOverHttpSpecTests.cs b/src/HotChocolate/AspNetCore/test/AspNetCore.Tests/GraphQLOverHttpSpecTests.cs
index 1b5bbba27c4..f7200d7655b 100644
--- a/src/HotChocolate/AspNetCore/test/AspNetCore.Tests/GraphQLOverHttpSpecTests.cs
+++ b/src/HotChocolate/AspNetCore/test/AspNetCore.Tests/GraphQLOverHttpSpecTests.cs
@@ -1,7 +1,9 @@
#if NET6_0_OR_GREATER
using System.Net.Http.Json;
using CookieCrumble;
+using HotChocolate.AspNetCore.Serialization;
using HotChocolate.AspNetCore.Tests.Utilities;
+using Microsoft.Extensions.DependencyInjection;
using static System.Net.Http.HttpCompletionOption;
namespace HotChocolate.AspNetCore;
@@ -11,13 +13,11 @@ public class GraphQLOverHttpSpecTests : ServerTestBase
private static readonly Uri _url = new("http://localhost:5000/graphql");
public GraphQLOverHttpSpecTests(TestServerFactory serverFactory)
- : base(serverFactory)
- {
- }
+ : base(serverFactory) { }
///
/// This request does not specify a accept header.
- /// expected response content-type: application/json
+ /// expected response content-type: graphql-response+json
/// expected status code: 200
///
[Fact]
@@ -31,10 +31,7 @@ public async Task Legacy_Query_No_Streams_1()
using var request = new HttpRequestMessage(HttpMethod.Post, _url)
{
Content = JsonContent.Create(
- new ClientQueryRequest
- {
- Query = "{ __typename }"
- })
+ new ClientQueryRequest { Query = "{ __typename }" })
};
using var response = await client.SendAsync(request);
@@ -54,42 +51,83 @@ public async Task Legacy_Query_No_Streams_1()
{""data"":{""__typename"":""Query""}}");
}
- ///
- /// This request does not specify a accept header.
- /// expected response content-type: application/json
- /// expected status code: 200
- ///
- [Fact]
- public async Task Query_No_Body()
+ ///
+ /// This request does not specify a accept header and spec is set to legacy.
+ /// expected response content-type: graphql-response+json
+ /// expected status code: 200
+ ///
+ [Fact]
+ public async Task Legacy_Query_No_Streams_Legacy_Response()
+ {
+ // arrange
+ var server = CreateStarWarsServer(
+ configureServices: s => s.AddHttpResponseFormatter(
+ new HttpResponseFormatterOptions
+ {
+ HttpTransportVersion = HttpTransportVersion.Legacy
+ }));
+ var client = server.CreateClient();
+
+ // act
+ using var request = new HttpRequestMessage(HttpMethod.Post, _url)
{
- // arrange
- var server = CreateStarWarsServer();
- var client = server.CreateClient();
+ Content = JsonContent.Create(
+ new ClientQueryRequest { Query = "{ __typename }" })
+ };
+
+ using var response = await client.SendAsync(request);
+
+ // assert
+ // expected response content-type: application/json
+ // expected status code: 200
+ Snapshot
+ .Create()
+ .Add(response)
+ .MatchInline(
+ @"Headers:
+ Content-Type: application/json; charset=utf-8
+ -------------------------->
+ Status Code: OK
+ -------------------------->
+ {""data"":{""__typename"":""Query""}}");
+ }
+
+ ///
+ /// This request does not specify a accept header.
+ /// expected response content-type: application/json
+ /// expected status code: 200
+ ///
+ [Fact]
+ public async Task Query_No_Body()
+ {
+ // arrange
+ var server = CreateStarWarsServer();
+ var client = server.CreateClient();
- // act
- using var request = new HttpRequestMessage(HttpMethod.Post, _url)
+ // act
+ using var request = new HttpRequestMessage(HttpMethod.Post, _url)
+ {
+ Content = new ByteArrayContent(Array.Empty())
{
- Content = new ByteArrayContent(Array.Empty())
- {
- Headers = { ContentType = new("application/json") { CharSet = "utf-8" } }
- }
- };
- using var response = await client.SendAsync(request);
-
- // assert
- // expected response content-type: application/json
- // expected status code: 200
- Snapshot
- .Create()
- .Add(response)
- .MatchInline(
- @"Headers:
+ Headers = { ContentType = new("application/json") { CharSet = "utf-8" } }
+ }
+ };
+ using var response = await client.SendAsync(request);
+
+ // assert
+ // expected response content-type: application/json
+ // expected status code: 200
+ Snapshot
+ .Create()
+ .Add(response)
+ .MatchInline(
+ @"Headers:
Content-Type: application/graphql-response+json; charset=utf-8
-------------------------->
Status Code: BadRequest
-------------------------->
{""errors"":[{""message"":""The GraphQL request is empty."",""extensions"":{""code"":""HC0012""}}]}");
- }
+ }
///
/// This request does not specify a accept header and has a syntax error.
@@ -107,10 +145,7 @@ public async Task Legacy_Query_No_Streams_2()
using var request = new HttpRequestMessage(HttpMethod.Post, _url)
{
Content = JsonContent.Create(
- new ClientQueryRequest
- {
- Query = "{ __typ$ename }"
- })
+ new ClientQueryRequest { Query = "{ __typ$ename }" })
};
using var response = await client.SendAsync(request);
@@ -148,10 +183,7 @@ public async Task Legacy_Query_No_Streams_3()
using var request = new HttpRequestMessage(HttpMethod.Post, _url)
{
Content = JsonContent.Create(
- new ClientQueryRequest
- {
- Query = "{ __type name }"
- })
+ new ClientQueryRequest { Query = "{ __type name }" })
};
using var response = await client.SendAsync(request);
@@ -202,10 +234,7 @@ public async Task Legacy_With_Stream_1()
using var request = new HttpRequestMessage(HttpMethod.Post, _url)
{
Content = JsonContent.Create(
- new ClientQueryRequest
- {
- Query = "{ ... @defer { __typename } }"
- })
+ new ClientQueryRequest { Query = "{ ... @defer { __typename } }" })
};
using var response = await client.SendAsync(request);
@@ -253,14 +282,8 @@ public async Task New_Query_No_Streams_1()
using var request = new HttpRequestMessage(HttpMethod.Post, _url)
{
Content = JsonContent.Create(
- new ClientQueryRequest
- {
- Query = "{ __typename }"
- }),
- Headers =
- {
- { "Accept", ContentType.GraphQLResponse }
- }
+ new ClientQueryRequest { Query = "{ __typename }" }),
+ Headers = { { "Accept", ContentType.GraphQLResponse } }
};
using var response = await client.SendAsync(request);
@@ -296,14 +319,8 @@ public async Task New_Query_No_Streams_2()
using var request = new HttpRequestMessage(HttpMethod.Post, _url)
{
Content = JsonContent.Create(
- new ClientQueryRequest
- {
- Query = "{ __typename }"
- }),
- Headers =
- {
- { "Accept", ContentType.Json }
- }
+ new ClientQueryRequest { Query = "{ __typename }" }),
+ Headers = { { "Accept", ContentType.Json } }
};
using var response = await client.SendAsync(request);
@@ -339,10 +356,7 @@ public async Task New_Query_No_Streams_3()
using var request = new HttpRequestMessage(HttpMethod.Post, _url)
{
Content = JsonContent.Create(
- new ClientQueryRequest
- {
- Query = "{ __typename }"
- }),
+ new ClientQueryRequest { Query = "{ __typename }" }),
Headers =
{
{ "Accept", $"{ContentType.Types.MultiPart}/{ContentType.SubTypes.Mixed}" }
@@ -389,13 +403,12 @@ public async Task New_Query_No_Streams_4()
using var request = new HttpRequestMessage(HttpMethod.Post, _url)
{
Content = JsonContent.Create(
- new ClientQueryRequest
- {
- Query = "{ __typename }"
- }),
+ new ClientQueryRequest { Query = "{ __typename }" }),
Headers =
{
- { "Accept", new[]
+ {
+ "Accept",
+ new[]
{
ContentType.GraphQLResponse,
$"{ContentType.Types.MultiPart}/{ContentType.SubTypes.Mixed}"
@@ -437,14 +450,8 @@ public async Task New_Query_No_Streams_5()
using var request = new HttpRequestMessage(HttpMethod.Post, _url)
{
Content = JsonContent.Create(
- new ClientQueryRequest
- {
- Query = "{ __typename }"
- }),
- Headers =
- {
- { "Accept", "*/*" }
- }
+ new ClientQueryRequest { Query = "{ __typename }" }),
+ Headers = { { "Accept", "*/*" } }
};
using var response = await client.SendAsync(request);
@@ -480,14 +487,8 @@ public async Task New_Query_No_Streams_6()
using var request = new HttpRequestMessage(HttpMethod.Post, _url)
{
Content = JsonContent.Create(
- new ClientQueryRequest
- {
- Query = "{ __typename }"
- }),
- Headers =
- {
- { "Accept", "application/*" }
- }
+ new ClientQueryRequest { Query = "{ __typename }" }),
+ Headers = { { "Accept", "application/*" } }
};
using var response = await client.SendAsync(request);
@@ -524,14 +525,8 @@ public async Task New_Query_No_Streams_7()
using var request = new HttpRequestMessage(HttpMethod.Post, _url)
{
Content = JsonContent.Create(
- new ClientQueryRequest
- {
- Query = "{ __typ$ename }"
- }),
- Headers =
- {
- { "Accept", ContentType.GraphQLResponse }
- }
+ new ClientQueryRequest { Query = "{ __typ$ename }" }),
+ Headers = { { "Accept", ContentType.GraphQLResponse } }
};
using var response = await client.SendAsync(request);
@@ -570,14 +565,8 @@ public async Task New_Query_No_Streams_8()
using var request = new HttpRequestMessage(HttpMethod.Post, _url)
{
Content = JsonContent.Create(
- new ClientQueryRequest
- {
- Query = "{ __type name }"
- }),
- Headers =
- {
- { "Accept", ContentType.GraphQLResponse }
- }
+ new ClientQueryRequest { Query = "{ __type name }" }),
+ Headers = { { "Accept", ContentType.GraphQLResponse } }
};
using var response = await client.SendAsync(request);
@@ -629,18 +618,16 @@ public async Task New_Query_No_Streams_9()
using var request = new HttpRequestMessage(HttpMethod.Post, _url)
{
Content = JsonContent.Create(
- new ClientQueryRequest
- {
- Query = "{ __typename }"
- }),
+ new ClientQueryRequest { Query = "{ __typename }" }),
Headers =
{
- { "Accept", new[]
+ {
+ "Accept",
+ new[]
{
ContentType.EventStream,
$"{ContentType.Types.MultiPart}/{ContentType.SubTypes.Mixed}",
- ContentType.Json,
- ContentType.GraphQLResponse,
+ ContentType.Json, ContentType.GraphQLResponse,
}
}
}
@@ -679,10 +666,7 @@ public async Task New_Query_No_Streams_10()
using var request = new HttpRequestMessage(HttpMethod.Post, _url)
{
Content = JsonContent.Create(
- new ClientQueryRequest
- {
- Query = "{ __typename }"
- })
+ new ClientQueryRequest { Query = "{ __typename }" })
};
request.Headers.TryAddWithoutValidation("Accept", "unsupported");
@@ -722,10 +706,7 @@ public async Task New_Query_No_Streams_12()
using var request = new HttpRequestMessage(HttpMethod.Post, _url)
{
Content = JsonContent.Create(
- new ClientQueryRequest
- {
- Query = "{ __typename }"
- })
+ new ClientQueryRequest { Query = "{ __typename }" })
};
request.Headers.TryAddWithoutValidation("Accept", "application/unsupported");
@@ -765,10 +746,7 @@ public async Task New_Query_No_Streams_13()
using var request = new HttpRequestMessage(HttpMethod.Post, _url)
{
Content = JsonContent.Create(
- new ClientQueryRequest
- {
- Query = "{ __typename }"
- })
+ new ClientQueryRequest { Query = "{ __typename }" })
};
request.Headers.TryAddWithoutValidation(
@@ -809,13 +787,12 @@ public async Task New_Query_With_Streams_1()
using var request = new HttpRequestMessage(HttpMethod.Post, _url)
{
Content = JsonContent.Create(
- new ClientQueryRequest
- {
- Query = "{ ... @defer { __typename } }"
- }),
+ new ClientQueryRequest { Query = "{ ... @defer { __typename } }" }),
Headers =
{
- { "Accept", new[]
+ {
+ "Accept",
+ new[]
{
ContentType.GraphQLResponse,
$"{ContentType.Types.MultiPart}/{ContentType.SubTypes.Mixed}"
@@ -870,14 +847,8 @@ public async Task New_Query_With_Streams_2()
using var request = new HttpRequestMessage(HttpMethod.Post, _url)
{
Content = JsonContent.Create(
- new ClientQueryRequest
- {
- Query = "{ ... @defer { __typename } }"
- }),
- Headers =
- {
- { "Accept", new[] { ContentType.GraphQLResponse } }
- }
+ new ClientQueryRequest { Query = "{ ... @defer { __typename } }" }),
+ Headers = { { "Accept", new[] { ContentType.GraphQLResponse } } }
};
using var response = await client.SendAsync(request, ResponseHeadersRead);
@@ -915,18 +886,8 @@ public async Task New_Query_With_Streams_3()
using var request = new HttpRequestMessage(HttpMethod.Post, _url)
{
Content = JsonContent.Create(
- new ClientQueryRequest
- {
- Query = "{ ... @defer { __typename } }"
- }),
- Headers =
- {
- { "Accept", new[]
- {
- ContentType.EventStream
- }
- }
- }
+ new ClientQueryRequest { Query = "{ ... @defer { __typename } }" }),
+ Headers = { { "Accept", new[] { ContentType.EventStream } } }
};
using var response = await client.SendAsync(request, ResponseHeadersRead);
diff --git a/src/HotChocolate/AspNetCore/test/AspNetCore.Tests/HttpPostMiddlewareTests.cs b/src/HotChocolate/AspNetCore/test/AspNetCore.Tests/HttpPostMiddlewareTests.cs
index df9a750ecbb..2663b193ee2 100644
--- a/src/HotChocolate/AspNetCore/test/AspNetCore.Tests/HttpPostMiddlewareTests.cs
+++ b/src/HotChocolate/AspNetCore/test/AspNetCore.Tests/HttpPostMiddlewareTests.cs
@@ -19,9 +19,7 @@ public class HttpPostMiddlewareTests : ServerTestBase
private static readonly Uri _url = new("http://localhost:5000/graphql");
public HttpPostMiddlewareTests(TestServerFactory serverFactory)
- : base(serverFactory)
- {
- }
+ : base(serverFactory) { }
[Fact]
public async Task Simple_IsAlive_Test()
@@ -153,15 +151,16 @@ public async Task SingleRequest_GetHeroName()
// act
var result =
- await server.PostAsync(new ClientQueryRequest
- {
- Query = @"
+ await server.PostAsync(
+ new ClientQueryRequest
+ {
+ Query = @"
{
hero {
name
}
}"
- });
+ });
// assert
result.MatchSnapshot();
@@ -175,15 +174,16 @@ public async Task SingleRequest_GetHeroName_Casing_Is_Preserved()
// act
var result =
- await server.PostAsync(new ClientQueryRequest
- {
- Query = @"
+ await server.PostAsync(
+ new ClientQueryRequest
+ {
+ Query = @"
{
HERO: hero {
name
}
}"
- });
+ });
// assert
result.MatchSnapshot();
@@ -194,23 +194,25 @@ public async Task Complexity_Exceeded()
{
// arrange
var server = CreateStarWarsServer(
- configureServices: c => c.AddGraphQLServer().ModifyRequestOptions(o =>
- {
- o.Complexity.Enable = true;
- o.Complexity.MaximumAllowed = 1;
- }));
+ configureServices: c => c.AddGraphQLServer().ModifyRequestOptions(
+ o =>
+ {
+ o.Complexity.Enable = true;
+ o.Complexity.MaximumAllowed = 1;
+ }));
// act
var result =
- await server.PostAsync(new ClientQueryRequest
- {
- Query = @"
+ await server.PostAsync(
+ new ClientQueryRequest
+ {
+ Query = @"
{
HERO: hero {
name
}
}"
- });
+ });
// assert
result.MatchSnapshot();
@@ -224,19 +226,17 @@ public async Task SingleRequest_GetHeroName_With_EnumVariable()
// act
var result =
- await server.PostAsync(new ClientQueryRequest
- {
- Query = @"
+ await server.PostAsync(
+ new ClientQueryRequest
+ {
+ Query = @"
query ($episode: Episode!) {
hero(episode: $episode) {
name
}
}",
- Variables = new Dictionary
- {
- { "episode", "NEW_HOPE" }
- }
- });
+ Variables = new Dictionary { { "episode", "NEW_HOPE" } }
+ });
// assert
result.MatchSnapshot();
@@ -250,19 +250,17 @@ public async Task SingleRequest_GetHumanName_With_StringVariable()
// act
var result =
- await server.PostAsync(new ClientQueryRequest
- {
- Query = @"
+ await server.PostAsync(
+ new ClientQueryRequest
+ {
+ Query = @"
query h($id: String!) {
human(id: $id) {
name
}
}",
- Variables = new Dictionary
- {
- { "id", "1000" }
- }
- });
+ Variables = new Dictionary { { "id", "1000" } }
+ });
// assert
result.MatchSnapshot();
@@ -276,9 +274,10 @@ public async Task SingleRequest_Defer_Results()
// act
var result =
- await server.PostRawAsync(new ClientQueryRequest
- {
- Query = @"
+ await server.PostRawAsync(
+ new ClientQueryRequest
+ {
+ Query = @"
{
... @defer {
wait(m: 300)
@@ -292,7 +291,7 @@ public async Task SingleRequest_Defer_Results()
}
}
}"
- });
+ });
// assert
result.MatchSnapshot();
@@ -307,12 +306,13 @@ public async Task Single_Diagnostic_Listener_Is_Triggered()
var server = CreateStarWarsServer(
configureServices: s => s
.AddGraphQLServer()
- .AddDiagnosticEventListener(_ => listenerA));
+ .AddDiagnosticEventListener(_ => listenerA));
// act
- await server.PostRawAsync(new ClientQueryRequest
- {
- Query = @"
+ await server.PostRawAsync(
+ new ClientQueryRequest
+ {
+ Query = @"
{
... @defer {
wait(m: 300)
@@ -326,7 +326,7 @@ public async Task Single_Diagnostic_Listener_Is_Triggered()
}
}
}"
- });
+ });
// assert
Assert.True(listenerA.Triggered);
@@ -342,13 +342,14 @@ public async Task Aggregate_Diagnostic_All_Listeners_Are_Triggered()
var server = CreateStarWarsServer(
configureServices: s => s
.AddGraphQLServer()
- .AddDiagnosticEventListener(_ => listenerA)
- .AddDiagnosticEventListener(_ => listenerB));
+ .AddDiagnosticEventListener(_ => listenerA)
+ .AddDiagnosticEventListener(_ => listenerB));
// act
- await server.PostRawAsync(new ClientQueryRequest
- {
- Query = @"
+ await server.PostRawAsync(
+ new ClientQueryRequest
+ {
+ Query = @"
{
... @defer {
wait(m: 300)
@@ -362,7 +363,7 @@ public async Task Aggregate_Diagnostic_All_Listeners_Are_Triggered()
}
}
}"
- });
+ });
// assert
Assert.True(listenerA.Triggered);
@@ -389,7 +390,6 @@ public async Task Apollo_Tracing_Invalid_Field()
name
}
}"
-
},
enableApolloTracing: true);
@@ -405,9 +405,10 @@ public async Task Ensure_Multipart_Format_Is_Correct_With_Defer()
// act
var result =
- await server.PostRawAsync(new ClientQueryRequest
- {
- Query = @"
+ await server.PostRawAsync(
+ new ClientQueryRequest
+ {
+ Query = @"
{
... @defer {
wait(m: 300)
@@ -421,7 +422,7 @@ public async Task Ensure_Multipart_Format_Is_Correct_With_Defer()
}
}
}"
- });
+ });
// assert
result.Content.MatchSnapshot();
@@ -435,9 +436,10 @@ public async Task Ensure_Multipart_Format_Is_Correct_With_Defer_If_Condition_Tru
// act
var result =
- await server.PostRawAsync(new ClientQueryRequest
- {
- Query = @"
+ await server.PostRawAsync(
+ new ClientQueryRequest
+ {
+ Query = @"
query ($if: Boolean!){
... @defer {
wait(m: 300)
@@ -451,11 +453,8 @@ public async Task Ensure_Multipart_Format_Is_Correct_With_Defer_If_Condition_Tru
}
}
}",
- Variables = new Dictionary
- {
- ["if"] = true
- }
- });
+ Variables = new Dictionary { ["if"] = true }
+ });
// assert
result.Content.MatchSnapshot();
@@ -469,9 +468,10 @@ public async Task Ensure_JSON_Format_Is_Correct_With_Defer_If_Condition_False()
// act
var result =
- await server.PostRawAsync(new ClientQueryRequest
- {
- Query = @"
+ await server.PostRawAsync(
+ new ClientQueryRequest
+ {
+ Query = @"
query ($if: Boolean!){
hero(episode: NEW_HOPE)
{
@@ -482,11 +482,8 @@ public async Task Ensure_JSON_Format_Is_Correct_With_Defer_If_Condition_False()
}
}
}",
- Variables = new Dictionary
- {
- ["if"] = false
- }
- });
+ Variables = new Dictionary { ["if"] = false }
+ });
// assert
result.Content.MatchSnapshot();
@@ -531,9 +528,10 @@ public async Task SingleRequest_CreateReviewForEpisode_With_ObjectVariable()
// act
var result =
- await server.PostAsync(new ClientQueryRequest
- {
- Query = @"
+ await server.PostAsync(
+ new ClientQueryRequest
+ {
+ Query = @"
mutation CreateReviewForEpisode(
$ep: Episode!
$review: ReviewInput!) {
@@ -542,18 +540,18 @@ public async Task SingleRequest_CreateReviewForEpisode_With_ObjectVariable()
commentary
}
}",
- Variables = new Dictionary
- {
- { "ep", "EMPIRE" },
+ Variables = new Dictionary
{
- "review",
- new Dictionary
+ { "ep", "EMPIRE" },
{
- { "stars", 5 }, { "commentary", "This is a great movie!" },
+ "review",
+ new Dictionary
+ {
+ { "stars", 5 }, { "commentary", "This is a great movie!" },
+ }
}
}
- }
- });
+ });
// assert
result.MatchSnapshot();
@@ -567,9 +565,10 @@ public async Task SingleRequest_CreateReviewForEpisode_Omit_NonNull_Variable()
// act
var result =
- await server.PostAsync(new ClientQueryRequest
- {
- Query = @"
+ await server.PostAsync(
+ new ClientQueryRequest
+ {
+ Query = @"
mutation CreateReviewForEpisode(
$ep: Episode!
$review: ReviewInput!) {
@@ -578,18 +577,17 @@ public async Task SingleRequest_CreateReviewForEpisode_Omit_NonNull_Variable()
commentary
}
}",
- Variables = new Dictionary
- {
+ Variables = new Dictionary
{
- "review",
- new Dictionary
{
- { "stars", 5 },
- { "commentary", "This is a great movie!" },
+ "review",
+ new Dictionary
+ {
+ { "stars", 5 }, { "commentary", "This is a great movie!" },
+ }
}
}
- }
- });
+ });
// assert
result.MatchSnapshot();
@@ -603,9 +601,10 @@ public async Task SingleRequest_CreateReviewForEpisode_Variables_In_ObjectValue(
// act
var result =
- await server.PostAsync(new ClientQueryRequest
- {
- Query = @"
+ await server.PostAsync(
+ new ClientQueryRequest
+ {
+ Query = @"
mutation CreateReviewForEpisode(
$ep: Episode!
$stars: Int!
@@ -618,13 +617,13 @@ public async Task SingleRequest_CreateReviewForEpisode_Variables_In_ObjectValue(
commentary
}
}",
- Variables = new Dictionary
- {
- { "ep", "EMPIRE" },
- { "stars", 5 },
- { "commentary", "This is a great movie!" }
- }
- });
+ Variables = new Dictionary
+ {
+ { "ep", "EMPIRE" },
+ { "stars", 5 },
+ { "commentary", "This is a great movie!" }
+ }
+ });
// assert
result.MatchSnapshot();
@@ -638,9 +637,10 @@ public async Task SingleRequest_CreateReviewForEpisode_Variables_Unused()
// act
var result =
- await server.PostAsync(new ClientQueryRequest
- {
- Query = @"
+ await server.PostAsync(
+ new ClientQueryRequest
+ {
+ Query = @"
mutation CreateReviewForEpisode(
$ep: Episode!
$stars: Int!
@@ -654,13 +654,13 @@ public async Task SingleRequest_CreateReviewForEpisode_Variables_Unused()
commentary
}
}",
- Variables = new Dictionary
- {
- { "ep", "EMPIRE" },
- { "stars", 5 },
- { "commentary", "This is a great movie!" }
- }
- });
+ Variables = new Dictionary
+ {
+ { "ep", "EMPIRE" },
+ { "stars", 5 },
+ { "commentary", "This is a great movie!" }
+ }
+ });
// assert
result.MatchSnapshot();
@@ -677,9 +677,10 @@ public async Task SingleRequest_CreateReviewForEpisode_Variables_Unused()
// act
var result =
- await server.PostAsync(new ClientQueryRequest
- {
- Query = @"
+ await server.PostAsync(
+ new ClientQueryRequest
+ {
+ Query = @"
query a {
a: hero {
name
@@ -691,8 +692,8 @@ public async Task SingleRequest_CreateReviewForEpisode_Variables_Unused()
name
}
}",
- OperationName = operationName
- });
+ OperationName = operationName
+ });
// assert
result.MatchSnapshot(operationName);
@@ -706,19 +707,17 @@ public async Task SingleRequest_ValidationError()
// act
var result =
- await server.PostAsync(new ClientQueryRequest
- {
- Query = @"
+ await server.PostAsync(
+ new ClientQueryRequest
+ {
+ Query = @"
{
hero(episode: $episode) {
name
}
}",
- Variables = new Dictionary
- {
- { "episode", "NEW_HOPE" }
- }
- });
+ Variables = new Dictionary { { "episode", "NEW_HOPE" } }
+ });
// assert
result.MatchSnapshot();
@@ -732,15 +731,16 @@ public async Task SingleRequest_SyntaxError()
// act
var result =
- await server.PostAsync(new ClientQueryRequest
- {
- Query = @"
+ await server.PostAsync(
+ new ClientQueryRequest
+ {
+ Query = @"
{
ähero {
name
}
}"
- });
+ });
// assert
result.MatchSnapshot();
@@ -761,10 +761,7 @@ public async Task SingleRequest_Double_Variable()
query ($d: Float) {
double_arg(d: $d)
}",
- Variables = new Dictionary
- {
- { "d", 1.539 }
- }
+ Variables = new Dictionary { { "d", 1.539 } }
},
"/arguments");
@@ -787,10 +784,7 @@ public async Task SingleRequest_Double_Max_Variable()
query ($d: Float) {
double_arg(d: $d)
}",
- Variables = new Dictionary
- {
- { "d", double.MaxValue }
- }
+ Variables = new Dictionary { { "d", double.MaxValue } }
},
"/arguments");
@@ -806,17 +800,15 @@ public async Task SingleRequest_Double_Min_Variable()
// act
var result =
- await server.PostAsync(new ClientQueryRequest
- {
- Query = @"
+ await server.PostAsync(
+ new ClientQueryRequest
+ {
+ Query = @"
query ($d: Float) {
double_arg(d: $d)
}",
- Variables = new Dictionary
- {
- { "d", double.MinValue }
- }
- },
+ Variables = new Dictionary { { "d", double.MinValue } }
+ },
"/arguments");
// assert
@@ -838,10 +830,7 @@ public async Task SingleRequest_Decimal_Max_Variable()
query ($d: Decimal) {
decimal_arg(d: $d)
}",
- Variables = new Dictionary
- {
- { "d", decimal.MaxValue }
- }
+ Variables = new Dictionary { { "d", decimal.MaxValue } }
},
"/arguments");
@@ -864,10 +853,7 @@ public async Task SingleRequest_Decimal_Min_Variable()
query ($d: Decimal) {
decimal_arg(d: $d)
}",
- Variables = new Dictionary
- {
- { "d", decimal.MinValue }
- }
+ Variables = new Dictionary { { "d", decimal.MinValue } }
},
"/arguments");
@@ -993,27 +979,28 @@ public async Task BatchRequest_GetHero_And_GetHuman_MultiPart()
// act
var response =
await server.SendPostRequestAsync(
- JsonConvert.SerializeObject(new List
- {
- new ClientQueryRequest
+ JsonConvert.SerializeObject(
+ new List
{
- Query = @"
+ new ClientQueryRequest
+ {
+ Query = @"
query getHero {
hero(episode: EMPIRE) {
id @export
}
}"
- },
- new ClientQueryRequest
- {
- Query = @"
+ },
+ new ClientQueryRequest
+ {
+ Query = @"
query getHuman {
human(id: $id) {
name
}
}"
- }
- }),
+ }
+ }),
"/graphql");
if (response.StatusCode == HttpStatusCode.NotFound)
@@ -1161,15 +1148,16 @@ public async Task Throw_Custom_GraphQL_Error()
// act
var result =
- await server.PostAsync(new ClientQueryRequest
- {
- Query = @"
+ await server.PostAsync(
+ new ClientQueryRequest
+ {
+ Query = @"
{
hero {
name
}
}"
- });
+ });
// assert
result.MatchSnapshot();
@@ -1181,17 +1169,15 @@ public async Task Strip_Null_Values_Variant_1()
// arrange
var server = CreateStarWarsServer(
configureServices: s => s.AddHttpResponseFormatter(
- _ => new DefaultHttpResponseFormatter(new() { NullIgnoreCondition = Fields })));
+ _ => new DefaultHttpResponseFormatter(
+ new() { Json = new() { NullIgnoreCondition = Fields } })));
var client = server.CreateClient();
// act
using var request = new HttpRequestMessage(HttpMethod.Post, _url)
{
Content = JsonContent.Create(
- new ClientQueryRequest
- {
- Query = "{ __schema { description } }"
- })
+ new ClientQueryRequest { Query = "{ __schema { description } }" })
};
using var response = await client.SendAsync(request);
@@ -1217,17 +1203,17 @@ public async Task Strip_Null_Values_Variant_2()
// arrange
var server = CreateStarWarsServer(
configureServices: s => s.AddHttpResponseFormatter(
- new JsonResultFormatterOptions { NullIgnoreCondition = Fields }));
+ new HttpResponseFormatterOptions
+ {
+ Json = new JsonResultFormatterOptions { NullIgnoreCondition = Fields }
+ }));
var client = server.CreateClient();
// act
using var request = new HttpRequestMessage(HttpMethod.Post, _url)
{
Content = JsonContent.Create(
- new ClientQueryRequest
- {
- Query = "{ __schema { description } }"
- })
+ new ClientQueryRequest { Query = "{ __schema { description } }" })
};
using var response = await client.SendAsync(request);
@@ -1258,20 +1244,18 @@ public async Task Strip_Null_Elements()
.AddGraphQLServer("test")
.AddQueryType()
.Services
- .AddHttpResponseFormatter(new JsonResultFormatterOptions
- {
- NullIgnoreCondition = Lists
- }));
+ .AddHttpResponseFormatter(
+ new HttpResponseFormatterOptions
+ {
+ Json = new JsonResultFormatterOptions { NullIgnoreCondition = Lists }
+ }));
var client = server.CreateClient();
// act
using var request = new HttpRequestMessage(HttpMethod.Post, url)
{
Content = JsonContent.Create(
- new ClientQueryRequest
- {
- Query = "{ nullValues }"
- })
+ new ClientQueryRequest { Query = "{ nullValues }" })
};
using var response = await client.SendAsync(request);