Skip to content

Commit

Permalink
Remote executable schemas (#139)
Browse files Browse the repository at this point in the history
* Static data link
* Http data link
* Merging local and remote schemas should just work
  • Loading branch information
pekkah committed Apr 2, 2019
1 parent 9da09af commit 3e68ff4
Show file tree
Hide file tree
Showing 47 changed files with 90,653 additions and 83 deletions.
2 changes: 1 addition & 1 deletion README.md
Expand Up @@ -56,7 +56,7 @@ See [Sample](https://github.com/pekkah/tanka-graphql-samples)
This repo includes a sample application which is used for testing
and development of the SignalR client and the server.

Open the `tanka-graphql.sln` and start the `graphql.samples.chat.web` project. This will start a simple chat server using the tanka.graphql.server.
Open the `tanka-graphql.sln` and start the `graphql.dev.chat.web` project. This will start a simple chat server using the tanka.graphql.server.

Start the client by following instructions below:

Expand Down
3 changes: 2 additions & 1 deletion dev/graphql.dev.chat.web/Controllers/QueryController.cs
Expand Up @@ -2,6 +2,7 @@
using tanka.graphql.samples.chat.web.GraphQL;
using tanka.graphql.server.utilities;
using Microsoft.AspNetCore.Mvc;
using tanka.graphql.requests;
using static tanka.graphql.Executor;
using static tanka.graphql.Parser;

Expand All @@ -25,7 +26,7 @@ public async Task<IActionResult> Post([FromBody] OperationRequest request)
Document = ParseDocument(request.Query),
Schema = _schemas.Chat,
OperationName = request.OperationName,
VariableValues = request.Variables?.ToVariableDictionary()
VariableValues = request.Variables?.ToNestedDictionary()
});

return Ok(result);
Expand Down
1 change: 1 addition & 0 deletions src/graphql.server/LogMessages.cs
@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using Microsoft.Extensions.Logging;
using tanka.graphql.requests;

