揭秘三大軟件設計開發方法(DDD,TDD,BDD),到底哪個好?

      網友投稿 1712 2022-05-30

      【引言】

      GraphQL是一種開源的數據查詢和操作語言,是一種用于API的數據查詢和操作的語言,也是一種利用現有數據完成查詢的動態理念。?GraphQL于2012年由Facebook內部開發,2015年公開發布。2018年11月7日,GraphQL項目從Facebook轉到了新成立的GraphQL基金會,由非營利性的Linux基金會主持管理。自2012年以來,GraphQL的崛起一直遵循著GraphQL的創建者Lee Byron所制定的推廣時間表,并準確無誤。Byron的目標是讓GraphQL在Web平臺上無所不在。

      它提供了一種開發Web API的方法,并與REST和其他Web服務架構進行了比較和對比。它允許客戶端定義所需的數據結構,而服務器返回的數據結構也是一樣的,因此可以防止過量的數據被返回,但這對查詢結果的web緩存的有效性有影響。查詢語言的靈活性和豐富性也增加了程序設計的復雜度,對于簡單的API來說,可能并不值得。它由類型系統、查詢語言和執行語義、靜態驗證和類型自省組成。

      GraphQL?支持讀取、寫入(包括突變)和訂閱數據的變化(實時更新--最常見的是使用?WebHooks?)。

      GraphQL服務器適用于多種語言,包括Haskell、JavaScript、Perl、Python、Ruby、Java、C#、Scala、Go、Elixir、Erlang、PHP、R和Clojure。

      2018年2月9日,GraphQL Schema Definition Language (SDL)成為規范的一部分。

      GraphQL?規范最新的版本發布在?https://graphql.github.io/graphql-spec/。

      最新的規范草案可以在?https://graphql.github.io/graphql-spec/draft/

      找到。

      之前發布的GraphQL規范可以在與其發布標簽匹配的permalinks中找到,?例如,https://graphql.github.io/graphql-spec/October2016/。

      【概覽】

      GraphQL是Facebook創建的API查詢語言。

      目標受眾不是客戶端開發者,而是那些已經對構建自己的GraphQL服務程序和工具感興趣的人。

      為了被廣泛采用,GraphQL必須提供針對各種后端、框架和語言的支持,這將需要跨項目和組織的協作努力

      GraphQL?由類型系統、查詢語言和執行語義、靜態驗證和類型自省組成,下面會分別介紹這些部分:

      下面的例子中,我們會用GraphQL來查詢《星球大戰》三部曲中的人物和位置信息。

      【類型系統】

      任何GraphQL實現的核心是描述它可以返回哪些類型的對象,在GraphQL類型系統中描述并在GraphQL Schema中返回。

      對于我們的Star Wars例子,GraphQL.js中的starWarsSchema.js文件定義了這個類型系統。

      系統中最基本的類型將是Human,代表著像Luke、Leia和Han這樣的角色。在我們的類型系統中,所有的人類都會有一個名字,所以我們定義Human類型有一個名為?"name "的字段。我們定義?"name "字段為不可空的字符串。使用我們將在整個規范和文檔中使用的速記符號,我們將把人類模型定義為:

      type?Human?{

      name:?String

      }

      這個速記詞方便描述類型系統的基本狀況;JavaScript實現的功能比較齊全,可以對類型和字段進行記錄。它還設置了類型系統和底層數據之間的映射;對于GraphQL.js中的一個測試用例來說,底層數據是一組JavaScript對象,但在大多數情況下,支持的數據將通過一些服務來訪問,而這個類型系統層將負責從類型和字段到那個服務的映射。

      在許多API中,甚至在GraphQL中,一個常見的模式是給對象一個ID,可以用來訪問這個對象。所以,讓我們把這個添加到我們的Human類型中,此外我們還要添加另一個字符串:?homePlanet。

      type?Human?{

      id:?String

      name:?String

      homePlanet:?String

      }

      既然我們討論的是《星球大戰三部曲》,那么描述一下每個角色出現的劇集是很有用的。為此,我們先定義一個枚舉,列出三部曲:

      enum?Episode?{?NEWHOPE,?EMPIRE,?JEDI?}

      現在我們要在Human中添加一個字段,描述他們參加過的劇集。是一個劇集列表:

      type?Human?{

      id:?String

      name:?String

      appearsIn:?[Episode]

      homePlanet:?String

      }

      現在,我們來介紹另一種類型,Droid:

      type?Droid?{

      id:?String

      name:?String

      appearsIn:?[Episode]

      primaryFunction:?String

      }

      現在我們有兩種類型了!?讓我們在這兩種類型之間增加一種關聯方式:人類和機器人都有朋友,人類和機器人也都可以做朋友。

      人類和機器人之間有共同的屬性;它們都有ID、名字,以及出現的劇集。

      我們添加一個接口Character,讓Human和Droid從這里派生。有了這些之后,我們就可以添加好友字段,也即返回一個Character列表。

      我們的類型系統就成了這樣:

      enum?Episode?{?NEWHOPE,?EMPIRE,?JEDI?}

      interface?Character?{

      id:?String

      name:?String

      friends:?[Character]

      appearsIn:?[Episode]

      }

      type?Human?implements?Character?{

      id:?String

      name:?String

      friends:?[Character]

      appearsIn:?[Episode]

      homePlanet:?String

      }

      type?Droid?implements?Character?{

      id:?String

      name:?String

      friends:?[Character]

      appearsIn:?[Episode]

      primaryFunction:?String

      }

      這里我們需要問一個問題,就是這些字段中的任何一個字段是否可以返回null? 默認情況下,null是GraphQL中任何類型的允許值,因為獲取數據以完成GraphQL查詢經常需要與不同的服務對話,而這些服務有可能是可用的,也可能是不可用的。如果我們想把某個類型標記為不能為空,我們可以通過在類型后添加一個"!"來表示。

      注意,在實現中,我們可能把一些字段保留為nullable,這樣我們就有了靈活性,最終可以判斷返回null來表示后端錯誤,同時也告訴客戶端發生了錯誤。

      我們嘗試把id設定為不為空字段:

      enum?Episode?{?NEWHOPE,?EMPIRE,?JEDI?}

      interface?Character?{

      id:?String!

      name:?String

      friends:?[Character]

      appearsIn:?[Episode]

      }

      type?Human?implements?Character?{

      id:?String!

      name:?String

      friends:?[Character]

      appearsIn:?[Episode]

      homePlanet:?String

      }

      type?Droid?implements?Character?{

      id:?String!

      name:?String

      friends:?[Character]

      appearsIn:?[Episode]

      primaryFunction:?String

      }

      接下來我們需要定義一個入口來訪問類型系統,實際上就是一個查詢數據類型。

      這個類型的名稱按照慣例是?Query,它描述了我們公共的、頂層API。這個例子中的查詢類型是這樣的:

      type?Query?{

      hero(episode:?Episode):?Character

      human(id:?String!):?Human

      droid(id:?String!):?Droid

      }

      在這個例子中,有三個操作字段:

      l??hero?返回《星球大戰》三部曲中的英雄人物;它有一個可選的參數,允許我們獲取特定劇集的英雄人物。

      l??human有一個非空字符串ID作為查詢參數,返回人類。

      l??droid有一個非空字符串ID作為查詢參數,返回機器人人。

      這些字段展示了類型系統的另一個特點,即字段可以指定參數來配置它們的結果。

      當我們將整個類型系統打包在一起,將上面的查詢類型定義為查詢的入口點,這就創建了一個GraphQL的設計定義。

      查詢語法

      GraphQL查詢準確的描述了調用者需要獲取什么數據。

      簡單查詢

      我們來看例子:

      query?HeroNameQuery?{

      hero?{

      name

      }

      }

      上面這個查詢的名字描述了很清晰的目的,就是要查詢一個名字。其返回結果大概是這樣的:

      {

      "hero":?{

      "name":?"R2-D2"

      }

      }

      更多數據查詢

      再來看另一個查詢:

      query?HeroNameAndFriendsQuery?{

      hero?{

      id

      name

      friends?{

      id

      name

      }

      }

      }

      這個查詢希望查詢到id, name以及其朋友的id和name。返回結果大概這樣:

      {

      "hero":?{

      "id":?"2001",

      "name":?"R2-D2",

      "friends":?[

      {

      "id":?"1000",

      "name":?"Luke?Skywalker"

      },

      {

      "id":?"1002",

      "name":?"Han?Solo"

      },

      {

      "id":?"1003",

      "name":?"Leia?Organa"

      }

      ]

      }

      }

      嵌套查詢

      下面看一個嵌套查詢的例子:

      query?NestedQuery?{

      hero?{

      name

      friends?{

      name

      appearsIn

      friends?{

      name

      }

      }

      }

      }

      返回結果:

      {

      "hero":?{

      "name":?"R2-D2",

      "friends":?[

      {

      "name":?"Luke?Skywalker",

      "appearsIn":?["NEWHOPE",?"EMPIRE",?"JEDI"],

      "friends":?[

      {?"name":?"Han?Solo"?},

      {?"name":?"Leia?Organa"?},

      {?"name":?"C-3PO"?},

      {?"name":?"R2-D2"?}

      ]

      },

      {

      "name":?"Han?Solo",

      "appearsIn":?["NEWHOPE",?"EMPIRE",?"JEDI"],

      "friends":?[

      {?"name":?"Luke?Skywalker"?},

      {?"name":?"Leia?Organa"?},

      {?"name":?"R2-D2"?}

      ]

      },

      {

      "name":?"Leia?Organa",

      "appearsIn":?["NEWHOPE",?"EMPIRE",?"JEDI"],

      "friends":?[

      {?"name":?"Luke?Skywalker"?},

      {?"name":?"Han?Solo"?},

      {?"name":?"C-3PO"?},

      {?"name":?"R2-D2"?}

      ]

      }

      ]

      }

      }

      指定ID查詢

      query?FetchLukeQuery?{

      human(id:?"1000")?{

      name

      }

      }

      或者:

      query?FetchSomeIDQuery($someId:?String!)?{

      human(id:?$someId)?{

      name

      }

      }

      返回結果:

      {

      "human":?{

      "name":?"Luke?Skywalker"

      }

      }

      指定ID的多個查詢

      query?FetchLukeAndLeiaAliased?{

      luke:?human(id:?"1000")?{

      name

      }

      leia:?human(id:?"1003")?{

      name

      }

      }

      結果:

      {

      "luke":?{

      "name":?"Luke?Skywalker"

      },

      "leia":?{

      "name":?"Leia?Organa"

      }

      }

      特殊字段:__typename

      下面來看特殊字段的例子:

      query?CheckTypeOfR2?{

      hero?{

      __typename

      name

      }

      }

      結果:

      {

      "hero":?{

      "__typename":?"Droid",

      "name":?"R2-D2"

      }

      }

      驗證

      通過使用類型系統,可以預先確定GraphQL查詢是否有效。服務器和客戶端之間如果創建了一個無效查詢,類型系統就可以有效地通知開發人員,而不需要運行時才報錯。

      上面我們列出了一些有效的查詢例子,接下來我們看看無效的查詢例子:

      字段未定義

      #?INVALID:?favoriteSpaceship不存在于Character上。

      query?HeroSpaceshipQuery?{

      hero?{

      favoriteSpaceship

      }

      }

      在最基礎字段(標量)下再查詢

      #?INVALID:?name?已經是最基礎的字段了,不能再進行子字段查詢。

      query?HeroFieldsOnScalarQuery?{

      hero?{

      name?{

      firstCharacterOfName

      }

      }

      }

      片段定義

      query?DroidFieldInFragment?{

      hero?{

      name

      ...DroidFields

      }

      }

      fragment?DroidFields?on?Droid?{

      primaryFunction

      }

      上面這種查詢是有效的,但是如果這個片段沒有被多次調用的話,我們可以匿名定義:

      query?DroidFieldInInlineFragment?{

      hero?{

      name

      ...?on?Droid?{

      primaryFunction

      }

      }

      }

      上面的查詢中,hero沒有primaryFunction字段定義,但是Droid有這個字段,通過片段聲明可以使這個查詢有效。

      自省

      這項功能允許我們詢問GraphQL支持哪些查詢。

      缺省詢問

      比如對上面的系統,我們可以這樣詢問:

      query?IntrospectionTypeQuery?{

      __schema?{

      types?{

      揭秘三大軟件設計開發方法(DDD,TDD,BDD),到底哪個好?

      name

      }

      }

      }

      得到的結果類似于這樣:

      {

      "__schema":?{

      "types":?[

      {

      "name":?"Query"

      },

      {

      "name":?"Character"

      },

      {

      "name":?"Human"

      },

      {

      "name":?"String"

      },

      {

      "name":?"Episode"

      },

      {

      "name":?"Droid"

      },

      {

      "name":?"__Schema"

      },

      {

      "name":?"__Type"

      },

      {

      "name":?"__TypeKind"

      },

      {

      "name":?"Boolean"

      },

      {

      "name":?"__Field"

      },

      {

      "name":?"__InputValue"

      },

      {

      "name":?"__EnumValue"

      },

      {

      "name":?"__Directive"

      }

      ]

      }

      }

      上面類型很多,我們分一下類:

      l??Query, Character, Human, Episode, Droid -?這些是我們在類型系統中定義的。

      l??String, Boolean -?這些是類型系統提供的內置標量。

      l??__Schema, __Type, __Type, __TypeKind, __Field, __InputValue, __EnumValue, __Directive -?這些都在前面加了雙下劃線,表示它們是自省系統的一部分。

      現在我們只詢問查詢支持:

      query?IntrospectionQueryTypeQuery?{

      __schema?{

      queryType?{

      name

      }

      }

      }

      結果如下:

      {

      "__schema":?{

      "queryType":?{

      "name":?"Query"

      }

      }

      }

      詢問特定類型

      query?IntrospectionDroidTypeQuery?{

      __type(name:?"Droid")?{

      name

      }

      }

      結果:

      {

      "__type":?{

      "name":?"Droid"

      }

      }

      類別查詢

      query?IntrospectionDroidKindQuery?{

      __type(name:?"Droid")?{

      name

      kind

      }

      }

      結果:

      {

      "__type":?{

      "name":?"Droid",

      "kind":?"OBJECT"

      }

      }

      上面是對象類型,我們來看接口類型:

      query?IntrospectionCharacterKindQuery?{

      __type(name:?"Character")?{

      name

      kind

      }

      }

      結果:

      {

      "__type":?{

      "name":?"Character",

      "kind":?"INTERFACE"

      }

      }

      字段支持查詢

      query?IntrospectionDroidFieldsQuery?{

      __type(name:?"Droid")?{

      name

      fields?{

      name

      type?{

      name

      kind

      }

      }

      }

      }

      結果:

      {

      "__type":?{

      "name":?"Droid",

      "fields":?[

      {

      "name":?"id",

      "type":?{

      "name":?null,

      "kind":?"NON_NULL"

      }

      },

      {

      "name":?"name",

      "type":?{

      "name":?"String",

      "kind":?"SCALAR"

      }

      },

      {

      "name":?"friends",

      "type":?{

      "name":?null,

      "kind":?"LIST"

      }

      },

      {

      "name":?"appearsIn",

      "type":?{

      "name":?null,

      "kind":?"LIST"

      }

      },

      {

      "name":?"primaryFunction",

      "type":?{

      "name":?"String",

      "kind":?"SCALAR"

      }

      }

      ]

      }

      }

      無名字段,查類型

      像列表類型字段沒有名字,我們可以查看類型ofType。

      query?IntrospectionDroidWrappedFieldsQuery?{

      __type(name:?"Droid")?{

      name

      fields?{

      name

      type?{

      name

      kind

      ofType?{

      name

      kind

      }

      }

      }

      }

      }

      結果:

      {

      "__type":?{

      "name":?"Droid",

      "fields":?[

      {

      "name":?"id",

      "type":?{

      "name":?null,

      "kind":?"NON_NULL",

      "ofType":?{

      "name":?"String",

      "kind":?"SCALAR"

      }

      }

      },

      {

      "name":?"name",

      "type":?{

      "name":?"String",

      "kind":?"SCALAR",

      "ofType":?null

      }

      },

      {

      "name":?"friends",

      "type":?{

      "name":?null,

      "kind":?"LIST",

      "ofType":?{

      "name":?"Character",

      "kind":?"INTERFACE"

      }

      }

      },

      {

      "name":?"appearsIn",

      "type":?{

      "name":?null,

      "kind":?"LIST",

      "ofType":?{

      "name":?"Episode",

      "kind":?"ENUM"

      }

      }

      },

      {

      "name":?"primaryFunction",

      "type":?{

      "name":?"String",

      "kind":?"SCALAR",

      "ofType":?null

      }

      }

      ]

      }

      }

      詢問描述文檔

      query?IntrospectionDroidDescriptionQuery?{

      __type(name:?"Droid")?{

      name

      description

      }

      }

      結果:

      {

      "__type":?{

      "name":?"Droid",

      "description":?"A?mechanical?creature?in?the?Star?Wars?universe."

      }

      }

      進一步的,我們可以使用自省系統創建更強大的文檔系統,從而豐富編碼人員的開發體驗。

      【小結】

      上面我們對GraphQL從類型系統,查詢語法,驗證和自省功能進行了學習。

      接下來我們看看GraphQL有什么缺點:

      缺陷

      GraphQL的主要缺點是它使用單一的端點,而不是遵循HTTP規范進行緩存。而網絡層面的緩存很重要,它可以減少服務器的流量。

      此外,對于簡單的應用程序來說,這并不是好的解決方案,因為它增加了復雜度(類型、查詢、驗證、自省),?而使用REST可以更簡單地完成的任務。

      歡迎討論。

      架構設計

      版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。

      上一篇:讓煤炭生產更安全更智能,精英數智聯手華為云打造煤礦大腦
      下一篇:《智能系統與技術叢書 生成對抗網絡入門指南》—3.4GAN的工程實踐
      相關文章
      男人的天堂亚洲一区二区三区 | 亚洲av午夜福利精品一区| www.91亚洲| 亚洲国产成人AV网站| 亚洲中文字幕久久无码| 国产精品亚洲片夜色在线| 亚洲一区中文字幕| 亚洲av乱码一区二区三区香蕉| 亚洲人成在线精品| 亚洲中文字幕日本无线码| 国产99在线|亚洲| 亚洲午夜福利在线视频| 亚洲成AV人影片在线观看| gogo全球高清大胆亚洲| 亚洲人成色77777在线观看大| 亚洲综合色在线观看亚洲| 国产亚洲精品不卡在线| 亚洲日韩乱码中文无码蜜桃臀网站 | 亚洲国产成人乱码精品女人久久久不卡 | 亚洲精品无码成人AAA片| 亚洲国产精品一区二区久久hs | 亚洲av成人无码网站…| 国产亚洲精品美女久久久久| 亚洲国产精品一区二区九九| 久久久久久久亚洲精品| 国产l精品国产亚洲区在线观看| 久久精品国产亚洲av麻| 亚洲成av人片不卡无码| 亚洲爆乳成av人在线视菜奈实| 欧美日韩亚洲精品| 久久影视国产亚洲| 久热综合在线亚洲精品| 久久亚洲精品无码AV红樱桃| 亚洲AV无码一区二区三区在线| 亚洲欧美日韩综合久久久| 亚洲成AV人网址| 亚洲VA中文字幕无码一二三区| 精品日韩亚洲AV无码一区二区三区| 亚洲午夜成激人情在线影院| 亚洲欧美黑人猛交群| 亚洲午夜精品第一区二区8050|