graphql

 一、javascript

只返回所需html

 

Describe your data

type Project { name: String tagline: String contributors: [User] }

Ask for what you want

{
  project(name: "GraphQL") { tagline } }

Get predictable results

{
  "project": { "tagline": "A query language for APIs" } }

GraphQL | A query language for your API https://graphql.org/前端

 

GraphQL is a query language for APIs and a runtime for fulfilling those queries with your existing data. GraphQL provides a complete and understandable description of the data in your API, gives clients the power to ask for exactly what they need and nothing more, makes it easier to evolve APIs over time, and enables powerful developer tools.java

 

個人前端故事----我爲何用GraphQL - F-happy - 博客園 https://www.cnblogs.com/fuhuixiang/p/7479276.htmlnode

個人前端故事----我爲何用GraphQL

 

背景

今年我在作一個有關商戶的app,這是一個包含商戶從入網到審覈、從駁回提交到入網維護的完整的生命週期線下推廣人員使用的客戶端軟件,但故事並無這麼簡單。。。python

疑問

隨着app的逐漸完善,遇到的問題也漸漸多了起來,界面加載太久,初始化頁面請求次數過多等各類各樣的小毛病開始凸顯了出來。因而我開始了優化之路,第一步即是從api請求入手,仔細查看了每一個api返回的內容,一直奇怪爲何接口老是返回不少的數據回來,好比我須要一個商戶的詳細信息,可接口卻會把這個商戶相關的門店信息、全部人信息等其它各類各樣的信息一塊兒返回回來,若是是例如商戶詳情頁面也就罷了,但是在商戶列表這個接口下依舊返回如此之多的數據,可想而知這個列表有多大多複雜了。git

後來問事後端的同窗才知道是爲了兼容 web 端的需求,一個接口須要同時爲多個平臺提供內容,這大大增長了接口的返回內容和處理邏輯,並且需求也常常改動,因此還不如把能用到的字段全都輸出出來,省得每次改需求都要先後端一塊兒聯動。github

反思

得知告終果,這確實是一個有「充分」理由的處理結果,但是真的只能這樣了嘛?有沒有什麼更好的解決辦法呢?咱們先來總結一下如今遇到的問題:web

  • 兼容多平臺致使字段冗餘
  • 一個頁面須要屢次調用 API 聚合數據
  • 需求常常改動致使接口很難爲單一接口精簡邏輯

以上三個問題看起來並不複雜,按照以往的邏輯其實也是很好解決的,就拿第一個來講,遇到多平臺須要兼容時其實能夠經過提供不一樣平臺的接口來解決,例如這樣:sql

http://api.xxx.com/web/getUserInfo/:uid http://api.xxx.com/app/getUserInfo/:uid http://api.xxx.com/mobile/getUserInfo/:uid

又或者是經過不一樣的參數去控制:

http://api.xxx.com/getUserInfo/:uid?platfrom=web

雖然這是一個方便的解決方案,但帶來的實際上是後端邏輯的增長,須要爲不一樣平臺維護不一樣的邏輯代碼。

再說第二個問題,一個頁面須要屢次調用接口來聚合數據這塊也能夠經過多加接口的方式來解決:

http://api.xxx.com/getIndexInfo

或者是經過 http2 來複用請求,但這些方法不是增長工做量就是有兼容性問題,那麼還有沒有其餘的方法呢?

若是你們還記得數據庫的知識的話,就發現其實咱們能夠用 SQL 的思路去解決這些事情,那若是把後端抽象成一個數據庫會怎麼樣呢?

我想要什麼字段就 SELECT 什麼字段就行咯,若是一個頁面須要多個數據源的內容來填充那不就是組合 SQL 語句嘛。這樣不就解決了上面提出的三個問題了嘛,並且不管前端需求如何變動,只要咱們維持一個數據的超集,那麼每次只要讓前端改動查詢語句就能夠了,後端這裏也不須要同步的去給某個接口增長字段什麼的了,那麼解決方案有了,那該怎麼把後端抽象成一個數據庫呢?

解決

既然思路有了,那麼辦法也會有的~這就是 Facebook 在2015年開源的 GraphQL

這又是一個什麼東西呢?具體的介紹直接看它的官網就行了,我在這裏就很少說了,直接來看看如何使用吧。

因爲個人中間層是基於 Koa2 的,因此就在 koa2 上面作演示了,手寫咱們先安裝依賴:

npm install graphql koa-graphql --save

這樣咱們就能夠在 koa 中使用 graphql 了,而後就是配置路由了,按照文檔上面的例子,咱們能夠這樣寫:

"use strict"; const router = require('koa-router')(); const graphqlHTTP = require('koa-graphql'); const GraphQLSchema = require('./graphql'); const renderGraphiQL = require('../utils/render_graphiQL'); const graphqlModule = graphqlHTTP((request) => ({ schema: GraphQLSchema, graphiql: false, context: {token: request.header.authorization, platform: request.query.platform}, formatError: error => ({ type: 'graphql', path: error.path, message: error.message, locations: error.locations ? error.locations[0] : null }) })); router.all('/graphql', graphqlModule);

