Here's to Change

请问你真的有在努力吗 ?

0%

GraphQL & Apollo Client for Android

关于 graphql 和 RestFul 的差别我就不说了,很多人都说过,如果自己没有体会我写在这里也不过是复制粘贴而已。这片文章的内容是我三个月使用过程中的经验,同时也是我在公司内部的技术分享,从 ppt 改成博客,勉强能够凑成一篇吧。

query

首先来看一个 query 文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
{
search(first: 10, query: "lib", after: "Y3Vyc29yOjE=", type: REPOSITORY) {
edges {
cursor
node {
__typename
... on Repository {
description
forkCount
homepageUrl
name
}
}
}
codeCount
userCount
wikiCount
repositoryCount
}
}

这是 github v4 版,也就是 graphql 的接口,大家可以在这个地址 https://developer.github.com/v4/explorer/ 登录后就可以查看所有的接口文档,绝对要比 v3 版本的清晰很多,并且可以直接做测试,类似于 postman 那样。这个工具的名字叫做 graphiql。

在上面的 query 文件中,我调用了 搜索接口,搜索参数为 lib,数据请求 10 条,并且是位于索引 “Y3Vyc29yOjE=” 之后的 10 条,而要求搜索的类型则是 Repository。这其实就对应于 CRUD 中 retrieve 操作。

要说明的是,上面的 query 与在上面的地址中进行测试编写的 query 文件并不同,因为客户端需要该文件来生成相关构造类和方法,因此比直接在 graphiql 中的 query 多最外面一层,其他所有操作也类似。比如上面的文件如果是用在 Android 客户端中应该是这样的:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
query Search($first:Int,$query:String,$after:String,$type:SearchType){ 
search(first:$first,query:$query,after:$after,type:$type){
edges{
cursor
node{
__typename
#... RepostoryFragment
... on Repository{
description
forkCount
homepageUrl
name
}
}
}
codeCount
userCount
wikiCount
repositoryCount
}
}

差异是由于这里的参数是直接写进去的,如果你所有的参数都不会变,那么直接写成后者的样式也是完全可以的。

mutation

接着来看一个 mutation 文件:

1
2
3
4
5
mutation UpdatePhoto($photos:[PhotoInput]){
updatePhoto(photos:$photos){
id
}
}

mutation 对应着 CRUD 中的 create、update、delete,也就是所有的修改、删除、插入操作。这个接口如要传入一个 PhotoInput 对象数组,对象中除了 ID,只需要放入需要修改的字段即可,前提是其他字段都是可空类型(graphql 中在类型后面加”!”表示不可空类型,如果没有则表示该字段可为空,可以直接传入 null)。

ApolloClient

知道了最基本的 query 和 mutation。我们就可以开始使用 apollo client 了。ApolloClient 是一套在客户端和前端快速使用 graphql 的实现,如果没有这一套实现,客户端要使用 graphql 是远比 RestFul API 麻烦的。Apollo Client 目前支持 React、Vue.js、Angular、Android、iOS 等在内的多个平台,官网地址是 graphql.org 。

如何使用

目前 Android 的 Apollo Client 的最新版本是 0.4.3

如果你英语还凑合,也可以直接在 github 上的仓库中查看如何集成和使用:apollo-android

首先要在 AS 中配置 gradle 插件:
在 project 的 build.gradle 的 dependencies 标记下添加:

1
2
3
4
5
6
7
8
buildscript {
repositories {
jcenter()
}
dependencies {
classpath 'com.apollographql.apollo:apollo-gradle-plugin:x.y.z'
}
}

然后在 app 下的 build.gradle 中添加

1
2
3
4
5
apply plugin: 'com.apollographql.android'

dependencies {
compile 'com.apollographql.apollo:apollo-runtime:x.y.z'
}

如果你同时使用 kotlin,那么 graphql 的 apply plugin 必须写在 kotlin 的 plugin 之前。

接下来我们需要生成 schema.json 文件。看到前面的 mutation 中的 PhotoInput,你也许会问,这个对象的定义在哪里,我怎么知道里面有什么属性,答案都在 schema.json 中。这个文件是对服务端所有接口,定义的类,方法等的描述,一般这个文件少说也要几千行,所以肯定是要自动化生成的。

生成这个文件需要一个工具:apollo-codegen,而这个文件是用 node 写的,所以你需要先安装 node 环境,这里我就不多说了。在 node 环境只需要执行

1
npm install -g apollo-codegen

就安装好了。然后执行

1
apollo-codegen download-schema server-url --output dir/schema.json

就会生成 schema.json 文件了。其中 server-url 是 graphql 后台的地址,一般的格式是 http://xxxx.xxx.xx/graphql,而 dir 就是本地的存放路径了,这里我建议为 app/src/main/graphql/packageName/api/schema.json 。以后所有的 graphql 查询文件也都放在这个路径下,这样可以便于识别,以免造成不必要的麻烦,在这里我的确是踩了一点坑的。

schema.json 这个文件很重要,apollo 的插件就是根据这个文件中的内容去检测你的 graphql 文件编写的是否正确的,也就是说,这个文件必须跟服务端的实现保持一致,在服务端有了任何修改,你都需要重新运行上面的 download-schema 命令来更新 schema 文件。这也是 graphql 一个比较麻烦的办法。

现在我们就可以编写 graphql 的 query 文件了,写好后放在前面提到的 app/src/main/graphql/packageName/api/ 路径下。

现在,只需要点击一下 build ,就可以看到生成的接口类了。你也能直接调用了。