GraphQL主要是一套針對圖狀數據查詢語言,推薦先讀讀知乎——什麼是 GraphQL?
基本類型
先看看提供的基本類型(標量類型)
GraphQL 自帶一組默認標量類型:
- Int:有符號 32 位整數。
- Float:有符號雙精度浮點值。
- String:UTF‐8 字符序列。
- Boolean:true 或者 false。
- ID:ID 標量類型表示一個唯一標識符,通常用以重新獲取對象或者作爲緩存中的鍵。ID 類型使用和 String 一樣的方式序列化;然而將其定義爲 ID 意味着並不需要人類可讀型。
自定義基本類型(Date是一個type,需要自行實現)
scalar Date
枚舉定義
通過enum關鍵字定義枚舉,如
enum Episode {
NEWHOPE
EMPIRE
JEDI
}
類定義
通過使用type進行類型定義,如
type Character {
str: String
}
GraphQL中,成員的表示方式是 成員名稱:類型名稱
memberName : typeName
通過在類型名稱後加上!,代表該成員不能爲空,比如如下定義了一個不能爲空的數組成員
type Company{
human: [String]!
}
在數組的基類型右邊加上!代表數組元素不能爲空,如下是一個不能爲空的數組,且數組元素不能爲空
type Company{
human: [String!]!
}
接口類型
通過不使用type而使用interface關鍵字定義一個接口,type可以去實現接口,這要求其實現其所有成員,所以這裏的接口更像一些規則的集合而非屬性的抽象(需要具備接口的成員),實現多個接口使用&分隔,如
interface Company{
human: [String!]!
}
interface Home{
family: [String!]!
}
type YytCompany implements Company & Home{
human: [String!]!
host: String!
family: [String!]!
}
聯合類型
使用union關鍵字創建一個可以指代多種類型的類型,比如如下代碼表示創建了一個聯合類型Author,其可代表Yyt也可代表Eetal,具體值由運行時接收的對象確定
type Yyt{
name:String
}
type Eetal{
host:String
}
union Author = Yyt|Eetal;
成員默認值、方法成員
通過在類型右側使用 = 加上 value,代表爲成員提供默認值。通過在成員名稱右側加上形參列表代表爲一個方法成員,格式如成員格式,如,方法形參支持 基本類型、枚舉和輸入類型
type Yyt{
name:String = "yyt"
}
type Eetal{
host:String = "yangyitao.top"
}
union Author = Yyt|Eetal;
type AQuery{
whois(arg : Int):Author
}
輸入類型
輸入類型代表可以作爲方法成員參數的複雜類型,如下定義一個輸入類型,則可以在方法參數中使用該類型
type Review{
stars: Int!
commentary: String
}
input ReviewInput {
stars: Int!
commentary: String
}
type AQuery{
Review(arg : ReviewInput):Review
}
命名空間
通過schema關鍵字指定某些type爲命名空間,如
type Query{
}
type Mutation{
}
schema {
query: Query
mutation: Mutation
}
查詢
- 服務端定義
type Query{
}
type Mutation{
}
schema {
query: Query
mutation: Mutation
}
type Hello{
name: String = "hello"
world: Int = 1
whois(arg2:String) : String
}
type SubHello{
Hello(arg1:String):Hello
}
- 簡單查詢語句
查詢語句直接使用對象格式的導航格式,同級別字段不需要逗號分隔
語句如果使用query作爲schema,可以省略schema名稱
因爲查詢結果使用json表示,默認使用查詢的成員名稱作爲鍵,所以多重查詢會造成重複覆蓋
需要通過使用別名來避免,格式是
別名: 查詢語句
如下代碼包含一個不使用別名的查詢和一個指定別名的查詢
query {
Hello{
name
}
hello2:Hello{
name
world
}
}
- 查詢結果
{
"data":{
"Hello":{
"name":"hello"
},
"hello2":{
"name":"hello",
"world":1
}
}
}
- 條件查詢語句
如果有些方法成員,需要傳遞參數,可以通過如下調用
query {
SubHello{
Hello(arg1 : "Hi"){
whois(arg2 : "Hi")
}
}
}
查詢結果
{
"data" : {
"SubHello":{
"Hello":{
"whois" : "這裏展示的是solve函數具體實現結果"
}
}
}
}
可以看到,有時層級傳遞參數是一樣的,可以通過在查詢語句中定義變量傳遞,如剛剛的查詢可以改爲
query Sample($arg : String = "yyt"){
SubHello{
Hello(arg1: $arg){
whois(arg2 : $arg)
}
}
}
- 指令
GraphQL還提供@include和@skip,分別代表當表達式成立才執行對應查詢,比如
query Sample($arg : String = "yyt" , $withName : Boolean = false,$skipWorld : Boolean = true){
SubHello{
Hello(arg1: $arg){
whois(arg2 : $arg)
name @inclue(if : $withName)
world @skip(if : $skipWorld)
}
}
}
執行結果
{
"data" : {
"SubHello":{
"Hello":{
"whois" : "這裏展示的是solve函數具體實現結果"
}
}
}
}
- 片段
通過fragment關鍵字,可以定義查詢片段,則在需要的地方通過
…片段名
即可完成引入片段代碼
比如
fragment nameFrag{
name
}
query {
Hello{
...nameFrag
}
}
- on關鍵字
這裏我也不知道叫什麼好,官方的文檔裏沒有提交這個的叫法,只說了他怎麼用,因爲查詢具備多態性(可能是接口實現,也可能是聚合類型作爲方法成員返回值類型),也就是有些方法返回的結果類型具備多個可能,則可以通過on關鍵字,指定返回不同類型時,篩選展示不同的字段,比如
{
search(text: "an") {
__typename
... on Human {
name
height
}
... on Droid {
name
primaryFunction
}
... on Starship {
name
length
}
}
}
這是官網的demo,閱讀了官網的文檔真的是有點糟糕,在表明場景前應該先把定義說明比較好吧?上述demo中意思是,__typename是返回當前結果類型,on Human代表如果返回類型是Human就使用前面的運算符運算後面的右值,否則此句查詢無效(沒有{name height}這個),沒錯這個是片段運算,這是一種簡寫,也叫內聯片段,所以也可以使用on定義模板,如剛剛查詢可以寫爲
fragment nameFrag on Hello{
name
}
query {
Hello{
...nameFrag
}
}
爲什麼沒有寫服務端的方法實現
因爲GraphQL的服務端實現是多語言版本的,可以理解爲,其核心是提供這種查詢語句的規範服務端定義好這些圖狀數據,客戶端自己定製查詢語句。而這些方法成員一般爲在服務端,不同語言下,傳入一個resolve函數(也就是方法成員的實現,去完成服務端語言的腳本計算。)比如如下爲js版本實現
//導入依賴
var { graphql, buildSchema } = require('graphql');
//定義schema
var schema = buildSchema(`
type Query {
hello: String
}
`);
//定義resolve,也就是圖狀數據,因爲在服務端,可以傳遞服務端語言的函數作爲成員值,取值時執行計算
var root = { hello: () => 'Hello world!' };
//查詢hello
graphql(schema, '{ hello }', root).then((response) => {
console.log(response);
});