记录一个从枯燥学习 GraphQL 的过程,到发现项目 Gitter,模仿项目 Github-Trending-API,最后做一个自己的学习项目 Github-Trending-GraphQL。
一开始我是这样想的,最后我是这样做的,复盘整个学习过程。
graphql 是什么? 在之前的项目中我们主要使用 graphql 来做已有接口数据的合并,这个主要处理已有 rest 相关服务接口的情况下,我们做了一个中间数据处理层。
最近在思考团队服务项目开发的时候,因为在开发中如果基于 rest 接口来开发的会,会定义很多路由。为了偷懒不去定义路由,于是决定在项目中使用 graphql (其实只是为了装B,我在项目中用了最新的XX技术),中间还有一些其他的思考。
Graphql 模型有三种类型的操作。
Query查询数据(R)。
# standard query { field } # shorthand { fields } Mutation新增、更新或删除数据(CUD)。
mutation { do( arguments ) { fields } } Objects表示可以访问的资源。
# Repository 包含项目的内容 # Implements # Connections # Fields Implements学不动了,省略....
受其它项目启发在枯燥的文档学习过程中,中间看到一个博客是推荐自己的小程序 gitter,出于习惯抓了一下小程序的请求,发现了趋势排行是通过 github-trending-api.now.sh 获取的数据,接着就找到了这个 API 对应的项目 github-trending-api。
在这之前我也看过几次 GitHub GraphQL API,只是趋于时间与其他因素(懒),一直没有使用落实到实际的项目中。发现官方没有提供 Trending API,github-trending-api 项目新增了 V3 中的Trending API,我是不是可以模仿该项目提供一个 GraphQL API。
带着两个目的开始一个新项目:
学习 GraphQL
做一个开源项目
初始化项目最简单的实现方式就是提供一个 GraphQL server,然后直接请求 github-trending-api.now.sh 。这种用法对于项目已有微服务的团队,可以利用中间服务层来合并数据请求,以及嵌套数据查询等。
GraphQL server 使用的是 Apollo Server,用它来创建一个 Node 服务,定义好 Schema,增加 resolver 解析函数。
在一开始学习的基础只是派上用场,GitHub Trending 主要提供两个方面,一个是 Repository ,另外一个是 Developer。
type Repository { author: String contributors: [Contributor] currentPeriodStars: Int description: String forks: Int language: Lang name: String stars: Int url: String }Repository 中除了基本的 scalar type 还有两个是 contributor 和 language,一个数组数据,一个是对象,继续细分类型下去就得到了
type Contributor { avatar: String url: String username: String } type Lang { name: String color: String }Developer 分析数据后一样得到一个数据结构
type Developer { avatar: String name: String repository: RepositoryMini username: String url: String }其中项目仓库是一个对象数据,细分下来可以得到一个
type RepositoryMini { description: String name: String url: String } Query 如何定义定义好了基本数据类型 Repository 和 Developer 以后,需要对外提供一个统一的 Query,于是得到了一个新的根数据类型
type Query { repositories: [Repository], developers: [Developer] }实际的查询趋势过程中我们还会增加参数,一个参数是 language,一个参数 since,其中 since 只能取 daily、 weekly、 monthly ,但实际也能取其它值,只是默认的还是 daily。修改后得到了下面的结果
type Query { repositories(language: String, since: String): [Repository], developers(language: String, since: String): [Developer] }如果要验证 since 只能取三个值中的一直,需要新增一个枚举类型
type Query { repositories(language: String, since: Since): [Repository], developers(language: String, since: Since): [Developer] } enum Since { daily weekly monthly } 如何优化 Query上述写法实际过程中可能还会有这样一个问题,如果要同时查询获得 Repository 和 Developer 的数据,需要按照筛选条件查询的适合,需要重复传递参数,再提升一下这两个类型实际是属于类型 Trending 的。新增一个类型
type Trending { repositories: [Repository] developers: [Developer] }根查询 Query 也可以修改一下了
type Query { trending(language: String, since: String): Trending } 客户端发起查询请求按照最终我们定义好的数据结构,我们可以发起一个这样的 query
{ Trending(language: "javascript", since: "daily") { repositories { name author description language { name color } forks stars contributors { avatar url username } currentPeriodStars url } developers { avatar name repository { url name description } username url } } }