使用Apollo Server搭建GraphQL的服务端和客户端

5,256 阅读3分钟

不懂的地方还是有很多,分享一下学习的心得,如果有错误,还望各位大佬斧正~

什么是GraphQL

GraphQL,是Facebook开源的一种api查询语言,对查询数据提供了一套完整的描述,客户端可以精准的获取需要的数据,而没有任何冗余

graphql

最基础的查询方式如上图,左边是请求,右边是响应,我希望获取todoList这个集合,集合里的每一个元素都包括_id,content,completed字段,服务端返回的数据就是我请求需要的数据,不会多也不会少

GraphQL的基础概念——Query

    type todo {
        _id: ID!
        content: String!
        completed: Boolean!
    }
  • todo表示这是一个GraphQL的对象
  • _idcontentcompletedtodo中的字段,IDStringBoolean都是graphql内置的类型
  • String!表示这个字段的值为String类型且不可为空

接着创建一个查询

    type Query {
        todoList: [todo]!
    }
  • QueryMutetion都是GraphQL的关键字,一个代表查询,一个代表变更,在这里使用了Query创建了一个查询
  • [todo]!表示字段todoList的值是一个上面定义的todo类型的数组,[todo]!表示这个字段要么是空数组[],要么是元素为todo的数组[todo,todo,...]

GraphQL中的数据类型

  • Int: 有符号的32位整数
  • Float: 有符号的双精度浮点值
  • String: UTF‐8的字符串
  • Boolean: 布尔
  • ID: 唯一的标识,在序列化为String时表示人类不可读的

还可以自定义类型

搭建GraphQL服务器

了解了查询,就来创建一个GraphQL的服务器吧 我使用的是Apollo GraphQL,这是一个非常完整的GraphQL的实现,包括了客户端和服务端 node服务器使用的是koa 现在就开始吧

首先创建一个项目,然后安装以下依赖

npm i -S apollo-server-koa graphql koa

根目录创建app.js文件

const Koa = require("koa");
const { ApolloServer } = require("apollo-server-koa");

const { gql } = require("apollo-server-koa");

// 定义从服务器获取数据的graphql方法
const typeDefs = gql`
  type todo {
    _id: ID!
    content: String!
    completed: Boolean!
  }
  type Query {
    todoList: [todo]!
  }
`;

const server = new ApolloServer({
  // 使用gql标签和字符串定义的graphql的DocumentNode
  typeDefs,
  // 开启mock
  mocks: true
});

const app = new Koa();

// applyMiddleware将graphql服务连接到koa框架
server.applyMiddleware({ app });

app.listen({ port: 4000 }, () =>
  console.log(`🚀 Server ready at http://localhost:4000${server.graphqlPath}`)
);

接着运行node app.js,在http://localhost:4000/graphql就能看见apollo server提供的playground

查询

{
  todoList{
    _id
    content
    completed
  }
}

在左边输入上方的查询,右边就会出现mock的数据了

添加resolvers

resolvers是用于解析typeDefs查询的解析器,是一个键为type名,值为一个函数的映射 在app.js中添加resolvers

// ...
// 创建一个数据
const data = [
  {
    _id: "5ca16ed7c39e5a03d8ad3547",
    content: "html5",
    completed: false
  },
  {
    _id: "5ca16ee0c39e5a03d8ad3548",
    content: "javascript",
    completed: false
  },
  {
    _id: "5ca16ee5c39e5a03d8ad3549",
    content: "css",
    completed: false
  }
];
// resolvers
// Query对应查询,todoList是一个函数,返回的是数据
// 可以写异步函数,用于真实的数据库查询
const resolvers = {
  Query: {
    todoList: () => data
  }
};
// 添加resolvers,取消掉mocks
const server = new ApolloServer({
  typeDefs,
  resolvers,
});

const app = new Koa();
//...

再次查询,返回的结果就是data的数据了

GraphQL的基础概念——Mutation

Mutation可以对应REST API中的CRUD,一个简单的mutation如下 在typeDefs中增加

    type updateResponse {
        success: Boolean!
        todoList:[todo]!
    }
    type Mutation {
        addTodo(content: String): updateResponse!
    }

这是一个Mutation的操作,增加一个todo项,返回一个updateResponse对象

  • addTodo(content: String)接收一个为String类型的参数
  • updateResponse值包括一个键名为success值为Boolean和一个键名为todoList值为todo的数组

在playground中执行

修改resolvers

const resolvers = {
    Query: {
        todoList: () => data
    },
    Mutation: {
        addTodo: (_, { content }) => {
            console.log(content);
            data.push({
                _id:Math.random().toString(36).substring(3),
                content,
                completed:false
            });
            return { success: true, todoList:data };
        },
    }
};

函数中具体的参数可查阅Resolver type signature

执行

mutation{
  addTodo(content:"css"){
    success
    todoList{
      _id
      content
      completed
    }
  }
}

mutation表示这是一个mutation操作,操作名为addTodo,接收一个名为content类型为String的参数,返回的数据是successtodoList

在nodejs的控制台能看见console出来的参数

在客户端中使用GraphQL

官方提供了包括reactreact-nativevueaugularnative-ios...等 在creact-react-app中使用

虽然官方提供了组件模式的QueryMutation组件,不过我在学习过程中,用的还是直接以JS写的方法模式,Client api参考

create-react-app的项目中安装依赖

npm install apollo-boost react-apollo graphql --save

创建client.js,并在package.json中增加proxy

import ApolloClient from "apollo-boost";
const Client = new ApolloClient();
const getList = async () => {
    return await Client.query({
        query: gql`
            {
                todoList {
                    _id
                    content
                    completed
                }
            }
        `
    });
};
const add = async content => {
    return await Client.mutate({
		// 参数,content对应的下面的$content
        variables: { content },
        mutation: gql`
            mutation add($content: String!) {
                addTodo(content: $content) {
                    success
                    todoList{
                        _id
                        content
                        completed
                    }
                }
            }
        `
    })
};
export {getList,add};

提供IDE支持

我使用的是webstorm是一款集成功能非常强大的IDE,在plugins里搜索安装JS GraphQL

导出schema.json

  • npm install -g apollo-codegen
  • 客户端根目录执行 apollo-codegen introspect-schema http://localhost:4000/graphql --output graphql.schema.json

webstrome就会提供非常智能的graphql代码格式化和补全功能了

Demo

学习过程中写了2个demo,数据库使用的mongodb,以前也没用过,也是现学的,好多都不懂……

客户端

服务端

不懂的地方依旧很多,文档是英文的又特别复杂,路漫漫其修远兮~

公司肯定不会用graphql的,rest api都成问题,唉……