Skip to content

Commit

Permalink
Merge branch 'develop' into develop_2x
Browse files Browse the repository at this point in the history
  • Loading branch information
sahb1239 committed Jul 27, 2019
2 parents be3d36d + 63dc74b commit c6b4111
Show file tree
Hide file tree
Showing 14 changed files with 244 additions and 46 deletions.
2 changes: 1 addition & 1 deletion examples/SAHB.GraphQLClient.Examples/Program.cs
Expand Up @@ -88,7 +88,7 @@ static async Task Main(string[] args)
"https://mpjk0plp9.lp.gql.zone/graphql", HttpMethod.Post);
IGraphQLDeserialization graphQLDeserialization = new GraphQLDeserilization();

var deserilizedResult = graphQLDeserialization.DeserializeResult<HeroQuery>(result, null);
var deserilizedResult = graphQLDeserialization.DeserializeResult<HeroQuery>(result.Response, null);

Console.WriteLine(deserilizedResult.Data.Hero.Name);

Expand Down
61 changes: 41 additions & 20 deletions src/SAHB.GraphQLClient/Batching/Internal/GraphQLBatchMerger.cs
Expand Up @@ -70,29 +70,22 @@ public IGraphQLQuery<T> AddQuery<T>(params GraphQLQueryArgument[] arguments)
return new GraphQLBatchQuery<T>(this, identifier);
}

public async Task<T> GetValue<T>(string identitifer)
public Task<T> GetValue<T>(string identifier)
where T : class
{
if (!_isExecuted)
await Execute().ConfigureAwait(false);

if (_result.ContainsErrors)
{
throw new GraphQLErrorException(query: _executedQuery , errors: _result.Errors);
}

// Create new JObject
JObject deserilizeFrom = new JObject();
return GetDeserializedResult<T>(identifier);
}

// Get all fields
foreach (var field in _fields[identitifer])
{
// Add field with previous alias to JObject
deserilizeFrom.Add(field.Inner.Alias, _result.Data[field.Alias]);
}
public async Task<GraphQLDataDetailedResult<T>> GetDetailedValue<T>(string identifier)
where T : class
{
var deserialized = await GetDeserializedResult<T>(identifier);

// Deserilize
return _graphQLDeserialization.DeserializeResult<T>(deserilizeFrom, _fields[identitifer]);
return new GraphQLDataDetailedResult<T>
{
Data = deserialized,
Headers = _result.Headers
};
}

public async Task Execute()
Expand All @@ -119,7 +112,10 @@ public async Task Execute()
var serverResult = await _executor.ExecuteQuery(query: _executedQuery, url: _url, method: _httpMethod, authorizationToken: _authorizationToken, authorizationMethod: _authorizationMethod, headers: _headers).ConfigureAwait(false);

// Deserilize result
_result = _graphQLDeserialization.DeserializeResult<JObject>(serverResult, fields);
_result = _graphQLDeserialization.DeserializeResult<JObject>(serverResult.Response, fields);

// Set headers
_result.Headers = serverResult.Headers;
}

private void UpdateAlias()
Expand Down Expand Up @@ -155,6 +151,31 @@ private void UpdateArguments()
}
}

private async Task<T> GetDeserializedResult<T>(string identifier)
where T : class
{
if (!_isExecuted)
await Execute().ConfigureAwait(false);

if (_result.ContainsErrors)
{
throw new GraphQLErrorException(query: _executedQuery, errors: _result.Errors);
}

// Create new JObject
JObject deserilizeFrom = new JObject();

// Get all fields
foreach (var field in _fields[identifier])
{
// Add field with previous alias to JObject
deserilizeFrom.Add(field.Inner.Alias, _result.Data[field.Alias]);
}

// Deserialize from
return _graphQLDeserialization.DeserializeResult<T>(jsonObject: deserilizeFrom, fields: _fields[identifier]);
}

public bool Executed => _isExecuted;

// ReSharper disable once InconsistentNaming
Expand Down
6 changes: 6 additions & 0 deletions src/SAHB.GraphQLClient/Batching/Internal/GraphQLBatchQuery.cs
@@ -1,4 +1,5 @@
using SAHB.GraphQLClient.QueryGenerator;
using SAHB.GraphQLClient.Result;
using System.Threading.Tasks;

