Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added File Upload Support to Fusion. #6359

Merged
merged 8 commits into from
Jul 20, 2023
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
47 changes: 29 additions & 18 deletions src/HotChocolate/Core/src/Types/Types/Extensions/TypeExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -272,7 +272,7 @@ internal static IInputType EnsureInputType(this IType type)
throw InputTypeExpected(type);
}

return (IInputType)type;
return (IInputType) type;
}

public static bool IsOutputType(this IType type)
Expand All @@ -297,7 +297,7 @@ internal static IOutputType EnsureOutputType(this IType type)
throw OutputTypeExpected(type);
}

return (IOutputType)type;
return (IOutputType) type;
}

public static bool IsUnionType(this IType type)
Expand Down Expand Up @@ -345,7 +345,7 @@ internal static bool IsType(this IType type, TypeKind kind)
return true;
}

if (type.Kind == TypeKind.NonNull && ((NonNullType)type).Type.Kind == kind)
if (type.Kind == TypeKind.NonNull && ((NonNullType) type).Type.Kind == kind)
{
return true;
}
Expand All @@ -363,7 +363,8 @@ private static bool IsType(this IType type, TypeKind kind1, TypeKind kind2)

if (type.Kind == TypeKind.NonNull)
{
var innerKind = ((NonNullType)type).Type.Kind;
var innerKind = ((NonNullType) type).Type.Kind;

if (innerKind == kind1 || innerKind == kind2)
{
return true;
Expand All @@ -383,7 +384,8 @@ internal static bool IsType(this IType type, TypeKind kind1, TypeKind kind2, Typ

if (type.Kind == TypeKind.NonNull)
{
var innerKind = ((NonNullType)type).Type.Kind;
var innerKind = ((NonNullType) type).Type.Kind;

if (innerKind == kind1 || innerKind == kind2 || type.Kind == kind3)
{
return true;
Expand All @@ -402,12 +404,12 @@ public static IType InnerType(this IType type)

if (type.Kind == TypeKind.NonNull)
{
return ((NonNullType)type).Type;
return ((NonNullType) type).Type;
}

if (type.Kind == TypeKind.List)
{
return ((ListType)type).ElementType;
return ((ListType) type).ElementType;
}

return type;
Expand All @@ -422,7 +424,7 @@ public static IType NullableType(this IType type)

return type.Kind != TypeKind.NonNull
? type
: ((NonNullType)type).Type;
: ((NonNullType) type).Type;
}

public static string TypeName(this IType type)
Expand All @@ -444,16 +446,16 @@ public static ListType ListType(this IType type)

if (type.Kind == TypeKind.List)
{
return (ListType)type;
return (ListType) type;
}

if (type.Kind == TypeKind.NonNull)
{
var innerType = ((NonNullType)type).Type;
var innerType = ((NonNullType) type).Type;

if (innerType.Kind == TypeKind.List)
{
return (ListType)innerType;
return (ListType) innerType;
}
}

Expand All @@ -471,7 +473,7 @@ public static INamedType NamedType(this IType type)

if (IsNamed(current))
{
return (INamedType)current;
return (INamedType) current;
}

for (var i = 0; i < 6; i++)
Expand All @@ -480,7 +482,7 @@ public static INamedType NamedType(this IType type)

if (IsNamed(current))
{
return (INamedType)current;
return (INamedType) current;
}
}

Expand Down Expand Up @@ -648,6 +650,15 @@ public static IType ToType(
TypeResources.TypeExtensions_KindIsNotSupported);
}

public static ITypeNode RenameName(this ITypeNode typeNode, string name)
=> typeNode switch
{
NonNullTypeNode nonNull => new NonNullTypeNode((INullableTypeNode)RenameName(nonNull.Type, name)),
ListTypeNode list => new ListTypeNode(RenameName(list.Type, name)),
NamedTypeNode named => named.WithName(named.Name.WithValue(name)),
_ => throw new NotSupportedException(TypeResources.TypeExtensions_KindIsNotSupported)
};

public static bool IsInstanceOfType(this IInputType type, IValueNode literal)
{
while (true)
Expand All @@ -670,14 +681,14 @@ public static bool IsInstanceOfType(this IInputType type, IValueNode literal)
switch (type.Kind)
{
case TypeKind.NonNull:
type = (IInputType)((NonNullType)type).Type;
type = (IInputType) ((NonNullType) type).Type;
continue;

case TypeKind.List:
{
if (literal.Kind is SyntaxKind.ListValue)
{
var list = (ListValueNode)literal;
var list = (ListValueNode) literal;

if (list.Items.Count == 0)
{
Expand All @@ -687,15 +698,15 @@ public static bool IsInstanceOfType(this IInputType type, IValueNode literal)
literal = list.Items[0];
}

type = (IInputType)((ListType)type).ElementType;
type = (IInputType) ((ListType) type).ElementType;
continue;
}

case TypeKind.InputObject:
return literal.Kind == SyntaxKind.ObjectValue;

default:
return ((ILeafType)type).IsInstanceOfType(literal);
return ((ILeafType) type).IsInstanceOfType(literal);
}
}
}
Expand Down Expand Up @@ -752,4 +763,4 @@ public static IType RewriteNullability(this IType type, INullabilityNode? nullab
throw RewriteNullability_InvalidNullabilityStructure();
}
}
}
}
8 changes: 5 additions & 3 deletions src/HotChocolate/Core/src/Types/Types/InputParser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -467,12 +467,14 @@ private object ParseDirective(

return null;
}

