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
38 changes: 18 additions & 20 deletions src/GraphQL.Client/GraphQLHttpClient.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
using System;
using System.Collections.Concurrent;
using System.Diagnostics;
using System.IO;
using System.Net.Http;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using GraphQL.Client.Abstractions;
Expand Down Expand Up @@ -73,7 +73,7 @@ public async Task<GraphQLResponse<TResponse>> SendQueryAsync<TResponse>(GraphQLR
if (Options.UseWebSocketForQueriesAndMutations)
return await _graphQlHttpWebSocket.SendRequest<TResponse>(request, cancellationToken);

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

/// <inheritdoc />
Expand Down Expand Up @@ -124,35 +124,33 @@ public IObservable<GraphQLResponse<TResponse>> CreateSubscriptionStream<TRespons

#region Private Methods

private async Task<GraphQLHttpResponse<TResponse>> SendHttpPostRequestAsync<TResponse>(GraphQLRequest request, CancellationToken cancellationToken = default)
private async Task<GraphQLHttpResponse<TResponse>> SendHttpRequestAsync<TResponse>(GraphQLRequest request, CancellationToken cancellationToken = default)
{
var preprocessedRequest = await Options.PreprocessRequest(request, this);
using var httpRequestMessage = GenerateHttpRequestMessage(preprocessedRequest);
using var httpResponseMessage = await HttpClient.SendAsync(httpRequestMessage, cancellationToken);

httpResponseMessage.EnsureSuccessStatusCode();

var bodyStream = await httpResponseMessage.Content.ReadAsStreamAsync();
var response = await JsonSerializer.DeserializeFromUtf8StreamAsync<TResponse>(bodyStream, cancellationToken);
return response.ToGraphQLHttpResponse(httpResponseMessage.Headers, httpResponseMessage.StatusCode);
}
using var httpRequestMessage = preprocessedRequest.ToHttpRequestMessage(Options, JsonSerializer);
using var httpResponseMessage = await HttpClient.SendAsync(httpRequestMessage, HttpCompletionOption.ResponseHeadersRead, cancellationToken);

private HttpRequestMessage GenerateHttpRequestMessage(GraphQLRequest request)
{
var message = new HttpRequestMessage(HttpMethod.Post, Options.EndPoint)
var contentStream = await httpResponseMessage.Content.ReadAsStreamAsync();

if (httpResponseMessage.IsSuccessStatusCode)
{
Content = new StringContent(JsonSerializer.SerializeToString(request), Encoding.UTF8, Options.MediaType)
};
var graphQLResponse = await JsonSerializer.DeserializeFromUtf8StreamAsync<TResponse>(contentStream, cancellationToken);
return graphQLResponse.ToGraphQLHttpResponse(httpResponseMessage.Headers, httpResponseMessage.StatusCode);
}

if (request is GraphQLHttpRequest httpRequest)
httpRequest.PreprocessHttpRequestMessage(message);
// error handling
string content = null;
if (contentStream != null)
using (var sr = new StreamReader(contentStream))
content = await sr.ReadToEndAsync();

return message;
throw new GraphQLHttpRequestException(httpResponseMessage.StatusCode, httpResponseMessage.Headers, content);
}

private Uri GetWebSocketUri()
{
var webSocketSchema = Options.EndPoint.Scheme == "https" ? "wss" : "ws";
string webSocketSchema = Options.EndPoint.Scheme == "https" ? "wss" : "ws";
return new Uri($"{webSocketSchema}://{Options.EndPoint.Host}:{Options.EndPoint.Port}{Options.EndPoint.AbsolutePath}");
}