namespace SAHB.GraphQLClient.Batching.Internal
Expand All @@ -22,5 +23,10 @@ public Task<T> Execute()
{
return _batch.GetValue<T>(_identitifer);
}

public Task<GraphQLDataDetailedResult<T>> ExecuteDetailed()
{
return _batch.GetDetailedValue<T>(_identitifer);
}
}
}
10 changes: 10 additions & 0 deletions src/SAHB.GraphQLClient/Executor/GraphQLExecutorResponse.cs
@@ -0,0 +1,10 @@
using System.Net.Http.Headers;

namespace SAHB.GraphQLClient.Executor
{
public class GraphQLExecutorResponse
{
public string Response { get; set; }
public HttpResponseHeaders Headers { get; set; }
}
}
17 changes: 11 additions & 6 deletions src/SAHB.GraphQLClient/Executor/GraphQLHttpExecutor.cs
@@ -1,4 +1,4 @@
using System;
using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Net.Http.Headers;
Expand Down Expand Up @@ -44,7 +44,7 @@ public GraphQLHttpExecutor(HttpClient client)
}

/// <inheritdoc />
public async Task<string> ExecuteQuery(string query, string url = null, HttpMethod method = null, string authorizationToken = null, string authorizationMethod = "Bearer", IDictionary<string, string> headers = null)
public async Task<GraphQLExecutorResponse> ExecuteQuery(string query, string url = null, HttpMethod method = null, string authorizationToken = null, string authorizationMethod = "Bearer", IDictionary<string, string> headers = null)
{
// Check parameters for null
if (query == null) throw new ArgumentNullException(nameof(query));
Expand Down Expand Up @@ -95,10 +95,10 @@ public async Task<string> ExecuteQuery(string query, string url = null, HttpMeth
}
catch (Exception ex)
{
throw new GraphQLHttpExecutorServerErrorStatusCodeException(response.StatusCode, query, errorResponse, "Response from server was not successfully", ex);
throw new GraphQLHttpExecutorServerErrorStatusCodeException(response.StatusCode, query, errorResponse, "Response from server was not successful", ex);
}

throw new GraphQLHttpExecutorServerErrorStatusCodeException(response.StatusCode, query, errorResponse, "Response from server was not successfully");
throw new GraphQLHttpExecutorServerErrorStatusCodeException(response.StatusCode, query, errorResponse, "Response from server was not successful");
}

// Get response
Expand All @@ -110,9 +110,14 @@ public async Task<string> ExecuteQuery(string query, string url = null, HttpMeth
Logger.LogInformation($"Response: {stringResponse}");
}

return stringResponse;
// Return
return new GraphQLExecutorResponse
{
Response = stringResponse,
Headers = response.Headers
};
}

#region Logging

private ILoggerFactory _loggerFactory;
Expand Down
2 changes: 1 addition & 1 deletion src/SAHB.GraphQLClient/Executor/IGraphQLHttpExecutor.cs
Expand Up @@ -31,6 +31,6 @@ public interface IGraphQLHttpExecutor
/// <param name="authorizationToken">The authorization token which should be used</param>
/// <param name="authorizationMethod">Authorization method used for the authorization token</param>
/// <returns></returns>
Task<string> ExecuteQuery(string query, string url = null, HttpMethod method = null, string authorizationToken = null, string authorizationMethod = "Bearer", IDictionary<string, string> headers = null);
Task<GraphQLExecutorResponse> ExecuteQuery(string query, string url = null, HttpMethod method = null, string authorizationToken = null, string authorizationMethod = "Bearer", IDictionary<string, string> headers = null);
}
}
7 changes: 5 additions & 2 deletions src/SAHB.GraphQLClient/GraphQLHttpClient.cs
Expand Up @@ -110,13 +110,16 @@ public IGraphQLBatch CreateBatch(GraphQLOperationType operationType, string url
var requestQuery = QueryGenerator.GenerateQuery(operationType, selectionSet, arguments.ToArray());

// Get response
string stringResponse = await HttpExecutor.ExecuteQuery(requestQuery, url, httpMethod, headers: headers, authorizationToken: authorizationToken, authorizationMethod: authorizationMethod).ConfigureAwait(false);
GraphQLExecutorResponse response = await HttpExecutor.ExecuteQuery(requestQuery, url, httpMethod, headers: headers, authorizationToken: authorizationToken, authorizationMethod: authorizationMethod).ConfigureAwait(false);

// Deserilize
var result = Deserialization.DeserializeResult<T>(stringResponse, selectionSet);
var result = Deserialization.DeserializeResult<T>(response.Response, selectionSet);
if (result?.Errors?.Any() ?? false)
throw new GraphQLErrorException(query: requestQuery, errors: result.Errors);

// Set headers
result.Headers = response.Headers;

return result;
}

