GraphQL 第二章 Schema 和類型
定義了 schema 後我們就能知道服務器會返回那種對象,這些對象有哪些字段可用等。
每個 GraphQL 服務都會定義一套類型,用以描述你可能從那個服務查詢到的數據,每當查詢到來,服務器就會根據 schema 驗證並執行查詢。
之前我們講了 GraphQL 的查詢語言,這裏我們來講一下 GraphQL Schema language 。這個和 GraphQL 的查詢語言類似。
一個 GraphQL schema 中的最基本的組件是對象類型,它表示你可以從服務上獲取到什麼樣類型的對象,以及對象的字段。
type Human {
name: String!
height: Float
friends: [Person!]!
}
這裏我們定義了一個 Human 對象類型,這個對象中包括了幾個字段。 String
Float
是內置的標量類型,String!
表示這個字段是非空的,[person!]!
表示一個 person 數組,他也是非空的,所以當你查詢 friends 時能得到一個數組,並且由於 Person!也是非空的,所以你可以得到的數組中每個項目都是一個 Person 對象.
GraphQL 對象類型上的每個字段都有可能有 0 或 多個參數
這裏所有的參數都是具名的
type Human {
name: String!
height:(unit: HeightUnit = METER) Float
friends:[Person!]!
}
Schema 中有兩個特殊的類型 Query 和 Mutation 。
schema {
query: Query
mutation: Mutation
}
每個 GraphQL 服務都有一個 query 類型,可能有一個 mutation 類型。這兩個類型和常規對象類型無差,但是它們之所以特殊,是因爲它們定義了每一個 GraphQL 查詢的入口,這也是它們唯一特殊的地方,別的與普通對象類型無二致。
query {
hero { name }
person(id: 1) { name}
}
# -------->
type Query {
hero: Charactor
person(id: ID!): Charactor
}
標量類型(scalar type)
在之前我們就用到過好多次String
Float
這些類型了,這些類型叫做標量類型,這些類型是沒有次級字段的,對象類型是有次級字段的。
GraphQL 自帶一組默認標量類型:
* Int:有符號 32 位整數。
* Float:有符號雙精度浮點值。
* String:UTF‐8 字符序列。
* Boolean:true 或者 false。
* ID:ID 標量類型表示一個唯一標識符,通常用以重新獲取對象或者作爲緩存中的鍵。ID 類型使用和 String 一樣的方式序列化;然而將其定義爲 ID 意味着並不需要人類可讀型。
我們還可以自定義標量類型,取決於我們的實現中如何定義將其序列化、反序列化和驗證。
scalar Date
# 例如定義一個Date 類型應該總是被序列化成整形時間戳,而客戶端應該知道去要求任何 date 字段都是這樣的格式
枚舉類型(enumeration type)
這個其實和別的語言中的枚舉類型是差不多的。枚舉類型是一種特殊的標量,它限制在一個特殊的可選值集合內。
1. 驗證這個類型的任何參數是可選值的某一個
2. 與類型系統溝通,一個字段總是一個有限值集合的其中一個值
enum Hobby {
swim
football
basketball
}
類型修飾符
我們之前就已經看到過兩個了,分別是 !
[]
一個是用來標註 非空 ,一個是標註 數組
標記了非空的字段,服務器總會返回一個非空值,如果它得到一個空值,就會觸發一個 GraphQL 執行錯誤。如果定義的參數有這個非空標識,傳參時給個空值,會導致服務器返回一個驗證錯誤。
列表就相對來說直觀些了,通過[]
定義的就是一個數組了
接下來我們來看看這兩者結合使用的情況
myField: [String!]
# ------------- #
myField: null # 有效
myField: [] # 有效
myField: ['a','b'] # 有效
myField: ['a',null,'b'] # 錯誤
myField: [String]!
# ------------ #
myField: null # 錯誤
muField: [] # 有效
myField: ['a','b'] # 有效
myField: ['a',null,'b'] # 有效
結口(Interface)
GraphQL 支持接口,一個接口是一個抽象類型,它包含某些字段,而實現這個接口的對象類型必須包含這些字段
interface Human {
id: ID!
name: String
age: Int
height: Float
friends:[Person!]!
}
實現 Human
接口
type Female implements Human {
id: ID!
name: String
age: Int
height: Float
friends:[Person!]!
feature: [String!]
}
type Male implements Human {
id: ID!
name: String
age: Int
height: Float
friends: [Person!]!
hobby: [String!]
}
聯合類型(Union type)
聯合類型和接口十分相似,但是它並不指定類型之間的任何共同字段,聯合類型的成員需要是具體對象類型,你不能使用接口或者其他聯合類型來創建一個聯合類型。
union searchResult = Human | Hero | Person
輸入類型(input type)
我們之前傳遞的參數都是一些標量類型或者是枚舉類型的值,但是我們不可避免的會傳遞一些複雜對象,比如在新增、更新操作中,這時候就引入了輸入對象類型,它和常規對象一樣,只是關鍵字是 input
而不是 type
input person {
name: String
age: Int
...
}
mutation createPerson($person: Person){
createOne(one: $person){
name
age
}
}
# ---------- #
# person
{
name:'zs',
age: 10
}
輸入對象類型上的字段本身也可以指代輸入對象類型,但是你不能在你的 schema 混淆輸入和輸出類型。輸入對象類型的字段當然也不能擁有參數。