Recipe for Schema Stitching
Closed this issue ยท 12 comments
Upfront: Mesh looks like a great tool. Perhaps, non-trivial examples will be configurable with time. As for now, I've tried to do a simple stitching, correlating on the Id passed down from the parent resolver (see repo):
{
widgets {
id
gadgets {
name
}
}
}where the extra resolver uses the Id from the parent object:
const resolvers = {
Widget: {
async gadgets( /*parent*/ { id }, /*args*/ _, { Service2 }) {
return await Service2.api.gadgets({
parentId: id,
});
}
}
};
module.exports = { resolvers };However, this is problematic, as the Mesh cannot know it has to fetch the Id field in the widgets resolver. If one comments out the id, the query fails (with or without federation transform):
{
widgets {
# id # will not be queried in `widgets`
gadgets {
name
}
}
}with federation on:
{
"errors": [
{
"message": "Variable `parentId` of type `Int!` must not be null.",
"locations": [],
"path": [
"gadgets"
],
"extensions": {
"variableName": "parentId",
"code": "EXEC_NON_NULL_VIOLATION"
}
},
...without federation on:
{
"error": {
"errors": [
{
"message": "Cannot return null for non-nullable field Query.widgets.",
"locations": [
{
"line": 2,
"column": 3
}
],
"path": [
"widgets"
]
}
],
"data": null
}
}expected behaviour would be successful resolver execution like when querying with the Id of the parent (without "id": 1):
{
"data": {
"widgets": [
{
"gadgets": [
{
"name": "Gadget 1/1"
},
{
"name": "Gadget 1/2"
},
{
"name": "Gadget 1/3"
}
]
},
...
]
}
}This looks similar to the openapi-location-weather example, which failed to run due to certificate issues, but I presume it suffers from the same problem, as data is taken from the parent objects, and I couldn't find any special configuration to say that the fields must be fetched, even if not present in the query.
In json-schema-covid the additional resolver errors with a helpful message: "countryRegion is a needed field at case level to get population info" but ideally it's not the user experience GraphQL users expect (expecting to fetch only what they need in the result data structure)
Thanks @d-led for opening this issue!
Could you try to use selectionSet to provide required fields like below?
module.exports = {
Widget: {
gadgets: {
selectionSet: `{ id }`
resolve: ( /*parent*/ { id }, /*args*/ _, { Service2 }) => Service2.api.gadgets({
parentId: id,
}),
}
}
};query:
{
widgets {
# id # will not be queried in `widgets`
gadgets {
name
}
}
}with or without selectionSet:
{
"errors": [
{
"message": "Variable \"$_v0_parentId\" of required type \"Int!\" was not provided.",
"locations": [],
"path": [
"widgets",
0,
"gadgets"
]
},
{
"message": "Variable \"$_v0_parentId\" of required type \"Int!\" was not provided.",
"locations": [],
"path": [
"widgets",
1,
"gadgets"
]
},
{
"message": "Variable \"$_v0_parentId\" of required type \"Int!\" was not provided.",
"locations": [],
"path": [
"widgets",
2,
"gadgets"
]
},
{
"message": "Variable \"$_v0_parentId\" of required type \"Int!\" was not provided.",
"locations": [],
"path": [
"widgets",
3,
"gadgets"
]
},
{
"message": "Variable \"$_v0_parentId\" of required type \"Int!\" was not provided.",
"locations": [],
"path": [
"widgets",
4,
"gadgets"
]
}
],
"data": {
"widgets": [
{
"gadgets": null
},
{
"gadgets": null
},
{
"gadgets": null
},
{
"gadgets": null
},
{
"gadgets": null
}
]
}
}see the commit linked above (upgraded all dependencies)
@d-led #510 (comment)
I submitted some changes. You can try the latest canary version but you should use additionalTypeDefs near additionalResolvers instead of extend transform.
Could you try and let me know if it works?
installed something, and it works!
pushed the commit with the yarn.lock. My initial goal was to achieve the same with federation, but the current example only adds federation to one of the services. Still couldn't get the mesh config right. Do you think, the same scenario could work with federation as well?
P.S. superb evolution of the mesh!
I think so. First you need to convert your sources to federated services using Federation transform then add federation merger on top.
You can see how nonfederated graphql service transformed in that example
https://github.com/Urigo/graphql-mesh/tree/master/examples/federation-example
Thank you for your feedback and opening this issue :)
Available in 0.2.0. So, for federation let's move this discussion into different issue. Thank you for your collaboration so far! It helped us to improve Mesh a lot!