Expand Down
12 changes: 12 additions & 0 deletions src/SAHB.GraphQLClient/IGraphQLQuery.cs
@@ -1,4 +1,5 @@
using System.Threading.Tasks;
using SAHB.GraphQLClient.Result;

namespace SAHB.GraphQLClient
{
Expand All @@ -12,6 +13,11 @@ public interface IGraphQLQuery
/// Execute the query
/// </summary>
Task<dynamic> Execute();

/// <summary>
/// Execute query and return the result with response headers
/// </summary>
Task<GraphQLDataDetailedResult<dynamic>> ExecuteDetailed();
}

// ReSharper disable once InconsistentNaming
Expand All @@ -27,5 +33,11 @@ public interface IGraphQLQuery<T>
/// </summary>
/// <returns>The result of the query</returns>
Task<T> Execute();

/// <summary>
/// Execute query and return the result with response headers
/// </summary>
/// <returns>Object containing query result and response headers</returns>
Task<GraphQLDataDetailedResult<T>> ExecuteDetailed();
}
}
24 changes: 22 additions & 2 deletions src/SAHB.GraphQLClient/Internal/GraphQLQuery.cs
Expand Up @@ -8,6 +8,7 @@
using SAHB.GraphQLClient.Exceptions;
using SAHB.GraphQLClient.Executor;
using SAHB.GraphQLClient.QueryGenerator;
using SAHB.GraphQLClient.Result;

