GraphQL 是什么

Facebook 开发的一种数据查询语言

GraphQL 使用 Schema 来描述数据,并通过制定和实现 GraphQL 规范定义了支持 Schema 查询的 DSQL (Domain Specific Query Language,领域特定查询语言,由 FACEBOOK 提出。
GraphQL 学习笔记 - 图1

特点

  • 请求需要的数据,不多不少,只取得需要的字段
  • 获取多个资源,只用一个请求
  • 描述所有可能类型的系统。便于维护,根据需求平滑演进,添加或者隐藏字段。

GraphQL 和 Restful 对比

  • Restful 一个接口只能返回一个资源,GraphQL 一次可以获取多个资源。
  • Restful 用不同的 url 来区分资源,GraphQL 用类型区分资源。

实例

  1. const express = require('express');
  2. const { buildSchema } = require('graphql');
  3. const grapqlHTTP = require('express-graphql');
  4. // 定义 schema,查询和类型
  5. const schema = buildSchema(`
  6. type Query {
  7. hello: String,
  8. accountName: String,
  9. }
  10. `);
  11. // 定义查询对应的处理器
  12. const root = {
  13. hello() {
  14. return 'hello world';
  15. },
  16. accountName() {
  17. return '张三';
  18. }
  19. };
  20. const app = express();
  21. app.use('/graphql', grapqlHTTP({
  22. schema: schema,
  23. rootValue: root,
  24. graphiql: true
  25. }));
  26. app.listen(3000);

基本参数类型

基本数据类型:String、Int、Float、Boolean、ID,都可以在 shema 声明。

参数传递

  • 和 JavaScript 传递参数一样,小括号内定义形参,但是注意:参数需要定义类型。
  • !(叹号)代表参数不能为空。
  1. type Query {
  2. rollDice(numDice: Int!, numSides: Int): [Int]
  3. }
  1. const express = require('express');
  2. const { buildSchema } = require('graphql');
  3. const grapqlHTTP = require('express-graphql');
  4. // 定义 schema,查询和类型
  5. const schema = buildSchema(`
  6. type Query {
  7. getClassMates(classNo:Int!): [String]
  8. }
  9. `);
  10. // 定义查询对应的处理器
  11. const root = {
  12. getClassMates({ classNo }) {
  13. const obj = {
  14. 32: ['小明', '小李', '小鱼'],
  15. 61: ['大三', '大力', '大开'],
  16. };
  17. return obj[classNo];
  18. }
  19. };
  20. const app = express();
  21. app.use('/graphql', grapqlHTTP({
  22. schema: schema,
  23. rootValue: root,
  24. graphiql: true
  25. }));
  26. app.listen(3000);

自定义参数类型

  1. const express = require('express');
  2. const { buildSchema } = require('graphql');
  3. const grapqlHTTP = require('express-graphql');
  4. // 定义 schema,查询和类型
  5. const schema = buildSchema(`
  6. type Account {
  7. name: String
  8. age: Int
  9. sex: String
  10. department: String
  11. salary(city: String): Int
  12. }
  13. type Query {
  14. getClassMates(classNo: Int!): [String]
  15. account(username: String): Account
  16. }
  17. `);
  18. // 定义查询对应的处理器
  19. const root = {
  20. getClassMates({ classNo }) {
  21. const obj = {
  22. 32: ['小明', '小李', '小鱼'],
  23. 61: ['大三', '大力', '大开'],
  24. };
  25. return obj[classNo];
  26. },
  27. account({ username }) {
  28. const name = username;
  29. const sex = '男';
  30. const age = 18;
  31. const department = '开发部';
  32. const salary = ({ city }) => {
  33. if( city === '上海' ) {
  34. return 10000;
  35. }
  36. return 4000;
  37. };
  38. return {
  39. name,
  40. age,
  41. sex,
  42. department,
  43. salary
  44. }
  45. }
  46. };
  47. const app = express();
  48. app.use('/graphql', grapqlHTTP({
  49. schema: schema,
  50. rootValue: root,
  51. graphiql: true
  52. }));
  53. app.listen(3000);

image.png

前端调用 GraphQL 接口

public/index.html

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>graphqQL</title>
  6. </head>
  7. <body>
  8. <button id="getQuery">获取数据</button>
  9. <script>
  10. const button = document.querySelector('#getQuery');
  11. button.addEventListener('click',() => {
  12. const query = `
  13. query Account($username: String) {
  14. account(username: $username) {
  15. name
  16. age
  17. sex
  18. salary(city: "北京")
  19. }
  20. }
  21. `;
  22. const variables = { username: '李大四' };
  23. fetch('/graphql', {
  24. method: 'post',
  25. headers: {
  26. 'Content-Type': 'application/json',
  27. 'Accent': 'application/json',
  28. },
  29. body: JSON.stringify({
  30. query,
  31. variables,
  32. })
  33. }).then(res=>res.json)
  34. .catch(e=>{
  35. console.log(e);
  36. })
  37. });
  38. </script>
  39. </body>
  40. </html>

helloGraphQL.js

  1. const express = require('express');
  2. const { buildSchema } = require('graphql');
  3. const grapqlHTTP = require('express-graphql');
  4. // 定义 schema,查询和类型
  5. const schema = buildSchema(`
  6. type Account {
  7. name: String
  8. age: Int
  9. sex: String
  10. department: String
  11. salary(city: String): Int
  12. }
  13. type Query {
  14. getClassMates(classNo: Int!): [String]
  15. account(username: String): Account
  16. }
  17. `);
  18. // 定义查询对应的处理器
  19. const root = {
  20. getClassMates({ classNo }) {
  21. const obj = {
  22. 32: ['小明', '小李', '小鱼'],
  23. 61: ['大三', '大力', '大开'],
  24. };
  25. return obj[classNo];
  26. },
  27. account({ username }) {
  28. const name = username;
  29. const sex = '男';
  30. const age = 18;
  31. const department = '开发部';
  32. const salary = ({ city }) => {
  33. if( city === '上海' ) {
  34. return 10000;
  35. }
  36. return 4000;
  37. };
  38. return {
  39. name,
  40. age,
  41. sex,
  42. department,
  43. salary
  44. }
  45. }
  46. };
  47. const app = express();
  48. app.use('/graphql', grapqlHTTP({
  49. schema: schema,
  50. rootValue: root,
  51. graphiql: true
  52. }));
  53. app.use(express.static('public'));
  54. app.listen(3000);

Mutation

  1. const express = require('express');
  2. const { buildSchema } = require('graphql');
  3. const grapqlHTTP = require('express-graphql');
  4. // 定义 schema,查询和类型
  5. const schema = buildSchema(`
  6. input AccountInput {
  7. name: String
  8. age: Int
  9. sex: String
  10. department: String
  11. }
  12. type Account {
  13. name: String
  14. age: Int
  15. sex: String
  16. department: String
  17. }
  18. type Mutation {
  19. createAccount(input: AccountInput): Account
  20. updateAccount(id: ID!, input: AccountInput): Account
  21. }
  22. type Query {
  23. account: [Account]
  24. }
  25. `);
  26. const fakeDB = {};
  27. // 定义查询对应的处理器
  28. const root = {
  29. accounts(){
  30. var arr = [];
  31. for (let key in fakeDB) {
  32. arr.push(fakeDB[key]);
  33. }
  34. return arr;
  35. },
  36. createAccount({ input }) {
  37. // 相当于数据库的保存
  38. fakeDB[input.name] = input;
  39. return fakeDB[input.name]
  40. },
  41. updateAccount({ id, input }) {
  42. // 相当于数据库的更新
  43. Object.assign({}, fakeDB[id], input);
  44. fakeDB[id] = updateAccount;
  45. return updateAccount;
  46. }
  47. };
  48. const app = express();
  49. app.use('/graphql', grapqlHTTP({
  50. schema: schema,
  51. rootValue: root,
  52. graphiql: true
  53. }));
  54. app.listen(3000);

与数据库结合使用

参考

【1】GraphQL-js 中文网
【2】解析 GraphQL 的查询语法【译】| 前端外刊评论
【3】GraphQL 从入门到实践
【4】GraphQL 入门到精通(视频)
【5】GraghQL初探(一) | 奇舞周刊
【8】GraphQL 学习:Github GraphQL API v4 初探
【9】搭建你的第一个 GraphQL 服务器
【10】GraphQL-前端开发的利剑与桥梁