【问题标题】:Different field types depending on args不同的字段类型取决于 args
【发布时间】:2017-09-05 05:20:30
【问题描述】:

我的数据库结构如下:

有一个Product 表:

id (integer)
manufacture_id (integer)
state (boolean)

还有一个Product_translations

product_id (integer)
language_id (integer)
name (string)
description (string)

在查询产品时,如果我提供语言 ID 作为参数,我希望能够直接接收名称和描述,或者如果我不提供,则接收包含所有语言 ID 和名称/描述的翻译列表'不提供语言 ID。

有没有办法在不创建两个不同类型和两个不同查询的情况下实现这一点?

【问题讨论】:

    标签: graphql graphql-js


    【解决方案1】:

    是和否。

    当您为查询指定返回类型时(我们称之为getProduct),您只能指定一种类型(或者联合或接口……稍后会详细介绍)。该类型 (Product) 将具有不可变的字段列表。当您向服务器发出请求时,您必须识别这些字段的子集才能让服务器返回。考虑到这一点,不可能(至少在本机上)发送查询让服务器根据这些参数返回不同的字段子集。

    也就是说,您可以做的是定义一个包含所有可能字段的类型,如下所示:

    type Product {
      id: ID!
      name: String
      description: String
      translations: [Translation!]!
    }
    

    然后在 getProduct 的解析器中,您可以从表中获取产品,然后检查是否提供了 language 作为参数。如果不是,请获取翻译列表并将产品的翻译属性设置为它。如果提供了语言,则仅获取该翻译,使用它来填充产品的名称和描述属性,并将翻译设置为空数组。

    这样,根据语言是否作为参数传入,您返回的产品将包含 A) 名称和描述为 null 以及填充的翻译列表;或 B) 名称和描述以及用于翻译的空数组。

    恕我直言,还有一个更优雅的替代方案:联合和接口

    和以前一样,您需要根据语言参数是否存在来适当地构造返回的对象。但是,您返回的不是类型,而是联合或接口,然后利用 __resolveType 字段返回特定类型(每个类型都有不同的字段)。

    这种方法有两个优点:第一,您可以避免返回不必要的空字段。第二,如果您使用 Apollo 作为客户端,它会自动添加一个 __typename 字段,您可以在客户端使用该字段来轻松确定查询实际返回的类型。

    这是一个您可以直接插入Launchpad 的示例:

    import { makeExecutableSchema } from 'graphql-tools';
    
    const typeDefs = `
      type Query {
        getProduct (id: ID, language: ID):  ProductInterface
      },
      type Product  implements ProductInterface {
        id: ID
        translations: [Translation!]!
      },
      type TranslatedProduct implements ProductInterface {
        id: ID
        name: String
        description: String
      },
      type Translation {
        language: ID
        name: String
        description: String
      },
      interface ProductInterface {
        id: ID
      }
    `;
    
    const products = [
      {
        id: '1',
        translations: [ 
          {
            language: '100',
            name: 'Foo',
            description: 'Foo!'
          },
          {
            language: '200',
            name: 'Qux',
            description: 'Qux!'
          }
        ]
      }
    ]
    
    const resolvers = {
      Query: {
        getProduct: (root, {id, language}, context) => {
          const product = products.find(p => p.id === id)
          if (language) {
            product.translation = product.translations.find(t => t.language === language)
          }
          return product
        },
      },
      ProductInterface: {
        __resolveType: (root) => {
          if (root.translation) return 'TranslatedProduct'
          return 'Product'
        }
      },
      TranslatedProduct: {
        name: (root) => root.translation.name,
        description: (root) => root.translation.description
      }
    };
    
    export const schema = makeExecutableSchema({
      typeDefs,
      resolvers,
    });
    

    然后您可以请求这样的查询:

    {
      getProduct (id: "1", language: "200") {
        __typename
        ... on Product {
          translations {
            language
            name
            description
          }
        }
        ... on TranslatedProduct {
          name
          description
        }
      }
    }
    

    【讨论】:

      猜你喜欢
      • 2021-09-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-06-03
      • 2020-04-23
      • 1970-01-01
      • 2021-06-22
      • 2011-07-01
      相关资源
      最近更新 更多