Open xunnanxu opened 6 years ago
It's possible to get the DataFetchingEnvironment (graphql.schema.DataFetchingEnvironment) in any rejoiner method (query/mutation/modification). This can be used to access a "context" object that is set when the query is executed.
Here the context is set: https://github.com/google/rejoiner/blob/master/examples/src/main/java/com/google/api/graphql/examples/streaming/graphqlserver/GraphQlGrpcServer.java#L113
Here the DataFetchingEnvironment in injected in (it contains the context).
You can think of rejoiner methods as datafetchers.
I'm not 100% sure what you are trying to do, does this help?
Hi @siderakis thanks for the quick reply.
I think unfortunately the answer is no.
Using https://graphql.org/learn/execution/#root-fields-resolvers as a reference, the context
object here will apply to all resolvers whereas the grandparent id I mentioned needs to be resolver specific (i.e. different values applied to different resolvers). The solution I originally referenced is achieved by enhancing the obj
param in resolver, and that translated to rejoiner language means to dynamically add fields to proto message such that deeply nested object can get ids more than one level above through @SchemaModification
. This does not seem achievable due to rejoiner only allows proto message to be returned not some interim custom data structure.
As an example assuming the query is like
allPeople(startDate, endDate) {
company {
id
department {
id
team {
id
employee {
id
}
}
}
}
}
And let's assume each level is 1-many. The context
solution can pass startDate
and endDate
to each layer because they are all the same. But in case employee needs department id for grpc call that becomes tricky (assuming employee
proto only has team
id and team
has department
id). We cannot use the global context because different employee would belong to different department.
In this case the employee field depends on team and department. If there was another way to reach the team proto without having department as a parent employee wouldn't be resolvable, right?
The best thing I can think of right now is to replace the team field with a TeamAndDepartment proto. That proto would have two fields, one for the team and one for the department. You could then remove the department field from the schema.
allPeople(startDate, endDate) {
company {
id
department {
id
teamAndDepartment {
id
employee {
id
}
}
}
}
}
Sorry it's not a great solution.
Maybe a new return type could added ProtoAndContext
.
class ProtoAndContext<M extends message> {
M protoMessage;
Object context;
}
In this case the framework would only use the protoMessage field for the schema and could supply the context to downstream "resolvers".
Would this solve the general case, or just the example you gave?
Yeah but that bloats the return schema, which makes it messy (or you'd have to somehow remove the department id at team level to avoid that being returned to user).
ProtoAndContext
might work but that defeats the strong typing purpose.
I wonder if it makes sense to allow methods to return arbitrary object that wraps a proto msg like
interface EnhancedContext<T extends Message> {
T getMessage();
}
that way rejoiner can call that method to behave the same way today (and throws an exception if it can't). It's pretty much what you proposed but users would need to define their class rather than having Object
as the type (or you could probably use generic for context
).
In the js counterpart, there's a way to add arbitrary context info to a resolve context and thus you can relay the information all the way down as described in this issue: https://github.com/graphql/graphql-js/issues/1098
However in rejoiner since all fields are strictly typed to proto msgs or java native types, and there's no resolver exposed, it doesn't seem that use case is supported, unless one flattens the grandparent context onto the proto message (e.g. when schema is foo -> bar -> baz, let baz have foo's id), which is doable but doesn't seem like a good practice?