namespace SAHB.GraphQLClient.Internal
{
Expand Down Expand Up @@ -43,6 +44,22 @@ public GraphQLQuery(GraphQLOperationType operationType, IEnumerable<IGraphQLFiel

/// <inheritdoc />
public async Task<T> Execute()
{
var result = await GetDataResult().ConfigureAwait(false);
return result?.Data;
}

public async Task<GraphQLDataDetailedResult<T>> ExecuteDetailed()
{
var result = await GetDataResult().ConfigureAwait(false);
return new GraphQLDataDetailedResult<T>
{
Data = result.Data,
Headers = result.Headers
};
}

private async Task<GraphQLDataResult<T>> GetDataResult()
{
// Generate query
var query = _queryGenerator.GenerateQuery(OperationType, SelectionSet, _arguments);
Expand All @@ -51,12 +68,15 @@ public async Task<T> Execute()
var result = await _executor.ExecuteQuery(query, _url, _httpMethod, _authorizationToken, _authorizationMethod).ConfigureAwait(false);

// Deserilize
var deserilizationResult = _deserilization.DeserializeResult<T>(result, SelectionSet);
var deserilizationResult = _deserilization.DeserializeResult<T>(result.Response, SelectionSet);

if (deserilizationResult?.Errors?.Any() ?? false)
throw new GraphQLErrorException(query: query, errors: deserilizationResult.Errors);

return deserilizationResult?.Data;
// Set headers
deserilizationResult.Headers = result.Headers;

return deserilizationResult;
}
}

Expand Down
22 changes: 22 additions & 0 deletions src/SAHB.GraphQLClient/Result/GraphQLDataDetailedResult.cs
@@ -0,0 +1,22 @@
using System.Net.Http.Headers;

namespace SAHB.GraphQLClient.Result
{
// ReSharper disable once InconsistentNaming
/// <summary>
/// Contains the GraphQL data result with response headers
/// </summary>
/// <typeparam name="T">The data type returned</typeparam>
public class GraphQLDataDetailedResult<T>
{
/// <summary>
/// Contains the output from the GraphQL server. This is null, when errors has occured
/// </summary>
public T Data { get; set; }

/// <summary>
/// Contains the response headers
/// </summary>
public HttpResponseHeaders Headers { get; set; }
}
}
6 changes: 6 additions & 0 deletions src/SAHB.GraphQLClient/Result/GraphQLDataResult.cs
@@ -1,5 +1,6 @@
using System.Collections.Generic;
using System.Linq;
using System.Net.Http.Headers;

namespace SAHB.GraphQLClient.Result
{
Expand All @@ -15,6 +16,11 @@ public class GraphQLDataResult<T> where T : class
/// </summary>
public T Data { get; set; }

/// <summary>
/// Contains the response headers
/// </summary>
public HttpResponseHeaders Headers { get; set; }

/// <summary>
/// The errors which occured on execution of the query
/// </summary>
Expand Down
54 changes: 51 additions & 3 deletions tests/SAHB.GraphQLClient.Tests/Batching/BatchingTest.cs
@@ -1,6 +1,4 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Collections.Generic;
using System.Threading.Tasks;
using Newtonsoft.Json;
using SAHB.GraphQLClient.Deserialization;
Expand All @@ -10,6 +8,7 @@
using SAHB.GraphQLClient.QueryGenerator;
using SAHB.GraphQLClient.Tests.GraphQLClient.HttpClientMock;
using Xunit;
using System.Net.Http;

namespace SAHB.GraphQLClient.Tests.Batching
{
Expand Down Expand Up @@ -267,5 +266,54 @@ public async Task Test_Execute_Two_Times_Should_Not_Throw_Exception()
Assert.Equal(result1.Part1Field1, result2.Part1Field1);
Assert.Equal(result1.Part1Field2, result2.Part1Field2);
}

[Fact]
public async Task Test_ExecuteDetailed_Returns_Expected_Headers_And_Data()
{
// Arrange
var requiredQuery =
"{\"query\":\"query{batch0_Part1Field1:part1_field1 batch0_Part1Field2:part1Field2 batch1_Part2Field3:part2_field3 batch1_Part2Field4:part2Field4}\"}";
var requiredHeaders = new HttpResponseMessage().Headers;
requiredHeaders.Add("TestHeader", "TestValue");

var httpClientMock = new GraphQLHttpExecutorMock(
JsonConvert.SerializeObject(new
{
Data = new
{
batch0_Part1Field1 = "Value1",
batch0_Part1Field2 = "Value2",
batch1_Part2Field3 = "Value3",
batch1_Part2Field4 = "Value4"
}
}), requiredQuery, requiredHeaders);
var client = new GraphQLHttpClient(httpClientMock, new GraphQLFieldBuilder(),
new GraphQLQueryGeneratorFromFields(), new GraphQLDeserilization());

// Act
var batch = client.CreateBatch("");
var query1 = batch.Query<QueryBatchPart1>();
var query2 = batch.Query<QueryBatchPart2>();

var result1 = await query1.ExecuteDetailed();
var result2 = await query2.ExecuteDetailed();

// Assert
Assert.Equal(result1.Data.Part1Field1, "Value1");
Assert.Equal(result1.Data.Part1Field2, "Value2");

Assert.Equal(result2.Data.Part2Field3, "Value3");
Assert.Equal(result2.Data.Part2Field4, "Value4");

IEnumerable<string> expectedHeaders = new List<string>();
IEnumerable<string> actualHeaders = new List<string>();
requiredHeaders.TryGetValues("TestHeader", out expectedHeaders);
result1.Headers.TryGetValues("TestHeader", out actualHeaders);
Assert.Equal(actualHeaders, expectedHeaders);

requiredHeaders.TryGetValues("TestHeader", out expectedHeaders);
result2.Headers.TryGetValues("TestHeader", out actualHeaders);
Assert.Equal(actualHeaders, expectedHeaders);
}
}
}

0 comments on commit c6b4111

Please sign in to comment.