无法扩展远程 graphql 嵌套输入类型
Can't extending a remote graphql nested input type
graphql 服务 1 类型定义:
import { gql } from 'apollo-server';
const typeDefs = gql`
type Post {
postId: ID!
postTitle: String!
postContent: String!
postAuthorId: ID
}
input PostTag {
name: String!
}
input PostInput {
postTitle: String!
postContent: String!
postAuthorId: ID!
postTags: [PostTag!]!
}
type CommonResponse {
code: Int!
message: String!
}
type Query {
posts: [Post]!
}
type Mutation {
addPost(post: PostInput): CommonResponse!
}
`;
export { typeDefs };
现在,graphql 服务 2 想要从 graphql 服务 1 扩展 PostTag
输入类型,如下所示:
import { gql } from 'apollo-server';
const typeDefs = gql`
extend input PostTag {
color: String
}
`;
export { typeDefs };
我打印拼接方案,是正确的。
enum CacheControlScope {
PUBLIC
PRIVATE
}
type CommonResponse {
code: Int!
message: String!
}
type Mutation {
addPost(post: PostInput): CommonResponse!
}
type Post {
postId: ID!
postTitle: String!
postContent: String!
postAuthorId: ID
}
input PostInput {
postTitle: String!
postContent: String!
postAuthorId: ID!
postTags: [PostTag!]!
}
input PostTag {
name: String!
color: String
}
type Query {
posts: [Post]!
}
"""The `Upload` scalar type represents a file upload."""
scalar Upload
但是当客户端发送这样的突变时:
mutation{
addPost(post: {
postTitle: "ez2on",
postContent: "golang",
postAuthorId: "1",
postTags: [{
name: "222",
color: "red"
}]
}){
code
message
}
}
遇到这个错误:
{
"errors": [
{
"message": "Variable \"$_v0_post\" got invalid value { postTitle: \"ez2on\", postContent: \"golang\", postAuthorId: \"1\", postTags: [[Object]] }; Field \"color\" is not defined by type PostTag at value.postTags[0].",
"locations": [
{
"line": 7,
"column": 3
}
],
"path": [
"addPost"
],
"extensions": {
"code": "INTERNAL_SERVER_ERROR",
"exception": {
"errors": [
{
"message": "Variable \"$_v0_post\" got invalid value { postTitle: \"ez2on\", postContent: \"golang\", postAuthorId: \"1\", postTags: [[Object]] }; Field \"color\" is not defined by type PostTag at value.postTags[0].",
"locations": []
}
],
"stacktrace": [
"Error: Variable \"$_v0_post\" got invalid value { postTitle: \"ez2on\", postContent: \"golang\", postAuthorId: \"1\", postTags: [[Object]] }; Field \"color\" is not defined by type PostTag at value.postTags[0].",
" at new CombinedError (/Users/ldu020/workspace/github.com/mrdulin/apollo-graphql-tutorial/node_modules/graphql-tools/src/stitching/errors.ts:90:5)",
" at Object.checkResultAndHandleErrors (/Users/ldu020/workspace/github.com/mrdulin/apollo-graphql-tutorial/node_modules/graphql-tools/src/stitching/errors.ts:111:11)",
" at CheckResultAndHandleErrors.transformResult (/Users/ldu020/workspace/github.com/mrdulin/apollo-graphql-tutorial/node_modules/graphql-tools/src/transforms/CheckResultAndHandleErrors.ts:15:12)",
" at /Users/ldu020/workspace/github.com/mrdulin/apollo-graphql-tutorial/node_modules/graphql-tools/src/transforms/transforms.ts:37:45",
" at Array.reduce (<anonymous>)",
" at applyResultTransforms (/Users/ldu020/workspace/github.com/mrdulin/apollo-graphql-tutorial/node_modules/graphql-tools/src/transforms/transforms.ts:35:21)",
" at /Users/ldu020/workspace/github.com/mrdulin/apollo-graphql-tutorial/node_modules/graphql-tools/src/stitching/delegateToSchema.ts:104:12",
" at step (/Users/ldu020/workspace/github.com/mrdulin/apollo-graphql-tutorial/node_modules/graphql-tools/dist/stitching/delegateToSchema.js:31:23)",
" at Object.next (/Users/ldu020/workspace/github.com/mrdulin/apollo-graphql-tutorial/node_modules/graphql-tools/dist/stitching/delegateToSchema.js:12:53)",
" at fulfilled (/Users/ldu020/workspace/github.com/mrdulin/apollo-graphql-tutorial/node_modules/graphql-tools/dist/stitching/delegateToSchema.js:3:58)"
]
}
}
}
],
"data": null
}
请务必记住 makeRemoteExecutableSchema
只是 "uses the [provided] link to delegate requests to the underlying service"。当您从远程模式查询字段时,它会将对这些特定字段的请求委托给远程服务器,从而有效地重新路由请求。无论您将模式与其他模式拼接在一起,还是单独使用,都是如此。
模式拼接允许您组合任意数量的本地和远程模式。但是,任何远程模式仍将由各自的服务器解析其字段。
因为拼接合并了提供的模式的类型定义,所以您可以在一个模式中使用 extend
关键字来修改另一个模式的类型,即使它是一个远程模式。如果我们扩展对象类型,我们还可以 add some resolvers 来帮助解析我们添加的字段。
扩展远程模式的输入对象有点不同。没有 "resolving" 输入对象。相反,我们通过扩展它所做的就是说 "these fields are also valid"。然而,当我们请求一些将这个修改后的输入对象作为参数的远程模式字段时,这个字段的解析再次被委托给底层的远程模式。它获取修改后的输入对象,并在验证它时发现额外的字段并抛出错误。
换句话说,不可能像这样扩展输入类型。考虑一下,即使请求没有验证失败——即使您扩展了输入类型,原始解析器也没有改变,所以它必然不知道如何处理额外的输入类型字段。
注意:如果您执行上述操作但有两个 local 模式,扩展应该按预期工作,因为没有委托这个案例。不过,您仍然需要一个不一定知道如何处理新输入对象字段的解析器。
graphql 服务 1 类型定义:
import { gql } from 'apollo-server';
const typeDefs = gql`
type Post {
postId: ID!
postTitle: String!
postContent: String!
postAuthorId: ID
}
input PostTag {
name: String!
}
input PostInput {
postTitle: String!
postContent: String!
postAuthorId: ID!
postTags: [PostTag!]!
}
type CommonResponse {
code: Int!
message: String!
}
type Query {
posts: [Post]!
}
type Mutation {
addPost(post: PostInput): CommonResponse!
}
`;
export { typeDefs };
现在,graphql 服务 2 想要从 graphql 服务 1 扩展 PostTag
输入类型,如下所示:
import { gql } from 'apollo-server';
const typeDefs = gql`
extend input PostTag {
color: String
}
`;
export { typeDefs };
我打印拼接方案,是正确的。
enum CacheControlScope {
PUBLIC
PRIVATE
}
type CommonResponse {
code: Int!
message: String!
}
type Mutation {
addPost(post: PostInput): CommonResponse!
}
type Post {
postId: ID!
postTitle: String!
postContent: String!
postAuthorId: ID
}
input PostInput {
postTitle: String!
postContent: String!
postAuthorId: ID!
postTags: [PostTag!]!
}
input PostTag {
name: String!
color: String
}
type Query {
posts: [Post]!
}
"""The `Upload` scalar type represents a file upload."""
scalar Upload
但是当客户端发送这样的突变时:
mutation{
addPost(post: {
postTitle: "ez2on",
postContent: "golang",
postAuthorId: "1",
postTags: [{
name: "222",
color: "red"
}]
}){
code
message
}
}
遇到这个错误:
{
"errors": [
{
"message": "Variable \"$_v0_post\" got invalid value { postTitle: \"ez2on\", postContent: \"golang\", postAuthorId: \"1\", postTags: [[Object]] }; Field \"color\" is not defined by type PostTag at value.postTags[0].",
"locations": [
{
"line": 7,
"column": 3
}
],
"path": [
"addPost"
],
"extensions": {
"code": "INTERNAL_SERVER_ERROR",
"exception": {
"errors": [
{
"message": "Variable \"$_v0_post\" got invalid value { postTitle: \"ez2on\", postContent: \"golang\", postAuthorId: \"1\", postTags: [[Object]] }; Field \"color\" is not defined by type PostTag at value.postTags[0].",
"locations": []
}
],
"stacktrace": [
"Error: Variable \"$_v0_post\" got invalid value { postTitle: \"ez2on\", postContent: \"golang\", postAuthorId: \"1\", postTags: [[Object]] }; Field \"color\" is not defined by type PostTag at value.postTags[0].",
" at new CombinedError (/Users/ldu020/workspace/github.com/mrdulin/apollo-graphql-tutorial/node_modules/graphql-tools/src/stitching/errors.ts:90:5)",
" at Object.checkResultAndHandleErrors (/Users/ldu020/workspace/github.com/mrdulin/apollo-graphql-tutorial/node_modules/graphql-tools/src/stitching/errors.ts:111:11)",
" at CheckResultAndHandleErrors.transformResult (/Users/ldu020/workspace/github.com/mrdulin/apollo-graphql-tutorial/node_modules/graphql-tools/src/transforms/CheckResultAndHandleErrors.ts:15:12)",
" at /Users/ldu020/workspace/github.com/mrdulin/apollo-graphql-tutorial/node_modules/graphql-tools/src/transforms/transforms.ts:37:45",
" at Array.reduce (<anonymous>)",
" at applyResultTransforms (/Users/ldu020/workspace/github.com/mrdulin/apollo-graphql-tutorial/node_modules/graphql-tools/src/transforms/transforms.ts:35:21)",
" at /Users/ldu020/workspace/github.com/mrdulin/apollo-graphql-tutorial/node_modules/graphql-tools/src/stitching/delegateToSchema.ts:104:12",
" at step (/Users/ldu020/workspace/github.com/mrdulin/apollo-graphql-tutorial/node_modules/graphql-tools/dist/stitching/delegateToSchema.js:31:23)",
" at Object.next (/Users/ldu020/workspace/github.com/mrdulin/apollo-graphql-tutorial/node_modules/graphql-tools/dist/stitching/delegateToSchema.js:12:53)",
" at fulfilled (/Users/ldu020/workspace/github.com/mrdulin/apollo-graphql-tutorial/node_modules/graphql-tools/dist/stitching/delegateToSchema.js:3:58)"
]
}
}
}
],
"data": null
}
请务必记住 makeRemoteExecutableSchema
只是 "uses the [provided] link to delegate requests to the underlying service"。当您从远程模式查询字段时,它会将对这些特定字段的请求委托给远程服务器,从而有效地重新路由请求。无论您将模式与其他模式拼接在一起,还是单独使用,都是如此。
模式拼接允许您组合任意数量的本地和远程模式。但是,任何远程模式仍将由各自的服务器解析其字段。
因为拼接合并了提供的模式的类型定义,所以您可以在一个模式中使用 extend
关键字来修改另一个模式的类型,即使它是一个远程模式。如果我们扩展对象类型,我们还可以 add some resolvers 来帮助解析我们添加的字段。
扩展远程模式的输入对象有点不同。没有 "resolving" 输入对象。相反,我们通过扩展它所做的就是说 "these fields are also valid"。然而,当我们请求一些将这个修改后的输入对象作为参数的远程模式字段时,这个字段的解析再次被委托给底层的远程模式。它获取修改后的输入对象,并在验证它时发现额外的字段并抛出错误。
换句话说,不可能像这样扩展输入类型。考虑一下,即使请求没有验证失败——即使您扩展了输入类型,原始解析器也没有改变,所以它必然不知道如何处理额外的输入类型字段。
注意:如果您执行上述操作但有两个 local 模式,扩展应该按预期工作,因为没有委托这个案例。不过,您仍然需要一个不一定知道如何处理新输入对象字段的解析器。