標量(ScalarTypeDefinition)是 GraphQL 中不可分割的原子數據類型,在服務中充當葉子節點。對於客戶端而言,合法的查詢集(Select Set)必須到達葉子節點,也就是到達標量類型節點。javascript
GraphQL 規範提供了五種標量:java
UTF-8
字符序列上述五種類型與其餘語言對應的類型定義類似,相信讀者老爺們都已經很是熟悉,無需贅述,惟一值得探討的是 ID
類型。git
ID
類型只是一個字符串格式的值,引擎支持字符串解析值,也支持將 Int
解析值轉換爲字符串類型;ID
" 類型應該用於惟一標誌一個資源對象,也就是說,使用相同 ID 值,不管查詢多少次,結果都應該是同一對象,這一點有助於實現緩存,是 GraphQL 推薦的緩存方案;咱們來看一下例子加深印象:github
[ // 字符串類型 {id: '1'}, // int 類型,引擎會將其轉換爲字符串 {id: 1}, // float 類型 // 非法值,引擎不支持float轉換 // 將拋出 `TypeError` 錯誤 {id: 1.2}, // 與上面第一條重複 // 合法值,引擎並不強制 `ID` 值的惟一性 {id: '1'} ]
除規範定義的標量外,還能夠按需定義業務範疇內的標量。語法很是簡單:緩存
scalar Datetime
注意,這只是語義範疇定義,還須要定義序列化、反序列化函數:函數
new GraphQLScalarType({ name: "Datetime", description: "日期時間標量類型", // 序列化函數 serialize(value) { return value.toString(); }, // 解析函數 parseValue(value) { if (typeof value === "string") { return new Date(value); } throw new Error("參數類型錯誤"); }, // 解析函數 parseLiteral(ast) { if (ast.kind === Kind.STRING) { return new Date(ast.value); } throw new Error("參數類型錯誤"); } });
下面咱們一個一個看這些配置:工具
name
: 字段名,請保持與 schema 中定的標量類型名稱保持一致description
: 類型描述,在一些診斷工具上仍是頗有用的serialize
: 序列化函數,用於將結果轉換爲適合 http 傳輸的數值類型parseValue
: 解析函數,用於將客戶端經過 variables 參數傳遞的數值爲 Date 類型parseLiteral
: 一樣是解析函數,將客戶端傳遞的 字面量參數 解析爲 Date 類型配置中的 parseValue
、parseLiteral
兩個函數功能上類似,都用於解析客戶端參數,分別處理兩種參數傳遞方式:scala
# variables 參數 # 引擎將調用 parseValue 函數 query (before: Datetime){ users(before: $before) { id name } } variables { before: "1991-02-19" } # 字面量參數 # 引擎將調用 parseLiteral 函數 query { users(before: "1991-02-19") { id name } }
最後說一些注意的點:code
InputType
,能夠省略 parseValue
、parseLiteral
。parseValue
接收到的是 variables
對象中對應的值;而 parseLiteral
接收的則是引擎從 query
語句中解析出的 AST 節點。AST 節點內容形如:{ // 字面量類型 "kind": "StringValue", // 字面量值 "value": "1991-02-19", // 指明字面量是否爲 [BlockStringValue](https://facebook.github.io/graphql/June2018/#BlockStringValue()) 類型 "block": false, // token 位置 "loc": { "start": 18, "end": 30 } }
標量類型也支持返回結構化的對象,只要能爲引擎提供符合規則的 serialize
函數,一切皆有可能。咱們能夠寫出這樣一個標量:對象
// Address 對象類型,不過這是一個標量 new GraphQLScalarType({ name: "Address", description: "對象類型的標量", serialize(value) { // value 爲對象類型 // value = { city: '深圳', province: '廣東省', country: '中國' } return value; } });
可是要注意,標量類型是 不可分割 的,不能再傳入查詢子集:
# 合法請求 query { users { id name # Address 類型值 bornOrigin } }
返回結果:
{ "data": { "users": [ { "id": "1", "name": "foo", "bornOrigin": { "city": "深圳", "province": "廣東省", "country": "中國" } } ] } }
完整代碼在 此處。
能作是一回事,該不應這麼作,又是另外一回事,返回對象的標量雖然合乎規則,但卻違反了 按需加載 這一重要原則,沒有實際意義也不值得推崇。
標量是 GraphQL 中的原子類型,通常充當查詢的葉子節點。
GraphQL 規範提供了五種標量類型,其中 ID
最爲特殊,用於惟一標誌一個資源實例。在標準標量以外,也能夠按需定義新的標量,規則如上。