graphql-platform
graphql-platform copied to clipboard
Stitching variables can't be referenced when a query requires an object parameter
Describe the bug The documentation for schema stitching shows it's possible to reference resolver variables in the path using a special syntax.
extend type Query {
me: User! @delegate(schema: "users", path: "user(id: $contextData:UserId)")
}
However when trying to access a resolver variable as an object property HotChocolate will throw a SyntaxException: 'Unexpexcted token: $.'
extend type Query {
me: User! @delegate(schema: "users", path: "user(where: { id: $contextData:UserId })")
}
To Reproduce Modify the schema stitching example as above to reference a resolver variable within an object rather than a top level parameter and attempt to run the query.
Expected behavior The query should be parsed without an exception and the resolver variable should be included in the request.
Desktop (please complete the following information):
- OS: Windows 10
- Hot Chocolate 10.4.3 (also 11 preview 129)
Additional context Stepping through using the PDBs it looks like there would need to be a way to extend/inject the handling of $ variables from HotChocolate.Stitching.Delegation.SelectionPathParser.ParseValueLiteral in to HotChocolate.Parser.ParseValueLiteral as when Parser.ParseValueLiteral calls ParseObject it no longer calls through SelectionPathParser.ParseValueLiteral to have the chance to process stitching variables.
A hacky way to handle it could be to catch the Syntax Exception within SelectionPathParser.ParseValueLiteral and then re-attempt to handle the $ variable there.
@PascalSenn didn't we fix that?
@ben-hth thanks for reporting this.
@michaelstaib i also thought that. apparently still not all cases
There is a workaround for this that was posted in slack. Thanks @PascalSenn, hope my implementation is correct. 😄
Startup.cs
services
.AddGraphQLServer()
.MapField<ScopedContextMiddleware>(new FieldReference("Query", "me"))
...
ScopedContextMiddleware.cs
public class ScopedContextMiddleware
{
private readonly FieldDelegate _next;
public ScopedContextMiddleware(FieldDelegate next)
{
_next = next;
}
public async Task InvokeAsync(IMiddlewareContext context)
{
var filter = new Dictionary<string, object>();
filter["id"] = context.ContextData["UserId"];
context.ScopedContextData =
context.ScopedContextData.SetItem("UserId", filter);
await _next.Invoke(context);
}
}
Stitching.graphql
extend type Query {
me: User! @delegate(schema: "users", path: "user(where: $scopedContextData:UserId )")
}
Has there been any additional findings with this issue? I'm experiencing the same thing, but not with the query, but when extending a type. Just wanted to check since this is a pretty important piece of functionality when stitching.
Example code below
extend type Request { PersonInformation: [PersonInformation] @delegate(schema: "employeeProfile", path: "personInformations(where: {id: {eq: $fields:employeeProfileId}})") }
Error: "extensions": { "message": "Unexpected token: $.", "stackTrace": " at HotChocolate.Language.Utf8GraphQLParser.ParseValueLiteral(Boolean isConstant)\r\n at HotChocolate.Language.Utf8GraphQLParser.ParseValueLiteral(Boolean isConstant)\r\n at HotChocolate.Language.Utf8GraphQLParser.ParseValueLiteral(Boolean isConstant)\r\n at HotChocolate.Stitching.SelectionPathParser.ParseValueLiteral(Utf8GraphQLParser& parser)\r\n at HotChocolate.Stitching.SelectionPathParser.ParseArgument(Utf8GraphQLParser& parser)\r\n at HotChocolate.Stitching.SelectionPathParser.ParseArguments(Utf8GraphQLParser& parser)\r\n at HotChocolate.Stitching.SelectionPathParser.ParseSelectionPathComponent(Utf8GraphQLParser& parser)\r\n at HotChocolate.Stitching.SelectionPathParser.ParseSelectionPath(Utf8GraphQLParser& parser)\r\n at HotChocolate.Stitching.SelectionPathParser.Parse(String path)\r\n at HotChocolate.Stitching.Utilities.FieldDependencyResolver.CollectFieldNames(DelegateDirective directive, IHasName type, ISet1 dependencies)\r\n at HotChocolate.Stitching.Utilities.FieldDependencyResolver.CollectDelegationDependencies(Context context, IHasName type, IOutputField field)\r\n at HotChocolate.Stitching.Utilities.FieldDependencyResolver.VisitField(FieldNode node, Context context)\r\n at HotChocolate.Language.SyntaxVisitor2.VisitSelection(ISelectionNode node, TContext context)\r\n at HotChocolate.Language.SyntaxVisitor2.VisitMany[T](IEnumerable1 items, TContext context, Action2 action)\r\n at HotChocolate.Language.QuerySyntaxWalker1.VisitSelectionSet(SelectionSetNode node, TContext context)\r\n at HotChocolate.Stitching.Utilities.FieldDependencyResolver.GetFieldDependencies(DocumentNode document, SelectionSetNode selectionSet, INamedOutputType declaringType)\r\n at HotChocolate.Stitching.Delegation.ExtractFieldQuerySyntaxRewriter.RewriteSelectionSet(SelectionSetNode node, Context context)\r\n at HotChocolate.Language.SyntaxRewriter1.Rewrite[TParent,TProperty](TParent parent, TProperty property, TContext context, Func3 visit, Func2 rewrite)\r\n at HotChocolate.Stitching.Delegation.ExtractFieldQuerySyntaxRewriter.RewriteFieldSelectionSet(FieldNode node, IOutputField field, Context context)\r\n at HotChocolate.Stitching.Delegation.ExtractFieldQuerySyntaxRewriter.RewriteField(FieldNode node, Context context)\r\n at HotChocolate.Stitching.Delegation.ExtractFieldQuerySyntaxRewriter.ExtractField(NameString sourceSchema, DocumentNode document, OperationDefinitionNode operation, IFieldSelection selection, INamedOutputType declaringType)\r\n at HotChocolate.Stitching.Delegation.DelegateToRemoteSchemaMiddleware.CreateQuery(IMiddlewareContext context, NameString schemaName, IImmutableStack1 path, IImmutableStack1 reversePath)\r\n at HotChocolate.Stitching.Delegation.DelegateToRemoteSchemaMiddleware.InvokeAsync(IMiddlewareContext context)\r\n at HotChocolate.Utilities.MiddlewareCompiler1.ExpressionHelper.AwaitTaskHelper(Task task)\r\n at HotChocolate.Execution.Processing.ResolverTask.ExecuteResolverPipelineAsync(CancellationToken cancellationToken)\r\n at HotChocolate.Execution.Processing.ResolverTask.TryExecuteAsync(CancellationToken cancellationToken)" }
This is unfortunately a deal breaker for me from using this library. I believe it is generally encouraged to use objects for query parameters for flexibility. In my case, for instance, I have:
public class Query
{
public Order[] GetOrdersByUser(GetOrdersByUserInput input) { ... }
}
public record GetOrdersByUserInput(string userId, string orderType);
Then for my stitching:
extend type User {
orders(type: String!): [Order] @delegate(path: "orderByUser(input: { userId: $fields:id orderType: $arguments:type })")
}
This seems reasonable to have. But that produces the error described.
Rather disappointed there's no fix for this or no sign of one in any PRs or branches. Originally raised 18 months ago. It's definitely a deal-breaker as suggested above.
@PBTests We are actively working on stitching and this limitation will be removed in v13
Yes ... I hope that we have the first prototype end of next week. From that point forward we will have frequent previews. However, the first Gateway preview will not support everything we can today. This is a complete rewrite and brings many new features into the gateway with a much simpler setup. I will do a shoutout on slack to get feedback once we start with public testing.
@michaelstaib I've tried the previews up until 15, but this one is not fixed yet. Any news about when a fix for this is scheduled?
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.
I may have just encountered this issue when using an array of primitives (int[] in this case)?
Using the following type extensions:
extend type User {
roles: [Role] @delegate(schema: "roles", path: "roles(roleIds: $fields:roleIds)")
}
Where roleIds is an [int], trying to access this field results in:
"errors": [
{
"message": "Int cannot parse the given value of type `HotChocolate.Language.IntValueNode`."
}
]
I've tried this with the latest preview (13.0.0-preview.19) too, same error.
@jamiewinder can you share the type User ?
@PascalSenn Sure thing, it's simply:
type User {
userId: Int!
name: String!
roleIds: [Int!]!
}
And, if helpful, this is the roles query operation referred to in the delegate:
type Query {
roles(roleIds: [Int!]!): [Role!]!
}
Thanks.
@jamiewinder did you ever resolve this? I'm facing the same issue with an array of Guids.
@heymanitsmematt afraid not!
This is fixed with the new gateway of 13
We have moved this to 13.1 with the new gateway version.
Any ETA on this? I'm using 13.0.0-rc1, but problem still exists in that version..
HotChocolate.Stitching is now in legacy mode and is replaced by HotChocolate.Fusion. I am closing this issue as we essentially froze the fusion code.
You can join the beta for fusion no on slack.