前端调用 GraphQL API,从未如此方便!

2018-01-30 11:16:48 +08:00
 houfeng

GraphQL 既是一种用于 API 的查询语言也是一个满足你数据查询的运行时。GraphQL 对你的 API 中的数据提供了一套易于理解的完整描述,使得客户端能够准确地获得它需要的数据,而且没有任何冗余。

想更多的了解或使用 GraphQL,请移步 https://github.com/facebook/graphql

GraphQL 有针对不同语言的服务端实现,以帮助开发人员搭建 GraphQL Server

gq-loader 是一个 webpack 插件,你可以认为它一针对前端项目的一种 client 端实现,它的目的是帮助前端开发同学更简便的调用 GraphQL API,它让前端开发人员在使用 GraphQL 时更加方便,像普通 js 模块一样轻松自如,使前端开发人员能在 js 文件中通过 importrequire 导入 .gql.graphql 文件,然后直接调用。 并且它还支持通过 #import 语法导入其它 .gql 文件,比如 fragments。

#import 还提供了两个别名,分别是 #require#include,这两个别名和 #import 的用法及行为完全一致。

关注或使用 gq-loader,请访问 GitHub: https://github.com/Houfeng/gq-loader

安装

npm install gq-loader --save-dev

或者

yarn add gq-loader

基本使用

如同其它 loader 一样,首先,我们在 webpack.config.js 中添加 gq-loader 的配置

{
  test: /\.(graphql|gql)$/,
  exclude: /node_modules/,
  use: {
    loader: 'gq-loader'
    options: {
      url: 'Graphql Server URL'
    }
  }
}

然后,我们就可以在 js 文件中通过 import 来导入 .gql 文件使用它了,我们来一个简单的示例,假设已经有一个可以工作的 Graphql Server,那么,我们先创建一个可以查询用户的 getUser.gql

#import './fragment.gql' 

query MyQuery($name: String) {
  getUser(name: $name)
    ...userFields
  }
}

可以看到,我们通过 #import 引用了另外一个 .gql 文件 fragment.gql,在这个文件中我们描术了要返回的 user 的字段信息,这样我们就能在不同的地方「重用」它了,我们也创建一下这个文件

fragment userFields on User {
  name
  age
}

好了,我们可以在 js 文件中直接导入 getUser.gql,并且使用它查询用户了,从未如此简便,我们来看看

import getUser from './getUser.gql';
import React from 'react';
import ReactDOM from 'react-dom';

async function query() {
  const user = await getUser({ name: 'bob' });
  console.log('user', user);
}

function App() {
  return <button onClick={query}>click</button>;
}

ReactDOM.render(<App />, document.getElementById('root'));

在调用 getUser 时,我们可以给函数参数向 GraphQL 传递变量,这些变量就是我们的查询参数。

自定义请求

默认 gq-loader 就会帮你完成 graphql 请求,但某些场景下或许你想自已控制所有请求,如果有这样需要,我们还可以通过 request 属性来「自定义」请求,看一下示例,需要先稍微改动一下 loader 配置

{
  test: /\.(graphql|gql)$/,
  exclude: /node_modules/,
  use: {
    loader: 'gq-loader'
    options: {
      url: 'Graphql Server URL',
      //指定自动请求模块路径
      request: require.resolve('your_request_module_path');
    }
  }
}

your_request_module_path 填写自定义请求模块路径,gq-loader 将自动加载并使用对应请求模块,模块只需要改出一个「请求函数即可」,看如下自定义示例

const $ = require('jquery');

//url 是要请求的 GraphQL 服务地址
//data 是待发送的数据
//options 是自定义选项
module.exports = function(url, data, options){
  //如果有需要还可以处理 options
  return $.post(url, data);
};

其中,options 是导入 .gql 文件后「函数的第二个参数」,比如,可以这样传递 options 参数

import getUser from './getUser.gql';

