2017-08-23 40 views
2

我們處於GraphQL Query的響應必須返回對象的某些動態屬性的情況。在我們的情況下,我們無法預先定義所有可能的屬性 - 所以它必須是動態的。帶有基於參數的動態字段的GraphQL ObjectType

正如我們認爲有兩個選擇來解決它。

const MyType = new GraphQLObjectType({ 
    name: 'SomeType', 
    fields: { 
    name: { 
     type: GraphQLString, 
    }, 
    elements: { 
     /* 
     THIS is our special field which needs to return a dynamic object 
     */ 
    }, 
    // ... 
    }, 
}); 

正如您在示例代碼中看到的那樣,元素是必須返回對象的屬性。當解決這個可能是一個響應:

{ 
    name: 'some name', 
    elements: { 
    an_unkonwn_key: { 
     some_nested_field: { 
     some_other: true, 
     }, 
    }, 
    another_unknown_prop: 'foo', 
    }, 
} 

1)返回一個「任意對象」

我們只能返回任何對象 - 所以GraphQL不需要知道哪些字段的對象了。當我們告訴GraphQL該字段是GraphQlObjectType類型時,它需要定義字段。因此,似乎無法告訴GraphQL有人只是一個對象。

佛這一點,我們已經改變了它這樣的:

elements: { 
     type: new GraphQLObjectType({ name: 'elements' }); 
    }, 

2)我們可以,因爲它在功能

定義動態字段屬性。當我們定義字段的功能,我們可以定義我們的對象動態。但是該字段函數需要一些信息(在我們的例子中將傳遞給元素的信息),我們需要訪問它們來構建字段對象。

例子:

const MyType = new GraphQLObjectType({ 
    name: 'SomeType', 
    fields: { 
    name: { 
     type: GraphQLString, 
    }, 
    elements: { 
     type: new GraphQLObjectType({ 
     name: 'elements', 
     fields: (argsFromElements) => { 
      // here we can now access keys from "args" 
      const fields = {}; 
      argsFromElements.keys.forEach((key) => { 
      // some logic here .. 
      fields[someGeneratedProperty] = someGeneratedGraphQLType; 
      }); 
      return fields; 
     }, 
     }), 
     args: { 
     keys: { 
      type: new GraphQLList(GraphQLString), 
     }, 
     }, 
    }, 
    // ... 
    }, 
}); 

這可以工作,但如果要通過指定參數和/或解決對象的字段的方式問題將是。

問題 所以我們的問題現在是:哪種方式在我們的情況被推薦在GraphQL,是方案1或2可能嗎?也許還有另一種解決方案?

編輯 解決方案1在使用ScalarType時可以工作。示例:

type: new GraphQLScalarType({ 
     name: 'elements', 
     serialize(value) { 
      return value; 
     }, 
     }), 

我不確定這是否是推薦的方式來解決我們的情況。

回答

5

兩個選項都沒有真正可行的:

  1. GraphQL是強類型。 GraphQL.js不支持某種類型的any字段,並且架構中定義的所有類型都必須定義字段。 If you look in the docs,fields是必需的 - 如果您嘗試忽略它,您將遇到錯誤。

  2. 參數用於在每個請求的基礎上解析查詢。您無法將它們傳回您的架構。你的模式應該是靜態的。

正如您所建議的那樣,通過滾動您自己的客戶標量可以完成您想要做的事情。我認爲更簡單的解決方案就是使用JSON - 您可以導入custom scalar for it like this one。然後,只需將您的elements字段解析爲包含動態字段的JSON對象或數組。例如,如果需要,您也可以根據參數在解析器內部操縱JSON對象(如果想限制返回到args中定義的子集的字段)。

警告字:使用JSON或包含嵌套數據的任何自定義標量的問題是您限制了客戶端請求實際需要的靈活性。它還會導致客戶端的幫助錯誤更少 - 我寧願被告知我請求的字段不存在,或者在發出請求時返回null ,而不是稍後查找JSON blob的行我沒有包括我期望的領域。

+0

你的回答聽起來不錯。我們將在您的答案中嘗試定義的JSON類型。當然,如果我們僅僅返回「任何對象」而沒有可能控制其需要的數據,靈活性就會受到限制。但在我們的特殊情況下,我們沒有其他選擇,因爲屬性在我們的graphql服務器上是未知的。但是:這種情況在我們的邏輯中是非常特殊和獨特的。 – TJR

+0

如何使用JSON.stringify()將任何json obj創建爲一個字符串,然後將該字符串賦予一個鍵,例如{any_data:'stringified json object'} –