GraphQL从入门到实践

GraphQL是一种新的Api请求规范,它可以让客户端在请求中指定希望得到的数据,而不像REST那样只能在服务端进行预定义。GraphQL 的操作类型可以是 query、mutation 和subscription,描述客户端希望进行什么样的操作:

  • query 查询:获取数据
  • mutation 变更:对数据进行变更,比如增加、删除、修改
  • substription 订阅:当数据发生更改,进行消息推送

GraphQL入门

GraphQL为了方便人们学习,提供了Graphpack用来搭建零配置服务器,Graphpack会读取并发布src目录下的.graphql和resolvers.js。

mkdir graphql-demo
cd graphql-demo
npm install
npm install --save-dev graphpack

// 打开package.json 输入
"scripts": {
    "dev": "graphpack",
    "build": "graphpack build"
}

// 打开src/schema.graphql,输入
type Query {
  hello: String
}

// 打开src/resolvers.js,写入以下代码:
const resolvers = {
  Query: {
    hello: () => "Hello World!"
  }
};
export default resolvers;

然后在graphql-demo目录下执行npm run dev,打开http://localhost:4000就可以看到 GraphQL Playground。GraphQL Playground是GraphQL提供的前端页面,封装了http request。GraphQL Playground左边是输入,中间有个执行按钮,点击执行按钮会将我们输入的内容放入http request body发送给我们刚启动的服务器,进过GraphQL解析会执行相应的resolvers函数,GraphQL Playground获取到请求结果并在右边呈现。
之前我们在服务器端定义了Query类型的hello和Query类型的resolver解析函数hello,那我们要怎么获取到返回值Hello World!呢?在GraphQL Playground左边输入并执行以下代码:

// 输入
query {
  hello
}

// 输出
{
  "data": {
    "hello": "Hello world!"
  }
}

更多关于GraphQL的使用可以阅读GraphQL文档来学习。下面提供了query、mutation 和subscription的例子,供大家参考学习。

// db.js
export let users = [
  { id: 1, name: "John Doe", email: "[email protected]", age: 22 },
  { id: 2, name: "Jane Doe", email: "[email protected]", age: 23 }
];
// schema.graphql
type Query {
    hello: String
    users: [User!]!
    user(id: ID!): User!
}

type User {
    id: ID!
    name: String!
    email: String!
    age: Int
}

type Mutation {
    createUser(id: ID!, name: String!, email: String!, age: Int): User!
    updateUser(id: ID!, name: String, email: String, age: Int): User!
}

type Subscription {
    subsUser(id: ID!): User
}
// resolvers.js
import { users } from "./db";
const {PubSub, withFilter} = require('apollo-server')
const pubsub = new PubSub()
const USER_UPDATE_CHANNEL = 'USER_UPDATE'

const resolvers = {
  Query: {
    hello: () => "Hello World!",
    user: (parent, { id }, context, info) => {
      return users.find(user => user.id == id);
    },
    users: (parent, args, context, info) => {
      return users;
    }
  },
  Mutation: {
    createUser: (parent, { id, name, email, age }, context, info) => {
      const newUser = { id, name, email, age };
      users.push(newUser);
      return newUser;
    },
    updateUser: (parent, { id, name, email, age }, context, info) => {
      let newUser = users.find(user => user.id === parseInt(id));
      newUser.name = name;
      newUser.email = email;
      newUser.age = age;
      pubsub.publish(USER_UPDATE_CHANNEL, {subsUser: newUser})
      return newUser;
    }
  },
  Subscription: {
    subsUser: {
      subscribe: withFilter(
        (parent, {id}) => pubsub.asyncIterator(USER_UPDATE_CHANNEL),
        (payload, variables) =>  payload.subsUser.id === parseInt(variables.id)
      ),
      resolve: (payload, variables) => {
        console.log(' 接收到数据: ', payload)
        return payload.subsUser
      }
    }
  }
};

export default resolvers;

测试例子

Query测试例子
// hello
query {
  hello
}
// users(GraphQL返回值)
query {
  users {
    id
    name
  }
}
// user (GraphQL参数)
query {
  user(id: 1) {
    id
    name
  }
}
Mutation测试例子
// 可执行query users查看结果
mutation {
  createUser(id: 3, name: "xeon", email: "[email protected]", age: 22) {
    id
    name
    email
    age
  }
}
Subscription测试例子

在GraphQL Playground左上角新建两个tab,一个输入下面代码并执行,用于监听和相应数据更新

subscription {
  subsUser(id: 2) {
    id
    name
    email
  }
}

另一个tab执行更新操作

mutation {
  updateUser(id: 2, name: "xeon1", email: "[email protected]") {
    id
    name
    email
  }
}

GraphQL与REST

GraphQL在后端上是MVC中的Controller,用于定义API接口的参数和返回值,这似乎是和REST是一种竞争关系,而GraphQL提出“一切皆是图”口号也好像是在挑战REST提出的“一切都是资源“。但是冷静下来想一想,图也是一种资源,与其说GraphQL是颠覆REST的一种新技术,我更认可GraphQL是对REST的封装的说法,因为GraphQL在实现上主要干了两件事:

  • 提供了一个Api,用于接收请求数据
  • 根据schema.graphql解析请求数据,调用resolvers函数

技术层面上GraphQL是对REST的封装,在设计体验上GraphQL确实给我们带来了许多惊喜。就像文章开题所说的,GraphQL明显比REST更加灵活,在前后端交互上GraphQL也有许多明显的优势:

  • 减少HTTP请求,GraphQL可将业务模式自由组合,我们可以调用一次API就能获取到我们想要的数据
  • 提升HTTP请求速度,GraphQL可以指定需要的数据,避免传输无效的数据
  • 代码复用率高,减少后端代码量,特别是面向用户体验的API
  • GraphQL的Subscription封装了管道技术,更方便的实时交互
  • 减少前后端开发人员的沟通成本
    ···

BFF下GraphQL的地位

GraphQL在中台架构和BFF开发模式上的地位举足轻重。前端开发者选择GraphQL开发BFF层的无数种理由:

  • GraphQL的类型系统和类型语言与前端的TS不谋而合,前端开发者对GraphQL的学习成本并不高
  • GraphQL提供了多种后端语言库,这让GraphQL可以很好的对接各种模式的业务中台
  • GraphQL与REST兼容,可以从REST平稳地过度到GraphQL
  • 虽然GraphQL建议我们把业务建模为图,但是这并不意味着GraphQL与关系型数据库是相悖的。“图”是通过GraphQL的类型语言来构建的,与Model层无关,更与数据库无关,因此GraphQL可以很好的兼容关系型数据库

你可能感兴趣的:(GraphQL从入门到实践)