Skip to content

Commit

Permalink
Merge pull request #1 from EasyOC/fix_graphql_api_with_parameters
Browse files Browse the repository at this point in the history
Fix graphql api with parameters
  • Loading branch information
hyzx86 committed Mar 19, 2024
2 parents 65a131b + 1571457 commit 9541a11
Show file tree
Hide file tree
Showing 3 changed files with 146 additions and 9 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
using System.Net;
using System.Net.Mime;
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;
using GraphQL;
using GraphQL.Execution;
Expand All @@ -28,6 +27,7 @@ namespace OrchardCore.Apis.GraphQL
public class GraphQLMiddleware : IMiddleware
{
private readonly GraphQLSettings _settings;
private readonly IGraphQLTextSerializer _graphQLTextSerializer;
private readonly IGraphQLSerializer _serializer;
private readonly IDocumentExecuter _executer;
internal static readonly Encoding _utf8Encoding = new UTF8Encoding(false);
Expand All @@ -37,11 +37,13 @@ public class GraphQLMiddleware : IMiddleware
public GraphQLMiddleware(
IOptions<GraphQLSettings> settingsOption,
IDocumentExecuter executer,
IGraphQLSerializer serializer)
IGraphQLSerializer serializer,
IGraphQLTextSerializer graphQLTextSerializer)
{
_settings = settingsOption.Value;
_executer = executer;
_serializer = serializer;
_graphQLTextSerializer = graphQLTextSerializer;
}
public async Task InvokeAsync(HttpContext context, RequestDelegate next)
{
Expand Down Expand Up @@ -89,19 +91,17 @@ private async Task ExecuteAsync(HttpContext context)

if (mediaType.IsSubsetOf(_jsonMediaType) || mediaType.IsSubsetOf(_graphQlMediaType))
{

using var sr = new StreamReader(context.Request.Body);
if (mediaType.IsSubsetOf(_graphQlMediaType))
{
using var sr = new StreamReader(context.Request.Body);

request = new GraphQLNamedQueryRequest
{
Query = await sr.ReadToEndAsync()
};
}
else
{
request = await JsonSerializer.DeserializeAsync<GraphQLNamedQueryRequest>(context.Request.Body, JOptions.CamelCase);
request = _graphQLTextSerializer.Deserialize<GraphQLNamedQueryRequest>(await sr.ReadToEndAsync());
}
}
else
Expand Down Expand Up @@ -171,7 +171,7 @@ private async Task ExecuteAsync(HttpContext context)
await _serializer.WriteAsync(context.Response.Body, result);
}

