用介面的思想來理解GraphQL

明華發表於2018-07-27

介面是行為的定義,確定了跟系統互動的介面。 行為的實體是函式,函式包括定義和實現,而介面只關注函式的定義。 函式定義包括傳人蔘數和返回值,包含了引數名稱和型別,包含了返回值的型別。

GraphQL是介面

GraphQL本質上是一種介面的定義規範,裡面包括了種型別定義和函式定義(名稱,引數,返回值),可以精確的定義了前後端互動的介面。

GraphQL不是一般的介面

用介面的思想來理解GraphQL

GraphQL是隻定義介面,不關心實現,本身是語言不相關的。

這意味著GraphQL可以作為連線不同系統的統一規範。

GraphQL包含嚴格的型別定義,這種定義可以用來進行程式碼生成,結合本身有提供很多輔助開發工具,可以輔助解決介面的定義、實現、文件、除錯問題。

以上所說的這些,很多rpc平臺,像grpc、thrift都能解決。著這個角度講,GraphQL就是一種rpc協議。

如果要說不同之處,GraphQL設計之處的目的是解決前後端互動的問題。前後端互動網路傳輸是一個問題。

傳統的rpc返回結果的時候回返回完整的資料,但是很多時候我們只需要結果中的部分資料,這樣傳輸無用資料會造成頻寬浪費,同時也會影響處理速度,對於響應要求高或者網路頻寬不夠的應用不利,移動應用就屬於這類。

使用GraphQL介面時,可以基於定義約定想要的東西,然後GraphQL會根據請求,只返回想要的資料,這點類似於SQL。同時,可以在一次GraphQL請求傳送多個函式呼叫請求,這樣可以減少請求的傳送量,從而提高響應速度。

舉例說明

下面我們用Go語言定義了一個簡單的型別和介面。

// 定義的User型別
type User struct {
    ID int
    Name string
    Age int
    Posts []Post
}

type Post struct {
    ID int 
    Title string
    Owner User
}

// 定義的查詢介面
type Query interface {
    FetchUsers() []User
    FetchPosts(userID int) []Post
    GetUserById(id int) *User // 定義了函式的引數和返回值
}

// 定義的修改介面
type Mutation interface {
    CreateUser(name string, age int) User
    DeleteUser(id int) *User
}
複製程式碼

我們知道,介面如果成功呼叫,會返回一個完整的資料。比如,GetUserById成功呼叫後會返回一個完整的User給我們。 這裡包括大量User的全部屬性, 形如User {ID: 0, Name: "Alex", Age: 28}。 但是如果我們頻寬太窄,只需要User的Name資訊呢? 這裡就是graphql跟介面不同的地方。像SQL一樣,使用GraphQL你可以宣告你需要什麼屬性。

{
    GetUserById(id: 1) {
        Name
    }
}
複製程式碼

介面,你呼叫一個函式,返回一個結果。你返回多種結果,呼叫多次函式。 使用GraphQL,你能夠把多個對資料的要求放在一個請求裡面。

{
    GetUserById(id: 1) {
        Name
    }
    
    FetchPosts(userId: 1) {
        title
    }
}
複製程式碼

而且,GraphQL還支援順著型別定義巢狀的抓取資訊。 上面的查詢也可以寫成下面的形式。

{
    GetUserById(id: 1) {
        Posts {
            title
        }
    }
}
複製程式碼

當然你也可以喪心病狂的不斷巢狀抓取資料。

{
    GetUserById(id: 1) {
        Posts {
            title
            Owner {
                Name {
                    Posts {
                        title
                        ...
                    }
                }
            }
        }
    }
}
複製程式碼

這種按照介面的型別定義,不斷巢狀的抓取資料正是GraphQL中Graph的由來,表達了Graph + QL = 按圖 + 索驥內涵。 當然這種變態的抓取是非常恐怖的,如果有壞人故意發這種請求搞死我們,我們就完了,所以必須有一種方式來限制這種行為。 好在,我們可以對使用者的請求進行AST語法分析,限制巢狀的深度,比如,我們可以讓你最多巢狀3層。

總結

GraphQL本質上是一種為了解決前後端互動問題二設計的介面協議。很好的解決了介面的定義、文件、除錯、使用等問題,目測會越來越火。

相關文章