async function query() {
  const options = {...};
  const user = await getUser({ name: 'bob' }, options);
  console.log('user', user);
}

完整选项

注意,gq-loader 的 extensions 无论配置何值,在 js 中 import 时都不能省略扩展名,此选项仅作用于 .gql 文件 import 其它 .gql 文件

6536 次点击
所在节点    前端开发
29 条回复
xwhxbg
2018-01-30 11:21:56 +08:00
除非前后端都是我,不然不可能用 graphql
66beta
2018-01-30 11:54:29 +08:00
@xwhxbg 此话怎讲?打一架也不能解决吗?
xwhxbg
2018-01-30 12:02:48 +08:00
@66beta 学习成本在那里,再怎么好用你没法强迫别人用,除非你是老板
Sivan
2018-01-30 12:26:44 +08:00
用不用是一回事,学一学没坏处 :P
artikle
2018-01-30 14:15:44 +08:00
用过 GraphQL 写后台接口,要注意的是它并非用来提升接口性能,相反反而会降低接口性能。
比如你一个完整响应有 10 个字段,你只要返回两个字段,后台不会只查询那两个字段,
而是先查询出完整响应,再逐字段遍历解析才返回所需的两个字段的值。
这个就导致完整响应的字段过多或者响应结果值过多都会导致接口性能下降明显。
glues
2018-01-30 14:42:21 +08:00
没看出 GraphQL 好在哪?
tinyhill
2018-01-30 14:43:03 +08:00
@Sivan 四万老师说得对
coraline
2018-01-30 14:50:55 +08:00
http://mirror.am0200.com/ 这个就是用 GitHub 的 GraphQL API 的
EPr2hh6LADQWqRVH
2018-01-30 14:51:07 +08:00
稍微通读了一下 Github 页面,看不出这个 GraphQL 哪里 Graph 了,不知道 FB 这个什么想法,是需要把全世界的东西都削足适履塞到 js 里面来吗,然后再把 js 世界的所有东西都塞到 php 思维里面

正经看一下 Neo4j 的 Cypher 吧,那才叫 Graph Query
takato
2018-01-30 15:03:40 +08:00
@avastms Cypher 好用+1
torbrowserbridge
2018-01-30 15:05:51 +08:00
用了一段时间,又滚回 MySQL 了
tamer
2018-01-30 15:33:19 +08:00
@glues don't you recognize me, brother
artikle
2018-01-30 16:02:32 +08:00
@glues GraphQL 还是有其优点的。
一个是它只返回所请求的字段信息。
比如一个用户信息响应有多个字段,但前端只需要 UserID 和 UserName,那接口能只返回 UserID 和 UserName 这两个响应字段,而不返回其他多余的响应字段,这个对于 facebook 这种每天接口请求几十几百亿次的话,减少的流量带宽还是比较可观的。
二是可以合并多个请求接口。比如后台有产品信息及产品详情页信息两个接口,在一个 GraphQL 接口里,可以同时返回产品信息和产品详情两个接口的响应结果
glues
2018-01-30 16:05:10 +08:00
@tamer 发英文?我看你这是在故意刁难我胖虎
kslr
2018-01-30 16:42:30 +08:00
@artikle #13 仅仅这两点,其他 database 也很轻松做到。我觉得重要的还是脱离了 API 吧,但是应用范围感觉不是太大。
artikle
2018-01-30 17:15:00 +08:00
@kslr 其他 database 也很轻松做到?怎么实现?
kslr
2018-01-30 17:16:41 +08:00
@artikle #16 你忘了 sql 吗?
artikle
2018-01-30 17:19:28 +08:00
@kslr sql ?难道前端传 sql 语句过来?
mcfog
2018-01-30 17:20:28 +08:00
kslr
2018-01-30 17:24:16 +08:00
@artikle #18 restful 方案有很多啊....... GraphQL 没有诞生的时候就在用了

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/427036

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX