使用 graphql-tools 打印远程模式时出现 getDirectives 错误

Posted

技术标签:

【中文标题】使用 graphql-tools 打印远程模式时出现 getDirectives 错误【英文标题】:getDirectives error when printing remote schema with graphql-tools 【发布时间】:2019-08-26 17:54:00 【问题描述】:

我有两个节点服务器都通过express-graphql 服务于graphql。 我希望我的第一台服务器将其架构与第二台服务器的架构缝合。

我已按照以下说明操作:https://www.apollographql.com/docs/graphql-tools/remote-schemas

因为我正在使用 graphql-tools。

我能够从我的第二个节点服务器中检索架构,但是一旦我尝试打印它(仅使用 console.log)我就会收到此错误:

Uncaught exception TypeError: schema.getDirectives is not a function
    at printFilteredSchema (/Users/cchabert/git-repo/client-configuration-api/node_modules/graphql/utilities/schemaPrinter.js:61:27)
    at Object.printSchema (/Users/cchabert/git-repo/client-configuration-api/node_modules/graphql/utilities/schemaPrinter.js:47:10)
    at makeRemoteExecutableSchema (/Users/cchabert/git-repo/client-configuration-api/node_modules/graphql-tools/dist/stitching/makeRemoteExecutableSchema.js:60:30)
    at schema (/Users/cchabert/git-repo/client-configuration-api/app/api/schema.js:68:24)
    at module.exports (/Users/cchabert/git-repo/client-configuration-api/app/routes.js:102:13)
    at Object.<anonymous> (/Users/cchabert/git-repo/client-configuration-api/app/index.js:15:20)
    at Module._compile (internal/modules/cjs/loader.js:799:30)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:810:10)
    at Module.load (internal/modules/cjs/loader.js:666:32)
    at tryModuleLoad (internal/modules/cjs/loader.js:606:12)
    at Function.Module._load (internal/modules/cjs/loader.js:598:3)
    at Function.Module.runMain (internal/modules/cjs/loader.js:862:12)
    at internal/main/run_main_module.js:21:11

这会导致服务器死机,但我也能以某种方式看到架构:

received schema:  "_queryType":"Query","_mutationType":"Mutation",
"_subscriptionType":null,"_directives":["@skip","@include","@deprecated"],
"_typeMap":"Query":"Query","String":"String","Client":"Client",
"ID":"ID","DateTime":"DateTime",[...]

我确实在远程架构定义中看到了 _directives 字段,但文档并不清楚如何处理这个问题。

我也查看了graphql-tools repo 的 github 问题,但找不到任何东西。

这是一个代码sn-p:

const 
  addMockFunctionsToSchema,
  makeExecutableSchema,
  makeRemoteExecutableSchema,
  introspectSchema,
  mergeSchemas
 = require('graphql-tools')
const _ = require('lodash)
const  createHttpLink  = require('apollo-link-http')
const fetch = require('node-fetch')

[..]
const customFetch = (uri, options = ) => 
  const httpOptions = _.merge(options, 
    headers: 
      'Content-type': 'application/json'
    
  )
  return fetch(uri, httpOptions)


function schema() 
  const Query = `
    type Query 
      _empty: String
    
    type Mutation 
      _empty: String
    
  `
  const resolvers = 

  const mocks = 

  const localSchema = makeExecutableSchema(
    typeDefs: [Query, [...]],
    resolvers: [resolvers, [...]]
  ) // by itself this schema works without any issues

  const mergedMocks = _.merge(mocks, [...])

  addMockFunctionsToSchema(
    schema: localSchema,
    mocks: mergedMocks,
    preserveResolvers: true
  )

  const infoApiLink = createHttpLink( uri, fetch: customFetch )

  const remoteSchema = makeRemoteExecutableSchema(
    schema: introspectSchema(infoApiLink).then(remoteSchema => 
      console.log('received schema: ', JSON.stringify(remoteSchema))
      return remoteSchema
    ),
    link: infoApiLink
  )

  return mergeSchemas( schemas: [localSchema, remoteSchema] )


module.exports = 
  schema

我还想只使用 https://github.com/apollographql/graphql-tools/blob/master/docs/source/remote-schemas.md#--introspectschemafetcher-context 中提到的 Promises(无 async/await)来完成这项工作

欢迎提出任何建议。

【问题讨论】:

【参考方案1】:

makeRemoteExecutableSchema 应该传递一个 GraphQLSchema 的实例,但你没有这样做——你正在做的是传递一个 Promise,它将解析为 GraphQLSchema,这是行不通的。当您调用introspectSchema 时,它必须进行自省调用,这是异步完成的。它返回一个 Promise,该 Promise 解析为生成的 GraphQLSchema 对象。我们需要使用awaitthen 来获取该值,然后我们可以根据需要使用它。

没有 async/await 的不必要的混乱方式:

function schema () 
  // ... rest of your code
  return introspectSchema(infoApiLink).then(schema => 
    const remoteSchema = makeRemoteExecutableSchema( schema, link: infoApiLink )
    return mergeSchemas( schemas: [localSchema, remoteSchema] )
  )

或者使用异步/等待:

async function schema () 
  // ... rest of your code
  const schema = await introspectSchema(infoApiLink)
  const remoteSchema = makeRemoteExecutableSchema( schema, link: infoApiLink )
  return mergeSchemas( schemas: [localSchema, remoteSchema] )


无论哪种方式,请记住,通过调用 schema 函数,您将返回一个 Promise,该 Promise 将解析为 mergeSchemas 返回的值。因此,在您可以导入函数、调用它并直接使用结果之前,您将不得不再次使用 thenawait 来获取 Promise 首先解析的值:

import  schema  from './some-module'

schema()
  .then(schema => 
    const server = new ApolloServer( schema )
    server.listen()
  )
  .catch(error => 
    // handle the Promise rejecting
  )

【讨论】:

谢谢,昨天来晚了,有时候你只是需要一双眼睛。

以上是关于使用 graphql-tools 打印远程模式时出现 getDirectives 错误的主要内容,如果未能解决你的问题,请参考以下文章

使用最新版本的 Apollo 和 GraphQL 工具进行远程模式拼接

如何使用 graphql-tools 调用查询

如何使用 graphql-tools 使用或解析枚举类型?

GraphQL 拼接 VS 合并模式

typeDefs 必须只包含字符串、文档、模式或函数,得到对象

“graphql-tools”中的嵌套解析器不起作用