Expand Down
3 changes: 2 additions & 1 deletion src/GraphQL.Client/GraphQLHttpClientOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,8 @@ public class GraphQLHttpClientOptions
/// <summary>
/// Request preprocessing function. Can be used i.e. to inject authorization info into a GraphQL request payload.
/// </summary>
public Func<GraphQLRequest, GraphQLHttpClient, Task<GraphQLRequest>> PreprocessRequest { get; set; } = (request, client) => Task.FromResult(request);
public Func<GraphQLRequest, GraphQLHttpClient, Task<GraphQLHttpRequest>> PreprocessRequest { get; set; } = (request, client) =>
Task.FromResult(request is GraphQLHttpRequest graphQLHttpRequest ? graphQLHttpRequest : new GraphQLHttpRequest(request));

/// <summary>
/// This callback is called after successfully establishing a websocket connection but before any regular request is made.
Expand Down
29 changes: 0 additions & 29 deletions src/GraphQL.Client/GraphQLHttpException.cs

This file was deleted.

25 changes: 25 additions & 0 deletions src/GraphQL.Client/GraphQLHttpRequest.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
using System;
using System.Net.Http;
using System.Runtime.Serialization;
using System.Text;
using GraphQL.Client.Abstractions;

namespace GraphQL.Client.Http
{
Expand All @@ -15,10 +17,33 @@ public GraphQLHttpRequest(string query, object? variables = null, string? operat
{
}

public GraphQLHttpRequest(GraphQLRequest other): base(other.Query, other.Variables, other.OperationName)
{
}

/// <summary>
/// Allows to preprocess a <see cref="HttpRequestMessage"/> before it is sent, i.e. add custom headers
/// </summary>
[IgnoreDataMember]
[Obsolete("Inherit from GraphQLHttpRequest and override ToHttpRequestMessage() to customize the HttpRequestMessage. Will be removed in v4.0.0.")]
public Action<HttpRequestMessage> PreprocessHttpRequestMessage { get; set; } = message => { };

/// <summary>
/// Creates a <see cref="HttpRequestMessage"/> from this <see cref="GraphQLHttpRequest"/>.
/// Used by <see cref="GraphQLHttpClient"/> to convert GraphQL requests when sending them as regular HTTP requests.
/// </summary>
/// <param name="options">the <see cref="GraphQLHttpClientOptions"/> passed from <see cref="GraphQLHttpClient"/></param>
/// <param name="serializer">the <see cref="IGraphQLJsonSerializer"/> passed from <see cref="GraphQLHttpClient"/></param>
/// <returns></returns>
public virtual HttpRequestMessage ToHttpRequestMessage(GraphQLHttpClientOptions options, IGraphQLJsonSerializer serializer)
{
var message = new HttpRequestMessage(HttpMethod.Post, options.EndPoint)
{
Content = new StringContent(serializer.SerializeToString(this), Encoding.UTF8, options.MediaType)
};

PreprocessHttpRequestMessage(message);
return message;
}
}
}
41 changes: 41 additions & 0 deletions src/GraphQL.Client/GraphQLHttpRequestException.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
using System;
using System.Net;
using System.Net.Http.Headers;

namespace GraphQL.Client.Http
{

/// <summary>
/// An exception thrown on unexpected <see cref="System.Net.Http.HttpResponseMessage"/>
/// </summary>
public class GraphQLHttpRequestException : Exception
{
/// <summary>
/// The returned status code
/// </summary>
public HttpStatusCode StatusCode { get; }

/// <summary>
/// the returned response headers
/// </summary>
public HttpResponseHeaders ResponseHeaders { get; }

/// <summary>
/// the returned content
/// </summary>
public string? Content { get; }

/// <summary>
/// Creates a new instance of <see cref="GraphQLHttpRequestException"/>
/// </summary>
/// <param name="statusCode"></param>
/// <param name="responseHeaders"></param>
/// <param name="content"></param>
public GraphQLHttpRequestException(HttpStatusCode statusCode, HttpResponseHeaders responseHeaders, string? content) : base($"The HTTP request failed with status code {statusCode}")
{
StatusCode = statusCode;
ResponseHeaders = responseHeaders;
Content = content;
}
}
}