Skip to content

Commit 525b915

Browse files
authored
Merge pull request #191 from graphql-dotnet/access-to-http-response-headers
Allow access to HttpResponseHeaders
2 parents ccb8eb7 + 78eac27 commit 525b915

File tree

3 files changed

+63
-8
lines changed

3 files changed

+63
-8
lines changed

src/GraphQL.Client/GraphQLHttpClient.cs

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
using System.Collections.Concurrent;
33
using System.Diagnostics;
44
using System.Net.Http;
5+
using System.Net.Http.Headers;
56
using System.Text;
67
using System.Threading;
78
using System.Threading.Tasks;
@@ -64,10 +65,11 @@ public GraphQLHttpClient(GraphQLHttpClientOptions options, HttpClient httpClient
6465
#region IGraphQLClient
6566

6667
/// <inheritdoc />
67-
public Task<GraphQLResponse<TResponse>> SendQueryAsync<TResponse>(GraphQLRequest request, CancellationToken cancellationToken = default) {
68-
return Options.UseWebSocketForQueriesAndMutations
69-
? this.graphQlHttpWebSocket.SendRequest<TResponse>(request, cancellationToken)
70-
: this.SendHttpPostRequestAsync<TResponse>(request, cancellationToken);
68+
public async Task<GraphQLResponse<TResponse>> SendQueryAsync<TResponse>(GraphQLRequest request, CancellationToken cancellationToken = default) {
69+
if (Options.UseWebSocketForQueriesAndMutations)
70+
return await this.graphQlHttpWebSocket.SendRequest<TResponse>(request, cancellationToken);
71+
72+
return await this.SendHttpPostRequestAsync<TResponse>(request, cancellationToken);
7173
}
7274

7375
/// <inheritdoc />
@@ -113,10 +115,10 @@ public IObservable<GraphQLResponse<TResponse>> CreateSubscriptionStream<TRespons
113115
/// </summary>
114116
/// <returns></returns>
115117
public Task InitializeWebsocketConnection() => graphQlHttpWebSocket.InitializeWebSocket();
116-
118+
117119
#region Private Methods
118120

119-
private async Task<GraphQLResponse<TResponse>> SendHttpPostRequestAsync<TResponse>(GraphQLRequest request, CancellationToken cancellationToken = default) {
121+
private async Task<GraphQLHttpResponse<TResponse>> SendHttpPostRequestAsync<TResponse>(GraphQLRequest request, CancellationToken cancellationToken = default) {
120122
var preprocessedRequest = await Options.PreprocessRequest(request, this);
121123
using var httpRequestMessage = this.GenerateHttpRequestMessage(preprocessedRequest);
122124
using var httpResponseMessage = await this.HttpClient.SendAsync(httpRequestMessage, cancellationToken);
@@ -125,7 +127,8 @@ private async Task<GraphQLResponse<TResponse>> SendHttpPostRequestAsync<TRespons
125127
}
126128

127129
var bodyStream = await httpResponseMessage.Content.ReadAsStreamAsync();
128-
return await JsonSerializer.DeserializeFromUtf8StreamAsync<TResponse>(bodyStream, cancellationToken);
130+
var response = await JsonSerializer.DeserializeFromUtf8StreamAsync<TResponse>(bodyStream, cancellationToken);
131+
return response.ToGraphQLHttpResponse(httpResponseMessage.Headers, httpResponseMessage.StatusCode);
129132
}
130133

131134
private HttpRequestMessage GenerateHttpRequestMessage(GraphQLRequest request) {
Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,36 @@
1+
using System;
2+
using System.Net;
3+
using System.Net.Http.Headers;
4+
15
namespace GraphQL.Client.Http {
26

3-
public class GraphQLHttpResponse<T> : GraphQLResponse<T> {
7+
public class GraphQLHttpResponse<T>: GraphQLResponse<T> {
8+
public GraphQLHttpResponse(GraphQLResponse<T> response, HttpResponseHeaders responseHeaders, HttpStatusCode statusCode) {
9+
Data = response.Data;
10+
Errors = response.Errors;
11+
Extensions = response.Extensions;
12+
ResponseHeaders = responseHeaders;
13+
StatusCode = statusCode;
14+
}
15+
16+
public HttpResponseHeaders ResponseHeaders { get; set; }
17+
public HttpStatusCode StatusCode { get; set; }
18+
}
19+
20+
public static class GraphQLResponseExtensions {
21+
public static GraphQLHttpResponse<T> ToGraphQLHttpResponse<T>(this GraphQLResponse<T> response, HttpResponseHeaders responseHeaders, HttpStatusCode statusCode) {
22+
return new GraphQLHttpResponse<T>(response, responseHeaders, statusCode);
23+
}
24+
25+
/// <summary>
26+
/// Casts <paramref name="response"/> to <see cref="GraphQLHttpResponse{T}"/>. Throws ig the cast fails.
27+
/// </summary>
28+
/// <typeparam name="T"></typeparam>
29+
/// <param name="response"></param>
30+
/// <exception cref="InvalidCastException"><paramref name="response"/> is not a <see cref="GraphQLHttpResponse{T}"/></exception>
31+
/// <returns></returns>
32+
public static GraphQLHttpResponse<T> AsGraphQLHttpResponse<T>(this GraphQLResponse<T> response) {
33+
return (GraphQLHttpResponse<T>) response;
34+
}
435
}
536
}

tests/GraphQL.Integration.Tests/QueryAndMutationTests/Base.cs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
using System;
2+
using System.Net;
13
using System.Net.Http;
24
using System.Threading;
35
using System.Threading.Tasks;
@@ -46,6 +48,25 @@ public async void QueryTheory(int id, string name) {
4648
Assert.Equal(name, response.Data.Human.Name);
4749
}
4850

51+
[Theory]
52+
[ClassData(typeof(StarWarsHumans))]
53+
public async void QueryAsHttpResponseTheory(int id, string name) {
54+
var graphQLRequest = new GraphQLRequest($"{{ human(id: \"{id}\") {{ name }} }}");
55+
var responseType = new {Human = new {Name = string.Empty}};
56+
var response = await StarWarsClient.SendQueryAsync(graphQLRequest, () => responseType );
57+
58+
FluentActions.Invoking(() => response.AsGraphQLHttpResponse()).Should()
59+
.NotThrow("because the returned object is a GraphQLHttpResponse");
60+
61+
var httpResponse = response.AsGraphQLHttpResponse();
62+
63+
httpResponse.Errors.Should().BeNull();
64+
httpResponse.Data.Human.Name.Should().Be(name);
65+
66+
httpResponse.StatusCode.Should().BeEquivalentTo(HttpStatusCode.OK);
67+
httpResponse.ResponseHeaders.Date.Should().BeCloseTo(DateTimeOffset.Now, TimeSpan.FromMinutes(1));
68+
}
69+
4970
[Theory]
5071
[ClassData(typeof(StarWarsHumans))]
5172
public async void QueryWithDynamicReturnTypeTheory(int id, string name) {

0 commit comments

Comments
 (0)