咱們來看看 graphqlModule 對象中都包含寫什麼吧,首先是 schema,這個是咱們主要的解析邏輯,全部經過 graphql 的請求都會被傳入這裏進行解析和處理,graphiql 這個是 koa-graphql 自帶的一個圖形界面版的測試地址,後面我再單獨介紹這個插件,context 是咱們的上下文,若是咱們須要在每一個解析函數內獲取到例如用戶 token時就能夠在這裏賦值,需求說明的是這個必須是一個 object 對象,而且若是咱們不指定的話會默認傳整個 request 對象,接下來就是最後一個經常使用的屬性了,formatError 是格式化錯誤的屬性,咱們能夠根據業務的需求自定義咱們的錯誤返回。

接下來去看看從最簡單的 hello world 開始,而後完成一個最基礎的 demo。

首先咱們在客戶端發起一個 post 請求,而後在請求 body 中帶上咱們的查詢語句,在 Graphql 中有兩種類型的查詢,一直是 query 開頭的查詢操做,一種是 mutation 開頭的修改操做。

query {hello}

這是一個最簡單的查詢,那麼這個查詢是如何經過解析的呢?上文說到所有的 Graphql 查詢都會經過 schema 來進行解析,那咱們看看上面定義的GraphQLSchema對象是個什麼吧。

module.exports = new GraphQLSchema({  query: new GraphQLObjectType({  name: 'rootQueryType',  description: '查詢操做',  fields: {  hello: {  type: GraphQLString,  description: '演示 demo',  args: {  name: {type: GraphQLString, description: '演示參數'} }, resolve(it, args, context) { return args.name; } } } }),  mutation: new GraphQLObjectType({  name: 'rootMutationType',  description: '新增或修改操做',  fields: {} }) });

咱們一步步來講,首先在這個文件中導出的是一個 GraphQLSchema 對象,這是 Graphql 的基礎對象,裏面包含了咱們須要的兩種類型,而後看 query 屬性,它返回的是一個GraphQLObjectType對象,這是 Graphql 中對於 object 的基本類型,這個對象中包含 name:名稱(全局惟一),description: 描述(這會自動的顯示在文檔中,雖然是非必須的,可是我仍是強烈建議每一個 Graphql 節點都寫上,這樣在後面的維護和查詢中都很是有利),最後就是fields屬性了,一個 Graphql 語句能查到什麼就全靠這裏寫了什麼了,在開始的例句中咱們查詢 query{hello},其實就是說咱們要查根節點下的 hello 屬性,因此這裏咱們就須要在 query 的 fields 中寫上 hello 屬性了,不然這條查詢語句就沒法生效了。

接下來咱們看看這個 hello 屬性中又包含了什麼呢?首先咱們須要指定它的類型,這很關鍵,這個類型是 hello 的返回類型,在這裏我指定它返回的是一個字符串,除此以外還有 Int,Boolean 等 js 的基礎類型可供選擇,具體可去查看文檔,固然了,在複雜狀況下也能夠返回 GraphQLObjectType 這種對象類型,而後就是對 hello 的描述字段description,接下來是args 屬性,若是咱們須要給此次查詢傳入參數的話就靠這個了,接下來就是最關鍵的 resolve 函數了,這個函數接受三個參數,第一個是上層的返回值,這在循環嵌套的狀況下會常用,好比說若是 hello 還有子屬性的話,那麼子屬性的這個參數就會是 args.name,第二個參數即是查詢屬性,第三個是咱們一開始說的貫穿整個請求的上下文。下面是一個完整的例子:

Request: query{hello(name: "world")} Response: {"hello": "world"}

講完了 query 操做,其實 mutation 操做也是相似的,我就再也不展開說了。

總結

最後來總結一下這個解決方案吧,其實這個方案你說是否是最佳解呢?也未必,仍是要看具體的業務場景的,在我遇到的場景中各類數據的關係是明確的,或者說是能夠抽象成模型的,我認爲這是可否使用 Graphql 的關鍵,從上面的實例中咱們其實能夠發現經過 Graphql 咱們把每一個數據都規範了起來,指定了類型,肯定了嵌套關係,這在以 JavaScript 爲基礎的 node 環境中顯得那麼格格不入,自己 JavaScript 是弱類型的,基於此咱們能夠在 node 服務中靈活的修改數據,從而不須要關心返回值和參數值,可是 Graphql 用一種強類型的觀念來強制咱們設計每一個數據,也許會有些前端的同窗接受不了,可是我我的認爲這種思路實際上是很是合理的,而且 Graphql 這種還支持嵌套查詢,只須要 fields 屬性中有這個對象就好了,所以咱們能夠把每一個數據類型儘量的抽象和分離出來,舉個例子,店長這個角色不就是用戶對象加上商戶對象的組合嘛,這不只從關係上明確了邏輯,也方便了更多可能性的組合條件。

對應我一開始遇到的那幾個問題,Graphql 看上去彷佛完美的解決了個人問題,可是對於更加複雜的場景呢?或者說對於老項目的改形成本是否划算呢?雖然我沒有遇到,可是我以爲只要認真梳理數據結構,最終均可以的,但那個時候是否還須要 Graphql 呢?那就不知道了,這篇博客不是介紹 Graphql 如何使用的中文文檔,我想表達的是這種思路對於這種場景下的一個解決思路,如今它只是解決了個人這些問題,那麼從這個思路的身上能不能挖掘出更多的驚喜呢?它仍是太新了,也許過幾年回頭再看,它說不定就和 restful 同樣是 API 的標配了也說不定呢,畢竟 GitHub 今年也推出了他們的 Graphql API 了呢。

 

A query language for your API

GraphQL is a query language for APIs and a runtime for fulfilling those queries with your existing data. GraphQL provides a complete and understandable description of the data in your API, gives clients the power to ask for exactly what they need and nothing more, makes it easier to evolve APIs over time, and enables powerful developer tools.

Ask for what you need,
get exactly that

Send a GraphQL query to your API and get exactly what you need, nothing more and nothing less. GraphQL queries always return predictable results. Apps using GraphQL are fast and stable because they control the data they get, not the server.

{
  hero {
    name
height
m } }
{
  "hero": { "name": "Luke Skywalker", "height": 1.72, "mass": 77 } }

Get many resources
in a single request

GraphQL queries access not just the properties of one resource but also smoothly follow references between them. While typical REST APIs require loading from multiple URLs, GraphQL APIs get all the data your app needs in a single request. Apps using GraphQL can be quick even on slow mobile network connections.

{
  hero { name friends { name } } }
{
  "hero": { "name": "Luke Skywalker", "friends": [ { "name": "Obi-Wan Kenobi" }, { "name": "R2-D2" }, { "name": "Han Solo" }, { "name": "Leia Organa" } ] } }

Describe what’s possible
with a type system

GraphQL APIs are organized in terms of types and fields, not endpoints. Access the full capabilities of your data from a single endpoint. GraphQL uses types to ensure Apps only ask for what’s possible and provide clear and helpful errors. Apps can use types to avoid writing manual parsing code.

 
{
  hero { name friends { name homeWorld { name climate } species { name lifespan origin { name } } } } }
 
type Query { hero: Character } type Character { name: String friends: [Character] homeWorld: Planet species: Species } type Planet { name: String climate: String } type Species { name: String lifespan: Int origin: Planet }

Move faster with
powerful developer tools

Know exactly what data you can request from your API without leaving your editor, highlight potential issues before sending a query, and take advantage of improved code intelligence. GraphQL makes it easy to build powerful tools like GraphiQL by leveraging your API’s type system.

Evolve your API
without versions

Add new fields and types to your GraphQL API without impacting existing queries. Aging fields can be deprecated and hidden from tools. By using a single evolving version, GraphQL APIs give apps continuous access to new features and encourage cleaner, more maintainable server code.

type Film { title: String episode: Int releaseDate: String }
 
type Film { title: String episode: Int releaseDate: String openingCrawl: String }
 
type Film { title: String episode: Int releaseDate: String openingCrawl: String director: String }
 
 
 
 
 
 
 
type Film { title: String episode: Int releaseDate: String openingCrawl: String director: String directedBy: Person } type Person { name: String directed: [Film] actedIn: [Film] }
 
type Film { title: String episode: Int releaseDate: String openingCrawl: String director: String @deprecated directedBy: Person } type Person { name: String directed: [Film] actedIn: [Film] }

Bring your own
data and code

GraphQL creates a uniform API across your entire application without being limited by a specific storage engine. Write GraphQL APIs that leverage your existing data and code with GraphQL engines available in many languages. You provide functions for each field in the type system, and GraphQL calls them with optimal concurrency.

type Character { name: String homeWorld: Planet friends: [Character] }
// type Character {
class Character { // name: String getName() { return this._name } // homeWorld: Planet getHomeWorld() { return fetchHomeworld(this._homeworldID) } // friends: [Character] getFriends() { return this._friendIDs.map(fetchCharacter) } }
# type Character {
class Character: # name: String def name(self): return self._name # homeWorld: Planet def homeWorld(self): return fetchHomeworld(self._homeworldID) # friends: [Character] def friends(self): return map(fetchCharacter, self._friendIDs) 
// type Character {
public class Character { // name: String public String Name { get; } // homeWorld: Planet public async Task<Planet> GetHomeWorldAsync() { return await FetchHomeworldAsync(_HomeworldID); } // friends: [Character] public async IEnumerable<Task<Character>> GetFriendsAsync() { return _FriendIDs.Select(FetchCharacterAsync); } }

Who’s using GraphQL?

Facebook's mobile apps have been powered by GraphQL since 2012. A GraphQL spec was open sourced in 2015 and is now available in many environments and used by teams of all sizes.

相關文章
相關標籤/搜索