李承武

uni-app配置使用GraphQL

dcloud官方暂时没有关于如何支持GraphQL的说明,不过uni-app配置GraphQL还是挺简单的,但不熟悉uni-app和GraphQL的童鞋配置起来还是会比较迷茫,到处是坑。。。

其实早已经有热心的童鞋提拱支持uni-app的GraphQL client,我看了一下他github上的源码,发现是移植自国外一位GraphQL大神的库,而且该库相关说明和用例比较缺乏,说白了就是生态支持不好,遇到问题很难找到解决方法,而且该童鞋也不维护了,很多时候还得自己看源码慢慢调试摸索,我用来开发了一个项目,涉及上传功能的时候弄到我想哭。。。

使用Axios请求GraphQL API

提到GraphQL client,了解GraphQL的童鞋可能第一反应想到的就是Apollo,其实如果你无需用到Apollo生态及其功能特性,即不必使用此类框架,你可以使用任何你想要的库。

GraphQL本身并不关心网络层,所以你完全可以使用普通的HTTP方法带上具有GraphQL查询和修改的结构内容对其进行操作。

有时候引入框架意味着对现有架构进行大量修改,以至于很多人不敢在老项目中使用或直接放弃GraphQL,对大多数前端开发者来说,可能所有http请求仅用Axios就能搞定是最理想的状态。。。

所以我们可以用Axios这样请求GraphQL API:

import axios from 'axios'

axios.post(graphqlURL, {
query: `
    query albums {
      albums(limit: ${this.limit) {
          title
          content
          images
      }
    }
`}).then(res => {
    console.log(res)
}).catch(err => {
    console.log(err)
})

graphql-tag and print

graphql-tag用来把string转化成 GraphQL的AST。既然在客户端发请求时仍然使用string,为什么需要客户端转成AST呢?这有几个原因:

  • 编译成 AST 可以在编译时检查确保 query 的合法性 (比如查询了不存在的字段)
  • 可以按照特定条件对多个 query 进行合并,多个请求合并为同一个请求
  • 可以按照客户端缓存对某些字段进行过滤 (skip),避免冗余查询
  • ... 诸多好处

在服务器端也有诸多好处,如:

  • 解析出来客户端请求的 field,与数据库一对比,按需请求数据库字段
  • 添加新的 directives
  • ...

而print的作用是:Converts an AST into a string, using one set of reasonable formatting rules

import axios from 'axios'
import gql from 'graphql-tag'
import { print } from 'graphql'

const LOGIN = gql`mutation login($identifier:String!, $password:String!){
                    login(input:{
                        identifier: $identifier
                        password: $password
                    }){
                        jwt
                        user {
                            username
                        }
                    }
                }`

axios.post(graphqlURL, {
    query: print(LOGIN),
    variables: {
        identifier: this.email,
        password: this.password
    }
})
.then(res => {
    console.log(res)
})
.catch(err => {
    console.log(err)
})

让uni-app支持请求GraphQL API

好吧,说了那么多该进主题了,下面我们开始配置uni-app。

uni-app里直接使用Axios在App端和小程序端会报错,得自己定义适配,可参考
在uniapp设计的APP中引入axios,支持cookie(真机亲测可行)

我在这里就不折腾了,直接在uni-app插件市场下载仿Axios的库luch-request

// 如果你的项目还没有package.json文件
// npm init -y

// 安装
npm install graphql graphql-tag
// main.js

import Request from '@/utils/luch-request/index.js'
import gql from 'graphql-tag'
import { print } from 'graphql'

Vue.prototype.$http = new Request()
Vue.prototype.$gql = gql
Vue.prototype.$print = print

我们来测试一下请求是否能成功

const LOGIN = this.$gql`mutation login($identifier:String!, $password:String!){
                    login(input:{
                        identifier: $identifier
                        password: $password
                    }){
                        jwt
                        user {
                            username
                        }
                    }
                }`

this.$http.post(graphqlURL, {
    query: this.$print(LOGIN),
    variables: {
        identifier: this.email,
        password: this.password
    }
})
.then(res => {
    console.log(res)
})
.catch(err => {
    console.log(err)
})

发现graphql报错

Uncaught ReferenceError: require is not defined
    at eval (parser.mjs?2604:1)
    at Module.../../../../project/uni-app-graphql/node_modules/graphql/language/parser.mjs (chunk-vendors.js:34)
    at __webpack_require__ (index.js:787)
    at fn (index.js:150)
    at eval (index.js?f743:1)
    at Object.../../../../project/uni-app-graphql/node_modules/graphql-tag/src/index.js (chunk-vendors.js:10)
    at __webpack_require__ (index.js:787)
    at fn (index.js:150)
    at eval (main.js?3d9e:4)
    at Object.../../../../project/uni-app-graphql/main.js (index.js:985)

不熟悉webpack和vue.config.js配置的估计到这里够呛。。。

google一下说是要让webpack支持mjs后缀,在vue.config.js中尝试了webpack的配置方法还是不行,后来才发现vue有自己的一套vue config命令。。。

根目录新建vue.config.js文件并添加以下代码

module.exports = {
    chainWebpack: (config) => {
        // GraphQL Loader
        config.module // optional
            .rule('graphql')
            .test(/\.graphql$/)
            .use('graphql-tag/loader')
            .loader('graphql-tag/loader')
            .end()

        config.module
            .rule('mjs')
            .test(/\.mjs$/)
            .include.add(/node_modules/)
            .end()
            .type('javascript/auto')
            .end()

        config.resolve.extensions
            .add('.mjs')
            .add('.gql')
            .add('.graphql')
            .end()
    }
}

好了,现在你可以愉快地使用Axios一边请求GraphQL API,一边请求RESTful API。。。

enjoy life

参考:
https://github.com/Pines-Cheng/blog/issues/79
https://github.com/vuejs/vue-cli/issues/1637

评论