GraphQL 漸進學習 09-graphql-apollo-client-vue-客戶端開發
軟體環境
- vue > 2.5.x
目標
- 建立 graphql 客戶端
- 封裝請求處理
- 基於 token 驗證
程式碼
步驟
1 安裝依賴包
npm install
npm install --save vue-apollo graphql apollo-client apollo-link apollo-link-http apollo-cache-inmemory graphql-tag
-
webpack.json
包清單
"dependencies": {
"apollo-cache-inmemory": "^1.2.0",
"apollo-client": "^2.3.0",
"apollo-link": "^1.2.2",
"apollo-link-http": "^1.5.4",
"element-ui": "^2.3.7",
"graphql": "^0.13.2",
"graphql-tag": "^2.9.2",
"vue": "^2.5.2",
"vue-apollo": "^3.0.0-beta.5",
"vue-router": "^3.0.1"
},
如果遇到程式碼編譯問題,請對照我使用的包版本
2 編寫 webpack
配置
- 檔案
build/webpack.base.conf.js
module: {
rules: [
...
{
test: /.(graphql|gql)$/,
exclude: /node_modules/,
loader: `graphql-tag/loader`
}
...
]
}
- 當
import
時,自動做schema js
包裝 - 如
import QUERY_USER from `@/graphql/user.graphql`
,把QUERY_USER
列印看看
3 編寫 config.json
配置
- 檔案
src/utils/config.json
{
"graphqlServer": "http://127.0.0.1:7001/graphql",
"tokenName": "UU_AUTH_TOKEN"
}
-
graphqlServer
伺服器地址 -
tokenName
本地寫localStorage
key
名稱 ,推薦大家做本地化可以用cookie
設定過期時間
4 編寫 VueApollo
介面卡
- 檔案
src/apolloProvider.js
import Vue from `vue`
import {ApolloClient} from `apollo-client`
import {HttpLink} from `apollo-link-http`
import {InMemoryCache} from `apollo-cache-inmemory`
import VueApollo from `vue-apollo`
import { ApolloLink, concat, split } from `apollo-link`;
import { getMainDefinition } from `apollo-utilities`;
import Config from `@/utils/config.json`
Vue.use(VueApollo)
const httpLink = new HttpLink({
uri: Config.graphqlServer,
})
const authMiddleware = new ApolloLink((operation, forward) => {
const token = localStorage.getItem(Config.tokenName) || null
operation.setContext({
headers: {
Authorization: `Bearer ${token}`
}
});
return forward(operation);
})
const apolloClient = new ApolloClient({
link: concat(authMiddleware, httpLink),
cache: new InMemoryCache(),
connectToDevTools: true,
})
const apolloProvider = new VueApollo({
defaultClient: apolloClient,
defaultOptions: {
$loadingKey: `loading`
},
errorHandler (error) {
console.log(`Global apollo error handler`)
console.error(error)
}
})
export default apolloProvider
authMiddleware
中寫入Request headers token
apolloClient
中定義cache: new InMemoryCache()
- 檔案
src/main.js
import apolloProvider from `./apolloProvider`
...
new Vue({
el: `#app`,
provide: apolloProvider.provide(),
...
})
5 編寫 schema
定義
- 專案中的請求定義 我都放在了 目錄
src/graphql
下,有點像restful
的api
定義
.
├── removeUser.graphql
├── user.graphql
└── users.graphql
- 我這裡寫了 2 個查詢 1 個更新操作,名稱和服務端定義一致,這樣方便查詢修改
6 編寫 Graphql
請求
- 檔案
src/components/HelloWorld.vue
- 官方
readme.md
中只寫了一種元件
方式呼叫,我還是喜歡api
方式 - 程式碼 HelloWorld.vue
6.1 元件
方式
apollo: {
login: {
query: gql`
query queryFun($username: String!, $password: String!) {
user(username: $username, password: $password) {
id
name
token
}
}
`,
variables() {
return {
username: `ducafecat`,
password: `345457yftgyhdsfghre`
}
},
manual: true,
result({data, loading}) {
console.log(data, loading)
if (!loading) {
this.res = data
}
}
}
}
}
</script>
這種方式做查詢,適合功能單一的展示元件,靈活性感覺還是差了點,有興趣的可以去掉註釋大家體會下。
6.2 api
方式
-
query
查詢
import QUERY_USER from `@/graphql/user.graphql`
...
methods: {
handleLogin() {
this.clearData()
this.$apollo
.query({
// Query
query: QUERY_USER,
variables: {
username: `ducafecat`,
password: `12321321321321432`
},
})
.then(response => {
this.loading = false
this.res = response.data
localStorage.setItem(Config.tokenName, this.res.user.token)
alert(`登入成功,寫入Token完成,重新裝載 apolloProvider`)
window.location.reload()
})
.catch(error => {
this.loading = false
this.err = error
})
},
-
mutate
更新
handleRemoveUser() {
this.clearData()
this.$apollo
.mutate({
// Query
mutation: MUTATION_REMOVE_USER,
variables: {
id: 123
}
})
.then(response => {
this.loading = false
this.res = response.data
})
.catch(error => {
this.loading = false
this.err = error
})
},
參考
1 文章
- vue-apollo
- Egg/GraphQL
- facebook/GraphQL
- GraphQL API v4
- github/authenticating-with-graphql
- VueConf 2017 demo