Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 10 additions & 7 deletions src/GraphQL.Client/GraphQLHttpClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using System.Collections.Concurrent;
using System.Diagnostics;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
Expand Down Expand Up @@ -64,10 +65,11 @@ public GraphQLHttpClient(GraphQLHttpClientOptions options, HttpClient httpClient
#region IGraphQLClient

/// <inheritdoc />
public Task<GraphQLResponse<TResponse>> SendQueryAsync<TResponse>(GraphQLRequest request, CancellationToken cancellationToken = default) {
return Options.UseWebSocketForQueriesAndMutations
? this.graphQlHttpWebSocket.SendRequest<TResponse>(request, cancellationToken)
: this.SendHttpPostRequestAsync<TResponse>(request, cancellationToken);
public async Task<GraphQLResponse<TResponse>> SendQueryAsync<TResponse>(GraphQLRequest request, CancellationToken cancellationToken = default) {
if (Options.UseWebSocketForQueriesAndMutations)
return await this.graphQlHttpWebSocket.SendRequest<TResponse>(request, cancellationToken);

return await this.SendHttpPostRequestAsync<TResponse>(request, cancellationToken);
}

/// <inheritdoc />
Expand Down Expand Up @@ -113,10 +115,10 @@ public IObservable<GraphQLResponse<TResponse>> CreateSubscriptionStream<TRespons
/// </summary>
/// <returns></returns>
public Task InitializeWebsocketConnection() => graphQlHttpWebSocket.InitializeWebSocket();

#region Private Methods

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

var bodyStream = await httpResponseMessage.Content.ReadAsStreamAsync();
return await JsonSerializer.DeserializeFromUtf8StreamAsync<TResponse>(bodyStream, cancellationToken);
var response = await JsonSerializer.DeserializeFromUtf8StreamAsync<TResponse>(bodyStream, cancellationToken);
return response.ToGraphQLHttpResponse(httpResponseMessage.Headers, httpResponseMessage.StatusCode);
}

private HttpRequestMessage GenerateHttpRequestMessage(GraphQLRequest request) {
Expand Down
33 changes: 32 additions & 1 deletion src/GraphQL.Client/GraphQLHttpResponse.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,36 @@
using System;
using System.Net;
using System.Net.Http.Headers;

namespace GraphQL.Client.Http {

public class GraphQLHttpResponse<T> : GraphQLResponse<T> {
public class GraphQLHttpResponse<T>: GraphQLResponse<T> {
public GraphQLHttpResponse(GraphQLResponse<T> response, HttpResponseHeaders responseHeaders, HttpStatusCode statusCode) {
Data = response.Data;
Errors = response.Errors;
Extensions = response.Extensions;
ResponseHeaders = responseHeaders;
StatusCode = statusCode;
}

public HttpResponseHeaders ResponseHeaders { get; set; }
public HttpStatusCode StatusCode { get; set; }
}

public static class GraphQLResponseExtensions {
public static GraphQLHttpResponse<T> ToGraphQLHttpResponse<T>(this GraphQLResponse<T> response, HttpResponseHeaders responseHeaders, HttpStatusCode statusCode) {
return new GraphQLHttpResponse<T>(response, responseHeaders, statusCode);
}

/// <summary>
/// Casts <paramref name="response"/> to <see cref="GraphQLHttpResponse{T}"/>. Throws ig the cast fails.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="response"></param>
/// <exception cref="InvalidCastException"><paramref name="response"/> is not a <see cref="GraphQLHttpResponse{T}"/></exception>
/// <returns></returns>
public static GraphQLHttpResponse<T> AsGraphQLHttpResponse<T>(this GraphQLResponse<T> response) {
return (GraphQLHttpResponse<T>) response;
}
}
}
21 changes: 21 additions & 0 deletions tests/GraphQL.Integration.Tests/QueryAndMutationTests/Base.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
using System;
using System.Net;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
Expand Down Expand Up @@ -46,6 +48,25 @@ public async void QueryTheory(int id, string name) {
Assert.Equal(name, response.Data.Human.Name);
}

[Theory]
[ClassData(typeof(StarWarsHumans))]
public async void QueryAsHttpResponseTheory(int id, string name) {
var graphQLRequest = new GraphQLRequest($"{{ human(id: \"{id}\") {{ name }} }}");
var responseType = new {Human = new {Name = string.Empty}};
var response = await StarWarsClient.SendQueryAsync(graphQLRequest, () => responseType );

FluentActions.Invoking(() => response.AsGraphQLHttpResponse()).Should()
.NotThrow("because the returned object is a GraphQLHttpResponse");

var httpResponse = response.AsGraphQLHttpResponse();

httpResponse.Errors.Should().BeNull();
httpResponse.Data.Human.Name.Should().Be(name);

httpResponse.StatusCode.Should().BeEquivalentTo(HttpStatusCode.OK);
httpResponse.ResponseHeaders.Date.Should().BeCloseTo(DateTimeOffset.Now, TimeSpan.FromMinutes(1));
}

[Theory]
[ClassData(typeof(StarWarsHumans))]
public async void QueryWithDynamicReturnTypeTheory(int id, string name) {
Expand Down