private static GraphQLNamedQueryRequest CreateRequestFromQueryString(HttpContext context, bool validateQueryKey = false)
private GraphQLNamedQueryRequest CreateRequestFromQueryString(HttpContext context, bool validateQueryKey = false)
{
if (!context.Request.Query.ContainsKey("query"))
{
Expand All @@ -190,7 +190,7 @@ private static GraphQLNamedQueryRequest CreateRequestFromQueryString(HttpContext

if (context.Request.Query.ContainsKey("variables"))
{
request.Variables = JsonSerializer.Deserialize<Inputs>(context.Request.Query["variables"], JOptions.CamelCase);
request.Variables = _graphQLTextSerializer.Deserialize<Inputs>(context.Request.Query["variables"]);
}

if (context.Request.Query.ContainsKey("operationName"))
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
using System;
using System.Text.Json;
using System.Text.Json.Serialization;
using GraphQL;

namespace OrchardCore.Apis.GraphQL.Json;

public class GraphQLNamedQueryRequestJsonConverter : JsonConverter<GraphQLNamedQueryRequest>
{
public static readonly GraphQLNamedQueryRequestJsonConverter Instance = new();

/// <summary>
/// Name for the operation name parameter.
/// See https://github.com/graphql/graphql-over-http/blob/master/spec/GraphQLOverHTTP.md#request-parameters
/// </summary>
private const string _operationNameKey = "operationName";

/// <summary>
/// Name for the query parameter.
/// See https://github.com/graphql/graphql-over-http/blob/master/spec/GraphQLOverHTTP.md#request-parameters
/// </summary>
private const string _queryKey = "query";

/// <summary>
/// Name for the variables parameter.
/// See https://github.com/graphql/graphql-over-http/blob/master/spec/GraphQLOverHTTP.md#request-parameters
/// </summary>
private const string _variablesKey = "variables";

/// <summary>
/// Name for the extensions parameter.
/// See https://github.com/graphql/graphql-over-http/blob/master/spec/GraphQLOverHTTP.md#request-parameters
/// </summary>
private const string _extensionsKey = "extensions";

private const string _namedQueryKey = "namedQuery";


public override void Write(Utf8JsonWriter writer, GraphQLNamedQueryRequest value, JsonSerializerOptions options)
{
writer.WriteStartObject();
if (value.Query != null)
{
writer.WritePropertyName(_queryKey);
writer.WriteStringValue(value.Query);
}
if (value.OperationName != null)
{
writer.WritePropertyName(_operationNameKey);
writer.WriteStringValue(value.OperationName);
}
if (value.Variables != null)
{
writer.WritePropertyName(_variablesKey);
JsonSerializer.Serialize(writer, value.Variables, options);
}
if (value.Extensions != null)
{
writer.WritePropertyName(_extensionsKey);
JsonSerializer.Serialize(writer, value.Extensions, options);
}
if (value.NamedQuery != null)
{
writer.WritePropertyName(_namedQueryKey);
JsonSerializer.Serialize(writer, value.NamedQuery, options);
}
writer.WriteEndObject();
}

public override GraphQLNamedQueryRequest Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
if (reader.TokenType != JsonTokenType.StartObject)
throw new JsonException();

var request = new GraphQLNamedQueryRequest();

while (reader.Read())
{
if (reader.TokenType == JsonTokenType.EndObject)
{
return request;
}

if (reader.TokenType != JsonTokenType.PropertyName)
{
throw new JsonException();
}

string key = reader.GetString()!;

//unexpected end of data
if (!reader.Read())
throw new JsonException();

switch (key)
{
case _queryKey:
request.Query = reader.GetString()!;
break;
case _operationNameKey:
request.OperationName = reader.GetString()!;
break;
case _namedQueryKey:
request.NamedQuery = reader.GetString();
break;
case _variablesKey:
request.Variables = JsonSerializer.Deserialize<Inputs>(ref reader, options);
break;
case _extensionsKey:
request.Extensions = JsonSerializer.Deserialize<Inputs>(ref reader, options);
break;
default:
reader.Skip();
break;
}
}

//unexpected end of data
throw new JsonException();
}
}
18 changes: 17 additions & 1 deletion src/OrchardCore.Modules/OrchardCore.Apis.GraphQL/Startup.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,13 @@
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Options;
using OrchardCore.Apis.GraphQL.Json;
using OrchardCore.Apis.GraphQL.Services;
using OrchardCore.Apis.GraphQL.ValidationRules;
using OrchardCore.Environment.Shell.Configuration;
using OrchardCore.Extensions;
using OrchardCore.Json;
using OrchardCore.Json.Extensions;
using OrchardCore.Modules;
using OrchardCore.Navigation;
using OrchardCore.Security.Permissions;
Expand Down Expand Up @@ -46,7 +50,19 @@ public override void ConfigureServices(IServiceCollection services)
services.AddScoped<IPermissionProvider, Permissions>();
services.AddTransient<INavigationProvider, AdminMenu>();
services.AddSingleton<GraphQLMiddleware>();
services.AddGraphQL(builder => builder.AddSystemTextJson());
services.Configure<ContentSerializerJsonOptionsConfiguration>(options =>
{
});

services.AddGraphQL(builder => builder.AddSystemTextJson((options, sp) =>
{
// Common types of converters are already configured in the assembly "GraphQL.SystemTextJson".
options.Converters.Add(GraphQLNamedQueryRequestJsonConverter.Instance);
var contentSerializerJsonOptions = sp.GetRequiredService<IOptions<ContentSerializerJsonOptions>>().Value;
options.Merge(contentSerializerJsonOptions.SerializerOptions);
}));

services.AddOptions<GraphQLSettings>().Configure<IShellConfiguration>((c, configuration) =>
{
Expand Down

0 comments on commit 9541a11

Please sign in to comment.