namespace tanka.graphql.server
{
Expand Down
1 change: 1 addition & 0 deletions src/graphql.server/QueryStreamHub.cs
Expand Up @@ -3,6 +3,7 @@
using System.Threading.Tasks;
using Microsoft.AspNetCore.SignalR;
using tanka.graphql.channels;
using tanka.graphql.requests;

namespace tanka.graphql.server
{
Expand Down
1 change: 1 addition & 0 deletions src/graphql.server/QueryStreamService.cs
Expand Up @@ -7,6 +7,7 @@
using GraphQLParser.AST;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using tanka.graphql.requests;

namespace tanka.graphql.server
{
Expand Down
16 changes: 13 additions & 3 deletions src/graphql/ExecutionOptions.cs
Expand Up @@ -57,14 +57,24 @@ private static Error DefaultFormatError(Exception exception)
{
var message = exception.Message;

if (exception.InnerException != null) message += $" {exception.InnerException.Message}";
if (exception.InnerException != null)
message += $" {exception.InnerException.Message}";

var error = new Error(message);
var error = new Error(message);
EnrichWithErrorCode(error, exception);
if (!(exception is GraphQLError graphQLError)) return error;
if (!(exception is GraphQLError graphQLError))
return error;

error.Locations = graphQLError.Locations;
error.Path = graphQLError.Path?.Segments.ToList();
if (graphQLError.Extensions != null)
{
foreach (var extension in graphQLError.Extensions)
{
error.Extend(extension.Key, extension.Value);
}
}

return error;
}

Expand Down
2 changes: 2 additions & 0 deletions src/graphql/ExecutionResult.cs
@@ -1,6 +1,7 @@
using System.Collections.Generic;
using System.Linq;
using Newtonsoft.Json;
using tanka.graphql.requests;

namespace tanka.graphql
{
Expand All @@ -14,6 +15,7 @@ public class ExecutionResult : IExecutionResult
private IEnumerable<Error> _errors;
private IDictionary<string, object> _extensions;

[JsonConverter(typeof(NestedDictionaryConverter))]
public IDictionary<string, object> Data
{
get => _data;
Expand Down
6 changes: 3 additions & 3 deletions src/graphql/execution/ExecutionStrategyBase.cs
Expand Up @@ -54,7 +54,8 @@ public abstract class ExecutionStrategyBase : IExecutionStrategy
field,
fieldSelection,
argumentValues,
path);
path,
context);

var resolver = schema.GetResolver(objectType.Name, fieldName);

Expand Down Expand Up @@ -118,8 +119,7 @@ public abstract class ExecutionStrategyBase : IExecutionStrategy
throw new GraphQLError(
$"Object '{objectType.Name}' does not have field '{fieldName}'");

object responseValue = null;
responseValue = await ExecuteFieldAsync(
var responseValue = await ExecuteFieldAsync(
context,
objectType,
objectValue,
Expand Down
19 changes: 15 additions & 4 deletions src/graphql/execution/ExecutorContext.cs
@@ -1,25 +1,36 @@
using System;
using System.Collections.Generic;
using tanka.graphql.error;
using tanka.graphql.type;
using GraphQLParser.AST;
using tanka.graphql.type;

namespace tanka.graphql.execution
{
public class ExecutorContext : IExecutorContext
{
private readonly List<Exception> _errors;

public ExecutorContext(ISchema schema, GraphQLDocument document, Extensions extensions,
IExecutionStrategy strategy)
public ExecutorContext(ISchema schema,
GraphQLDocument document,
Extensions extensions,
IExecutionStrategy strategy,
GraphQLOperationDefinition operation,
IDictionary<string, GraphQLFragmentDefinition> fragments,
IDictionary<string, object> coercedVariableValues)
{
Schema = schema ?? throw new ArgumentNullException(nameof(schema));
Document = document ?? throw new ArgumentNullException(nameof(document));
Extensions = extensions ?? throw new ArgumentNullException(nameof(extensions));
Strategy = strategy ?? throw new ArgumentNullException(nameof(strategy));
Operation = operation;
Fragments = fragments;
CoercedVariableValues = coercedVariableValues;
_errors = new List<Exception>();
}

public GraphQLOperationDefinition Operation { get; }
public IDictionary<string, GraphQLFragmentDefinition> Fragments { get; }
public IDictionary<string, object> CoercedVariableValues { get; }

public ISchema Schema { get; }

public GraphQLDocument Document { get; }
Expand Down
12 changes: 8 additions & 4 deletions src/graphql/execution/IExecutorContext.cs
@@ -1,22 +1,26 @@
using System;
using System.Collections.Generic;
using tanka.graphql.error;
using tanka.graphql.type;
using GraphQLParser.AST;
using tanka.graphql.type;

namespace tanka.graphql.execution
{
public interface IExecutorContext
{
GraphQLOperationDefinition Operation { get; }

IDictionary<string, GraphQLFragmentDefinition> Fragments { get; }

ISchema Schema { get; }

GraphQLDocument Document { get; }

IExecutionStrategy Strategy { get; }
Extensions Extensions { get; }

IEnumerable<Exception> FieldErrors { get; }

Extensions Extensions { get; }
IExecutionStrategy Strategy { get; }
IDictionary<string, object> CoercedVariableValues { get; }

void AddError(Exception error);
}
Expand Down
22 changes: 14 additions & 8 deletions src/graphql/execution/QueryContext.cs
@@ -1,27 +1,28 @@
using System;
using System.Collections.Generic;
using System.Threading;
using tanka.graphql.error;
using tanka.graphql.type;
using System.Linq;
using GraphQLParser.AST;
using tanka.graphql.type;

namespace tanka.graphql.execution
{
public class QueryContext
{
public QueryContext(Func<Exception, Error> formatError,
public QueryContext(
Func<Exception, Error> formatError,
GraphQLDocument document,
GraphQLOperationDefinition operation,
ISchema schema,
Dictionary<string, object> coercedVariableValues,
object initialValue,
object initialValue,
Extensions extensions)
{
FormatError = formatError ?? throw new ArgumentNullException(nameof(formatError));
Document = document ?? throw new ArgumentNullException(nameof(document));
OperationDefinition = operation ?? throw new ArgumentNullException(nameof(operation));
Schema = schema ?? throw new ArgumentNullException(nameof(schema));
CoercedVariableValues = coercedVariableValues ?? throw new ArgumentNullException(nameof(coercedVariableValues));
CoercedVariableValues =
coercedVariableValues ?? throw new ArgumentNullException(nameof(coercedVariableValues));
InitialValue = initialValue;
Extensions = extensions;
}
Expand All @@ -40,7 +41,8 @@ public class QueryContext

public Extensions Extensions { get; }

public void Deconstruct(out ISchema schema, out GraphQLDocument document, out GraphQLOperationDefinition operation, out object initialValue,
public void Deconstruct(out ISchema schema, out GraphQLDocument document,
out GraphQLOperationDefinition operation, out object initialValue,
out Dictionary<string, object> coercedVariableValues)
{
schema = Schema;
Expand All @@ -57,7 +59,11 @@ public class QueryContext
Schema,
Document,
Extensions,
executionStrategy);
executionStrategy,
OperationDefinition,
Document.Definitions.OfType<GraphQLFragmentDefinition>()
.ToDictionary(f => f.Name.Value, f => f),
CoercedVariableValues);
}
}
}
3 changes: 2 additions & 1 deletion src/graphql/execution/Subscription.cs
Expand Up @@ -129,7 +129,8 @@ public static class Subscription
field,
fieldSelection,
coercedArgumentValues,
path);
path,
context);

var subscriber = schema.GetSubscriber(subscriptionType.Name, fieldName);

Expand Down
29 changes: 29 additions & 0 deletions src/graphql/introspection/IntrospectionParser.cs
@@ -0,0 +1,29 @@
using Newtonsoft.Json;

namespace tanka.graphql.introspection
{
public static class IntrospectionParser
{
public static IntrospectionResult Deserialize(string introspectionResult)
{
var result = JsonConvert.DeserializeObject<IntrospectionExecutionResult>(introspectionResult);

return new IntrospectionResult
{
Schema = result.Data.Schema
};
}
}

internal class IntrospectionExecutionResult
{
[JsonProperty("data")]
public IntrospectionExecutionResultData Data { get; set; }
}

internal class IntrospectionExecutionResultData
{
[JsonProperty("__schema")]
public __Schema Schema { get; set; }
}
}
7 changes: 7 additions & 0 deletions src/graphql/introspection/IntrospectionResult.cs
@@ -0,0 +1,7 @@
namespace tanka.graphql.introspection
{
public class IntrospectionResult
{
public __Schema Schema { get; set; }
}
}

0 comments on commit 3e68ff4

Please sign in to comment.