3

我创建了这个问题以防有人对如何在 Apollo中添加联合/多态类型感到好奇。希望这将使他们更容易。

在此示例中,我希望响应为 aWorksheetApiError

// typedefs.js
export default [`
  schema {
    query: Query
  }

  type Query {
    worksheet(id: String!): Worksheet | Error
  }

  type Worksheet {
    id: String!
    name String
  }

  type ApiError {
    code: String!
    message: String!
  }
`];

// resolvers.js
export default {
  Query: {
    worksheet(_, args, { loaders }) {
      return loaders.worksheet.get(args.id).catch(() => {
        // ApiError
        return {
          code: '1',
          message: 'test'
        }
      });
    }
  }
};

// Express Server 
import { graphqlExpress } from 'apollo-server-express';
import { makeExecutableSchema } from 'graphql-tools';
import typeDefs from './typedefs';
import resolvers from './resolvers';

...


app.post(
  '/graphql',
  graphqlExpress(req => ({
    makeExecutableSchema({ typeDefs, resolvers }),
    context: mkRequestContext(req.ctx, req.log),
    formatError: formatGraphQLError(req.ctx, req.log)
  }))
);
4

1 回答 1

4

在 GraphQL 中,要在 typedefs 中添加联合类型,您必须定义联合

IEunion WorksheetOrError = Worksheet | ApiError

// typedefs.js
export default [
  `
  schema {
    query: Query
  }

  type Query {
    worksheet(id: String!): WorksheetOrError
  }

  union WorksheetOrError = Worksheet | ApiError 

  type Worksheet {
    id: String!
    name String
  }

  type ApiError {
    code: String!
    message: String!
  }
`];

在解析器中,您必须为具有属性__resolveType的联合类型定义一个解析器。这将有助于告诉 GraphQL 执行器结果是哪种类型。

 // resolvers.js
export default {
  Query: {
    worksheet() {
      ... 
    }
  },
  WorksheetOrError: {
    __resolveType(obj) {
      if (obj.id) {
        return 'Worksheet';
      }

      if (obj.code) {
        return 'ApiError';
      }

      return null;
    }
  },
};

Apollo 客户端中创建 GraphQL 查询

// Your application code. 

// This is my Worksheet Query in my React code.
const WorksheetQuery = gql`
  query GetWorksheet($worksheetId: String!) {
    worksheet(id: $worksheetId) {
      ... on Worksheet {
        id
        name
      }
      ... on ApiError {
        code
        message
      }
    }
  }

现在您可以检查__typename以检查响应中的类型。

注意:对于那些想知道我为什么不使用GraphQL 错误的人。这是因为 Apollo 在遇到 graphQL 错误时似乎并没有很好地处理错误。因此,为了解决问题,我试图ApiError在我的回复中返回一个自定义。

使用带有错误类型的联合很好有几个原因。

  1. 目前,如果您想要 GraphQLError 的部分响应。Apollo 不会缓存错误,因此如果您想稍后重新使用缓存的响应,您将不会获得完整的响应,因为错误已被删除。(现在您无法显示带有错误的正确 UI)
  2. 在 Apollo 中获取 GraphQLError 将返回一个平面错误列表,其中包含错误在数据中的路径。因此,您需要验证错误发生在架构的哪一部分。但是,如果您按照上面的说明进行操作,则架构中已经存在错误。这样您就已经知道错误发生在架构的哪一部分。
于 2018-04-23T02:39:52.003 回答