graphql-tools
graphql-tools copied to clipboard
stitchSchemas with namespaced queries and mutations
Discussed in https://github.com/ardatan/graphql-tools/discussions/4042
Originally posted by wmwart December 22, 2021 Good afternoon. I have a question about using stitchSchemas with namespaced queries and mutations. I have 2 remote services:
###AssetService
type Asset {
id: ID!
name: String!
description: String
...
}
type AssetPayload {
item: Asset
}
type AssetsPayload {
items: [Asset!]
pageInfo: PaginationInfo
}
input AssetWhereUniqueInput {
id: ID
}
type AssetQuery {
getOne(where: AssetWhereUniqueInput!): AssetPayload! @withAuth
getList(filter: AssetFilter = {} sort: [AssetSort! ] = [{id: asc}] page: Int = 1 perPage: Int = 100): AssetsPayload! @withAuth
getMany(ids: [ID!]!): AssetsPayload! @withAuth
}
type AssetMutation {
create(input: AssetCreateInput!): AssetPayload! @withAuth
update( where: AssetWhereUniqueInput! input: AssetUpdateInput!): AssetPayload! @withAuth
remove(where: AssetWhereUniqueInput!): AssetPayload! @withAuth
restore(where: AssetWhereUniqueInput!): AssetPayload! @withAuth
delete(where: AssetWhereUniqueInput!): AssetPayload! @withAuth
}
type Query {
Asset: AssetQuery
}
type Mutation {
Asset: AssetMutation
}
...
and
### AssetClassService
type AssetClass {
id: ID!
name: String!
assets: [AssetWithoutAssetClass!]!
}
type AssetClassPayload {
item: AssetClass
}
type AssetClassesPayload {
items: [AssetClass!]
pageInfo: PaginationInfo
}
type AssetClassQuery {
getOne(where: AssetClassWhereUniqueInput!): AssetClassPayload! @withAuth
getList(filter: AssetClassFilter = {} sort: [AssetClassSort! ] = [{id: asc}] page: Int = 1 perPage: Int = 100): AssetClassesPayload! @withAuth
getMany(ids: [ID!]): [AssetClass!]!
}
type AssetClassMutation {
create(input: AssetClassCreateInput!): AssetClassPayload! @withAuth
update( where: AssetClassWhereUniqueInput! input: AssetClassUpdateInput!): AssetClassPayload! @withAuth
remove(where: AssetClassWhereUniqueInput!): AssetClassPayload! @withAuth
restore(where: AssetClassWhereUniqueInput!): AssetClassPayload! @withAuth
delete(where: AssetClassWhereUniqueInput!): AssetClassPayload! @withAuth
}
type Asset {
id: ID!
assetClass: AssetClass
}
type AssetQuery {
getMany(ids: [ID!]!): [Asset!]!
}
type Query {
AssetClass: AssetClassQuery
Asset: AssetQuery
}
type Mutation {
AssetClass: AssetClassMutation
}
Thus, when using stitchSchemas in my proxy service, a function for obtaining a stitched schema appeared:
const makeGatewaySchema = async () => {
const assetServiceExecutor = makeRemoteExecutor('http://localhost:7702', { log: true });
const assetClassServiceExecutor = makeRemoteExecutor('http://localhost:7703', { log: true });
return stitchSchemas({
subschemas: [
{
schema: await introspectSchema(assetServiceExecutor),
executor: assetServiceExecutor,
merge: {...}
},
{
schema: await introspectSchema(assetClassServiceExecutor),
executor: assetClassServiceExecutor,
merge: {...}
},
],
});
}
Which allows me to fulfill the request:
query Items {
Asset {
getList {
items {
id
name
assetClass {
id
name
description
}
}
}
}
}
However, none of the combination of merge options of these subcircuits specified in the documentation and examples of use returned me the required answer.
I assume that the problem is precisely in the namespaced types.
Please help me specify the correct settings for merge options or share a link to a solution to a similar problem
I used different options for describing fieldName with merge AssetClass from AssetClassService:
fieldName: 'AssetClass.getMany',
fieldName: { AssetClass: "getMany"},
fieldName: "getMany",
and other. But nothing happened
In addition, the query that I indicated above gave the result without additional merge options, but except for the assetClass {..., assetClass: null} field.
However, when I added to the AssetClassService in the schema
type AssetQuery {
getMany(ids: [ID!]): AssetsPayload! @withAuth
}
type Query {
Asset: AssetQuery
}
The request stopped returning data.
{
"data": {
"Asset": null
}
}
test various options ...
return stitchSchemas({
subschemas: [
{
schema: await introspectSchema(assetServiceExecutor),
executor: assetServiceExecutor,
merge: {
Asset: {
canonical: true,
selectionSet: '{ id }',
fieldName: 'Asset.getList',
args: ({ id }) => {
return { id }
},
},
AssetClass: {
selectionSet: '{ id }',
fieldName: 'getMany',
key: (root, args, context, info) => {
return root.id
},
argsFromKeys: (root, args, context, info) => {
return { ids: root.ids }
},
}
}
},
{
schema: await introspectSchema(assetClassServiceExecutor),
executor: assetClassServiceExecutor,
batch: true,
merge: {
Asset: {
selectionSet: '{ id assets }',
fieldName: 'Asset._resolveReference',
key: (root, args, context, info) => {
return root.assets
},
argsFromKeys: (root, args, context, info) => {
return { ids: root.assets }
},
},
AssetClass: {
canonical: true,
selectionSet: '{ id }',
fieldName: 'AssetClass.getMany',
key: (root, args, context, info) => {
return root.id
},
argsFromKeys: (root, args, context, info) => {
return { ids: root.ids }
},
}
}
},
],
});
}
Thanks for reporting this issue. Would you create a PR with a failing test?
@ardatan , Here is a repository with two examples: https://github.com/denisgnt/gateway-service-example.