如何在 Apollo graphql 中添加联合类型

How do I add union type in Apollo graphql

我提出这个问题是为了防止有人对如何在 Apollo 中添加 union / Polymorphic 类型感到好奇。希望这会让他们更轻松。

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

// 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)
  }))
);

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

union 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 Client

中创建 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 以检查响应中的类型。

Note: For those who are wondering why I'm not using GraphQL errors. It's because Apollo doesn't seem to handle errors well when it encounters a graphQL error. So for a work around I'm trying to return a custom ApiError in my response.

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

  1. 目前如果您想要使用 GraphQLError 的部分响应。 Apollo 不会缓存错误,因此如果您想稍后重新使用缓存的响应,您将无法获得完整的响应,因为错误已被删除。 (现在你不能显示正确的 UI 错误)
  2. 在 Apollo 中恢复 GraphQLError 将 return 一个简单的错误列表以及数据中错误所在的路径。因此,您需要验证错误发生在架构的哪一部分。但是,如果您按照上述说明进行操作,架构中就会出现错误。这样您就已经知道错误发生在架构的哪一部分。