-
-
Notifications
You must be signed in to change notification settings - Fork 809
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
How to stitch from a concrete to an abstract type? #751
Comments
I guess I can utilise the new author {
email
} to: author {
... on User {
email
}
} I'm not familiar with how graphql's AST works so I hope someone can shed some light on this! |
Solved the problem. I created a new transformer called Here's the implementation: import { Transform, Request } from 'graphql-tools';
import {
GraphQLSchema,
TypeInfo,
visit,
visitWithTypeInfo,
parse,
print,
InlineFragmentNode,
Kind,
SelectionSetNode,
SelectionNode,
} from 'graphql';
export class WrapFieldsInFragment implements Transform {
private targetSchema: GraphQLSchema;
private parentType: string;
private targetType: string;
constructor(
targetSchema: GraphQLSchema,
parentType: string,
targetType: string,
) {
this.targetSchema = targetSchema;
this.parentType = parentType;
this.targetType = targetType;
}
public transformRequest(originalRequest: Request) {
const typeInfo = new TypeInfo(this.targetSchema);
const document = visit(
originalRequest.document,
visitWithTypeInfo(typeInfo, {
// tslint:disable-next-line function-name
[Kind.SELECTION_SET]: (
node: SelectionSetNode,
): SelectionSetNode | null | undefined => {
const parentType = typeInfo.getParentType();
let selections = node.selections;
if (parentType && parentType.name === this.parentType) {
const fragment = parse(
`fragment ${this.targetType}Fragment on ${
this.targetType
} ${print(node)}`,
);
let inlineFragment: InlineFragmentNode;
for (const definition of fragment.definitions) {
if (definition.kind === Kind.FRAGMENT_DEFINITION) {
inlineFragment = {
kind: Kind.INLINE_FRAGMENT,
typeCondition: definition.typeCondition,
selectionSet: definition.selectionSet,
};
}
}
selections = selections.concat(inlineFragment);
}
if (selections !== node.selections) {
return {
...node,
selections,
};
}
},
}),
);
return { ...originalRequest, document };
}
} To use it: {
...
Chirp: {
author: {
fragment: `fragment ChirpFragment on Chirp { authorId }`,
resolve(chirp, args, context, info) {
return info.mergeInfo.delegateToSchema({
schema: authorSchema,
operation: 'query',
fieldName: 'node',
args: {
id: chirp.authorId,
},
context,
info,
transforms: [new WrapFieldsInFragment(authorSchema, 'Node', 'User')]
});
},
},
},
} Then it will transform the request in the {
node(id: "id-1") {
id
email
}
} to: {
node(id: "id-1") {
id
email
... on User {
id
email
}
}
} Then the result will include all fields that a specific type contains. |
@josephktcheung Any reason why not to create a pull request with this quite useful transform? |
Hi @saerdnaer, Feel free to take my code and create a pull request, I'm busy working on my own project so I don't have time to write the test cases and make a pull request :) Best, |
This transform should be built in like ExpandAbstractTypes, which allows delegation from abstract types in gateway to concrete in subschema, the reverse should also be built in. |
* ExpandAbstractTypes to check transformed subschema An abstract type may be present in the target schema, but renamed. ExpandAbstractTypes expands the abstract types not present in the target schema, but it should check the transformed target schema, to not be misled by renaming. This may require manually passing the transformed schema in some cases. The default can stay to assume no renaming. Within stitched schemas, the correct transformed schema can be saved to and then read from info.mergeInfo.transformedSchema. * move ICreateRequest to delegate package with ICreateRequestFromInfo * Add WrapConcreteTypes transform = fixes #751 * allow redelegation of nested root query fields in some circumstances nested root fields may not always successfully stitch to subschemas, for example when the root field is a new abstract field stitching to a concrete field or the reverse * provide transformedSchema argument in more instances = changes CreateResolverFn signature to take an options argument of type ICreateResolverOptions
@yaacovCR Does the transform apply automatically or did you forget to add an export named WrapConcreteTypes in https://github.com/ardatan/graphql-tools/blob/master/packages/delegate/src/transforms/index.ts ? |
It applies automatically but I also meant to add an export. PR welcome, traveling.... |
Hi,
Not sure if it's asked before. I'm currently stitching 2 graphql schemas together but I'm not sure how can I transform a
node
interface query result to a concrete type.Here's a modified apollo stitching example. https://launchpad.graphql.com/0vjzzp49r5
Let's say both
Chirp
andAuthor
implementNode
interface. Instead of providingchirpById
andauthorById
, both schemas only providenode
query to query any item that implementsNode
interface.And again we want to extend both
Chirp
andAuthor
type:Then in the resolver map, here's how I resolve
Chirp
'sauthor
field by querying thenode
query from theAuthor
schema...Now if I perform the following query on the stitched schema, the author's email returns null:
I can get the author's email by doing something like this but it's not desirable:
Is it possible to make
NotWorking
query works i.e. gettingUser
's fields without using inline fragments? Thanks!The text was updated successfully, but these errors were encountered: