小洋的前端記事本(NO.5):GraphQL小實踐
這裡記錄著小洋童鞋在前端道路上的所思所想所感。
生命在於折騰,不在折騰中崩潰,就在折騰中涅槃。
GraphQL| A query language for your API,誕生於移動快速迭代時代,理念是給客戶端提供類似”資料庫操作“的能力,使其能夠從服務介面這個大的“大資料庫”中去篩選或修改想要的資料,用以滿足前端資料的個性化需求,既保證了多樣性,又控制了介面數量,期望更好的分類維護介面。GraphQL 伺服器有很多的實現,Node.js 當然也不例外,下面我們就一起折騰折騰 GraphQL 吧 : )
GraphQL Node.js Server
準備
首先給大家簡單的介紹一下 GraphQL 特性,GraphQL 其實是一種和後端交換資料的協議,像通過 SQL 語言可以運算元據庫一樣,GraphQL 通過 Schema 的方式來控制資料,並約定提供以下能力:
可以說很多資料交換的情景都可以使用 GraphQL 的概念,我們就先基於 Express 來快速打造一個 http 伺服器 ( GraphQL 官方並沒有說只限於 http) 用最簡單的方式體驗一下 GraphQL,我們的專案起始於 package.json:
{
"name": "graphql-start",
"description": "簡單體驗一下 GraphQL ",
"private": true,
"dependencies": {
"babel-register": "^6.18.0", // ES6 你懂的
"babel-preset-es2015": "^6.18.0", // ES6 你懂的
"express": "^4.14.0", // 快速搭一個伺服器
"body-parser": "^1.15.2", // Express 中介軟體,獲取 GraphQL 請求用的
"graphql": "^0.8.2" // 我們的主角,處理 GraphQL 請求用的
}
}
$npm install 以後我們就可以愉快的玩耍了,首先搭好程式入口,本地服務以及處理 GraphQL 請求的 handler:
/* 入口:index.js */
require(`babel-register`)({
presets: [ `es2015` ]
});
require(`./server.js`);
/* 本地服務:server.js */
// base
import express from `express`;
import {graphql} from `graphql`;
import bodyParser from `body-parser`;
// 組織服務端識別的 schema
import schema from `./schema`;
let app = express();
let PORT = 3000;
// 用 text 的方式解析 request doby,形象起見我們設定一個特殊的 Content-Type
app.use(bodyParser.text({type: `application/graphql`}));
// 建立 "/graphql" 的路由(可以看做一個API)接收 GraphQL 請求,使用 GET ? 特殊字元,url連結長度不考慮啦?
app.post(`/graphql`, (req, res) => {
// 組織服務端識別的 schema, 並處理 GraphQL 請求
graphql(schema, req.body).then((result) => {
res.send(JSON.stringify(result, null, 2));
})
});
let server = app.listen(PORT, function () {
let host = server.address().address;
let port = server.address().port;
console.log(`GraphQL listening at http://127.0.0.1`, host, port);
});
/* schema 例項:schema.js */
import {GraphQLSchema, GraphQLInt, GraphQLString, GraphQLBoolean, GraphQLObjectType, GraphQLList} from `graphql`;
// 建立一個GraphQLSchema例項,它提供了一個配置,下面主要來寫我們的頂級鍵 query 和 mutation
let schema = new GraphQLSchema({
query: ... ,
mutation: ...
});
export default schema;
上述程式碼建立了入口 index.js 、本地服務 server.js 以及 schema 例項 schema.js ,至此我們的 GraphQL 服務的骨架就出來了,下面我們只要來把 schema.js 填充完整就可以體驗 GraphQL 啦~
GraphQL Schema
以下所有程式碼均在 schema.js 中,開始前可以先了解一下 graphql-js
我們可以按照上述描述資料
,篩選資料
然後獲取資料
的順序生成測試程式碼感受一下 GraphQL 的魅力吧~
目標資料
首先我們先建立一個模擬資料來源 todo list:
let TODOs = [
{
"id": 111,
"title": "Read emails",
"completed": false
},
{
"id": 222,
"title": "Buy orange",
"completed": true
}
];
todo list 是一個元素為 todo object 的陣列,由於我們要給客戶端提供篩選及自省的能力,所以我們要通過 GraphQL 的 type 來描述所有組織結構,首先我們來描述元素 todo object
// 申明 todo object 的結構及組成
let TodoType = new GraphQLObjectType({
name: `todo`,
fields: function () {
return {
id: {
type: GraphQLInt, // Int 型
description: "todo object`s id"
},
title: {
type: GraphQLString, // String 型
description: "todo object`s title"
},
completed: {
type: GraphQLBoolean, // Boolean 值
description: "todo object`s status"
}
}
}
});
那麼 todo list 顯而易見就是 new GraphQLList(TodoType)
啦,即元素為 TodoType 的陣列。
Schema
有了資料來源我們就可以愉快的通過 GraphQL Schema 來取資料啦,我們的第一個 Schema 就先為獲取整個 todo list 吧,先在伺服器上註冊一個處理 GraphQL 請求的方法:
let schema = new GraphQLSchema({
query: new GraphQLObjectType({
name: `getTODOs`, // query name
description: `The TODOs!`,
fields: function () {
return {
TODOs: { // 返回結果 {TODOs: [...]}
type: new GraphQLList(TodoType),
description: `The TODOs List!`,
resolve: function () {
// 返回 todo list
return TODOs;
}
}
}
}
})
//, mutation: ...
});
之前已經建立了一個埠為3000,路由為 /graphql 的 GraphQL API,至此終於可以 $node index.js 開始我們的 GraphQL 之旅啦~
query
比如我們可以通過下面的 query 來獲取 TODOs 下的 title ,由於 TODOs 是陣列所以結果對應也是陣列:
注:通過控制檯,Postman等均可構造 POST 請求驗證結果,本文所有請求都通過 curl 來構造(包括新增 ContentType 請求頭及 data)。
introspection
在介紹自省之前,我們可以先了解一下域,每個 GraphQL 根域都有 __schema 域,這個域有一個子域叫 queryType。我們可以通過查詢這些域來了解 GraphQL 伺服器支援那些查詢,按照 Object 的方式理解其實就是通過物件的屬性可以瞭解其結構及內容
看到上面的結果大家應該都有感覺了,其實 GraphQL 請求的成功與否與介面的 Schema 設計結構息息相關,所有的資料結構查詢都是按協商好的規則進行的,還記得我們宣告的 GraphQLSchema 是怎麼寫的嗎?
{
name: `getTODOs`,
description: `The TODOs!`,
fields: function () {
return {
TODOs: {
type: new GraphQLList(TodoType),
description: `The TODOs List!`
...
}
}
}
}
發現結果是一一對應的了吧,哈哈~ 可以記住這個“萬能查詢”,同時 GraphQL 也提供了__Type, __TypeKind, __Field, __InputValue等等的關鍵字來檢測介面所支援查詢的屬性,比如我們現在已經知道了“/garphql”這個 API 會返回一個物件陣列,那我想知道他包含的物件是什麼結構咋變咧?
沒錯我們可以通過限定 __Type 去查已經註冊的 “todo” 物件來自省介面,還有很多關鍵字方法都可以達到上述的效果本文就不一一列舉了。細心的同學發現上面 __type(name: todo) 的用法了吧,同樣也可以用到我們的程式碼中來查詢具體某一條的 todo 物件:
let schema = new GraphQLSchema({
query: new GraphQLObjectType({
name: `getTODO`,
fields: function () {
return {
todo: {
type: TodoType, // 這次我們只返回一個 todo 物件
description: `The TODO!`,
args: {
id: {
type: GraphQLInt,
required: true
}
},
resolve: function (root, param, context) {
console.log(param.id);
// 這裡就可以放和資料庫的互動了,本例就簡單的返回第一個 todo 物件
return TODOs[0];
}
}
}
}
})
//, mutation: ...
});
mutation
有查詢資料當然也有修改資料,mutation 查詢和普通查詢請求(query)的重要區別在於 mutation 操作是按照順序執行的,即多次修改資料後再查詢,其返回一定是最後一次修改後的結果:
let schema = new GraphQLSchema({
// query: ... ,
mutation: new GraphQLObjectType({
name: `updateTODO`,
fields: {
updateTODO: {
type: TodoType,
description: `Update the TODO status`,
args: {
id: {
type: GraphQLInt,
required: true
}
},
resolve: function (root, param, context) {
// 這裡就可以放和資料庫的互動了,本例就簡單的更新 completed 屬性
console.log(param.id);
TODOs[0].completed = true;
return TODOs[0];
}
}
}
})
});
除錯
GraphiQL 可以快速聯想搜尋介面,並提供了非常強大的自省能力,是很好的提高 GraphQL 開發效率的工具
總結
正如官方所說 GraphQL 是一個查詢語言,而且目前還未完成,未來也可能會有更多更大的變動,但已經拓寬了我們的思路,讓我們看到了更多的可能性。目前 GraphQL 利好主要是在於前端的開發效率,落地時需要服務端的全力配合,也存在著一定的安全風險(暴力破解介面能力等),最大的效能瓶頸可能來自於資料庫查詢,但究竟好不好用,關鍵是看你怎麼用了,對吧? 我們仍在前行,陽光總在風雨後。
相關文章
- 快樂小demo-Vue實現todoList 記事本Vue
- GraphQL 基礎實踐
- 小洋的Python入門筆記😀Python筆記
- 記事本
- 基於 GraphQL 實踐的一點思考
- GraphQL java工程化實踐Java
- Apollo GraphQL 服務端實踐服務端
- GraphQL 從入門到實踐
- 記事本介面
- Shell 記事本
- 【Java】實現記事本(完整版)Java
- 基於SPA架構的GraphQL工程實踐架構
- 前端應該知道的GraphQL前端
- windows10的記事本在哪裡_win10開啟記事本的步驟WindowsWin10
- win10記事本怎麼開啟_win10的記事本在哪裡Win10
- 你知道的Electron小小記事本
- ROS小車實踐記錄(五)ROS
- 基於 GraphQL 的雲音樂 BFF 建設實踐
- 兩款可替代印象筆記的記事本筆記
- 「輕算賬」小程式實踐筆記筆記
- 多功能記事本:Notebooks for MacMac
- Notebooks for Mac多功能記事本Mac
- NoteBook - 基於 Hyperf 的記事本專案
- 微前端實踐前端
- rosedb 事務實踐ROS
- C# 記事本儲存logC#
- 開發一款記事本
- 【前端軼事】Chrome 小恐龍背後的故事前端Chrome
- 前端小bug記錄前端
- Mac記事本工具Soulver3的使用技巧Mac
- 讀小程式效能優優化實踐-筆記優化筆記
- [實踐系列] 前端路由前端路由
- qiankun微前端實踐前端
- 記事本怎麼轉換成excel表格 怎麼把記事本資料生成excel資料Excel
- 前端圖床搭建實踐(前端篇)前端圖床
- 聊聊微前端的原理和實踐前端
- Babel 在提升前端效率的實踐Babel前端
- IMVC(同構 MVC)的前端實踐MVC前端
- lerna管理前端packages的最佳實踐前端Package