是和否。
當您爲查詢指定返回類型(我們稱之爲getProduct
)時,您只能指定一種類型(或者聯合體或接口,稍後會詳細介紹)。該類型(Product
)將具有不可變的字段列表。當您向服務器發出請求時,您必須標識這些字段的子集才能讓服務器返回。考慮到這一點,根據這些參數,服務器返回不同的字段子集是不可能的(至少在本地)發送查詢。
這就是說,你可以做的是定義一個類型,其中包括所有可能的領域,如:
type Product {
id: ID!
name: String
description: String
translations: [Translation!]!
}
然後你解析爲getProduct
內,您可以從表中提取產品和然後檢查是否提供language
作爲參數。如果不是,請獲取翻譯列表並將產品的翻譯屬性設置爲該翻譯屬性。如果提供了語言,只提取該翻譯,使用它來填充產品的名稱和描述屬性,並將翻譯設置爲空數組。
通過這種方式,根據語言是否作爲參數傳入,您返回的產品將包含A)空名稱和描述以及已填充的翻譯列表;或者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
}
}
}