if(type.Kind == TypeKind.NonNull)
{
type = ((NonNullType)type).Type;
}

switch (type.Kind)
{
case TypeKind.NonNull:
return Deserialize(resultValue, ((NonNullType)type).Type, path, field);

case TypeKind.List:
return DeserializeList(resultValue, (ListType)type, path, field);

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using System.Text.Json;
using HotChocolate.Fusion.Metadata;
using HotChocolate.Transport.Http;
using static HotChocolate.Fusion.Clients.TransportFeatures;

namespace HotChocolate.Fusion.Clients;

Expand Down Expand Up @@ -40,6 +41,12 @@ private async Task<GraphQLResponse> ExecuteInternalAsync(SubgraphGraphQLRequest
try
{
var request = new GraphQLHttpRequest(subgraphRequest, _config.EndpointUri);

if((subgraphRequest.TransportFeatures & FileUpload) == FileUpload)
{
request.EnableFileUploads = true;
}

using var response = await _client.SendAsync(request, ct).ConfigureAwait(false);
var result = await response.ReadAsResultAsync(ct).ConfigureAwait(false);
return new GraphQLResponse(result);
Expand Down
57 changes: 53 additions & 4 deletions src/HotChocolate/Fusion/src/Core/Clients/SubgraphGraphQLRequest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,28 +3,77 @@

namespace HotChocolate.Fusion.Clients;

/// <summary>
/// Represents a GraphQL request that is sent to a subgraph.
/// </summary>
public sealed class SubgraphGraphQLRequest
{
/// <summary>
/// Initializes a new instance of <see cref="SubgraphGraphQLRequest"/>.
/// </summary>
/// <param name="subgraph">
/// The name of the subgraph.
/// </param>
/// <param name="document">
/// A GraphQL document string.
/// </param>
/// <param name="variableValues">
/// The variable values.
/// </param>
/// <param name="extensions">
/// The extensions.
/// </param>
/// <param name="transportFeatures">
/// The transport features that are needed for this GraphQL request.
/// </param>
public SubgraphGraphQLRequest(
string subgraph,
string document,
ObjectValueNode? variableValues,
ObjectValueNode? extensions)
ObjectValueNode? extensions,
TransportFeatures transportFeatures = TransportFeatures.Standard)
{
Subgraph = subgraph;
Document = document;
VariableValues = variableValues;
Extensions = extensions;
TransportFeatures = transportFeatures;
}

/// <summary>
/// Gets the name of the subgraph.
/// </summary>
public string Subgraph { get; }

/// <summary>
/// Gets a GraphQL document string.
/// </summary>
public string Document { get; }

/// <summary>
/// Gets the variable values.
/// </summary>
public ObjectValueNode? VariableValues { get; }

/// <summary>
/// Gets the extensions.
/// </summary>
public ObjectValueNode? Extensions { get; }

public static implicit operator OperationRequest(SubgraphGraphQLRequest method)
=> new(method.Document, null, null, method.VariableValues, method.Extensions);
}
/// <summary>
/// Gets the transport features that are needed for this GraphQL request.
/// </summary>
public TransportFeatures TransportFeatures { get; }

/// <summary>
/// Implicitly converts <see cref="SubgraphGraphQLRequest"/>s to <see cref="OperationRequest"/>s.
/// </summary>
/// <param name="request">
/// The <see cref="SubgraphGraphQLRequest"/> to convert.
/// </param>
/// <returns>
/// The converted <see cref="OperationRequest"/>.
/// </returns>
public static implicit operator OperationRequest(SubgraphGraphQLRequest request)
=> new(request.Document, null, null, request.VariableValues, request.Extensions);
}
23 changes: 23 additions & 0 deletions src/HotChocolate/Fusion/src/Core/Clients/TransportFeatures.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
namespace HotChocolate.Fusion.Clients;

/// <summary>
/// Specifies the transport features that are needed for a GraphQL request.
/// </summary>
[Flags]
public enum TransportFeatures
{
/// <summary>
/// Standard GraphQL over HTTP POST request.
/// </summary>
Standard = 0,

/// <summary>
/// GraphQL multipart request.
/// </summary>
FileUpload = 1,

/// <summary>
/// All Features.
/// </summary>
All = Standard | FileUpload
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
using HotChocolate.Fusion.Configuration;
using HotChocolate.Fusion.Metadata;
using HotChocolate.Language;
using HotChocolate.Types;
using HotChocolate.Types.Descriptors.Definitions;
using static System.Threading.Tasks.TaskCreationOptions;

namespace Microsoft.Extensions.DependencyInjection;
Expand Down Expand Up @@ -78,5 +80,10 @@ private static void ApplyConfiguration(ISchemaBuilder schemaBuilder, DocumentNod
schemaBuilder
.AddDocument(schemaDoc)
.SetFusionGraphConfig(fusionGraphConfig);

if (schemaDoc.Definitions.Any(t => t is ScalarTypeDefinitionNode { Name.Value: "Upload" }))
{
schemaBuilder.AddType<UploadType>();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -303,7 +303,7 @@ private static void ComposeResult(
else
{
var typeInfo = selectionData.GetTypeName();
var typeMetadata = context.Configuration.GetType<ObjectTypeInfo>(typeInfo);
var typeMetadata = context.Configuration.GetType<ObjectTypeMetadata>(typeInfo);
type = context.Schema.GetType<ObjectType>(typeMetadata.Name);
}

Expand Down
6 changes: 6 additions & 0 deletions src/HotChocolate/Fusion/src/Core/FusionResources.Designer.cs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions src/HotChocolate/Fusion/src/Core/FusionResources.resx
Original file line number Diff line number Diff line change
Expand Up @@ -66,4 +66,7 @@
<data name="ExecutionState_RegisterState_StateImmutable" xml:space="preserve">
<value>The state for the selection set `{0}` is immutable.</value>
</data>
<data name="ExecutionNodeBuilderMiddleware_CreateResolveByKeyBatchNode_StateInconsistent" xml:space="preserve">
<value>The state is inconsistent.</value>
</data>
</root>
Loading