GraphQL

作者: 倩倩_a570 | 来源:发表于2020-06-14 21:41 被阅读0次

    一、什么是GraphQL

    GraphQL 是一个用于 API 的查询语言,是一个使用基于类型系统来执行查询的服务端运行时(类型系统由你的数据定义)。GraphQL 并没有和任何特定数据库或者存储引擎绑定,而是依靠你现有的代码和数据支撑,GraphQL 可以运行在任何后端框架或者编程语言之上。

    GraphQL 全称叫 Graph Query Language,官方宣传语是“为你的 API 量身定制的查询语言”。

    用传统的方式来解释就是:相当于将你所有后端 API 组成的集合看成一个数据库,用户终端发送一个查询语句,你的 GraphQL 服务解析这条语句并通过一系列规则从你的“ API 数据库”里面将查询的数据结果返回给终端,而 GraphQL 就相当于这个系统的一个查询语言。

    二、存在的问题:

    REST API :服务端决定有哪些数据返回,客户端只能挑选使用,如果数据过于冗余也只能默默接收再对数据进行处理;而数据不能满足需求则需要请求更多的接口。以上就是我们常说的“过渡获取”和“欠缺获取”

    由于"过度"和"欠缺"的获取问题及其对客户端应用程序性能的影响,促进有效获取的 API 技术才有机会在市场上引起轰动 —— GraphQL 大胆地介入并填补了这一空白。

    举个简单的例子

    graphQL 查询语句

    {
      getCategories {
        id
        name
        products {
          id
          name
        }
      }
    }
    

    输出结果

    {
      "data": {
        "getCategories": [
          {
            "id": "1",
            "name": "吃的",
            "products": [
              {
                "id": "1",
                "name": "浪味仙"
              }
            ]
          },
          {
            "id": "2",
            "name": "喝的",
            "products": [
              {
                "id": "4",
                "name": "茶颜悦色"
              }
            ]
          }
        ]
      }
    }
    

    客户端现在不想要商品信息了 只需要获取商品分类,你只需要将你的查询语句修改一下即可

    {
      getCategories {
        id
        name
      }
    }
    

    输出结果

    {
      "data": {
        "getCategories": [
          {
            "id": "1",
            "name": "吃的"
          },
          {
            "id": "2",
            "name": "喝的"
          }
        ]
      }
    }
    

    现在我想要通过这一个查询,获取到商品分类,以及所有商品的信息

    {
      getCategories {
        id
        name
       
      }
      getProducts {
        id
        name
      }
    }
    

    输出结果

    {
      "data": {
        "getCategories": [
          {
            "id": "1",
            "name": "吃的"
          },
          {
            "id": "2",
            "name": "喝的"
          }
        ],
        "getProducts": [
          {
            "id": "1",
            "name": "浪味仙"
          },
          {
            "id": "4",
            "name": "茶颜悦色"
          }
        ]
      }
    }
    

    是不是很方便,通过上面例子,可以发现GraphQL API有如下优点:客户端可以自定义查询语句,数据获取灵活多变,服务端按需返回数据,减少网络的开销,提高了性能。而这些都是Restful API的弊端。

    三、基础概念

    在介绍GraphQL的使用之前先要了解一些概念

    1.GraphQL 类型系统(Type System)

    类型系统 是整个 GraphQL 的核心,它用来定义每个查询对象和返回对象的类型。GraphQL的Type简单可以分为两种,一种叫做Scalar Type(标量类型),另一种叫做Object Type(对象类型)。

    a)标量类型(Scalar Types)

    一个对象类型有自己的名字和字段,而某些时候,这些字段必然会解析到具体数据。这就是标量类型的来源:它们表示对应 GraphQL 查询的叶子节点。

    标量类型这个概念有点重要,这个字段是不是一个标量类型,决定了我们这个查询是不是还要继续往更深层去递归查询。

    GraphQL 自带一组默认标量类型:
    GraphQLInt:有符号 32 位整数。
    GraphQLFloat:有符号双精度浮点值。
    GraphQLString:UTF‐8 字符序列。
    GraphQLBoolean 或者 false。
    GraphQLID:ID 标量类型表示一个唯一标识符。

    b)对象类型

    一个 GraphQL schema 中的最基本的组件是对象类型,表示你可以从服务上获取到什么类型的对象,以及这个对象有什么字段。

    例如 以下这段代码中 id 、name 就是标量类型。products就是一个对象类型

     type categories {
        id
        name
        products {
          id
          name
        }
    
    b)Schema

    在 GraphQL 中,类型的定义以及查询本身都是通过 Schema 去定义的。
    Schema它是用来描述接口获取数据逻辑的。我们可以将Schema理解为多个Query组成的一张表。

    这里又涉及一个新的概念Query,GraphQL中使用Query来抽象数据的查询逻辑,当前标准下,有三种查询类型,分别是query(查询)、mutation(更改)和subscription(订阅)。

    query(查询):当获取数据时,应当选取Query类型
    mutation(更改):当尝试修改数据时,应当使用mutation类型
    subscription(订阅):当希望数据更改时,可以进行消息推送,使用subscription类型

    c)Resolver

    我们已经了解了graphQL的类型系统和schema,那么我们的数据到底怎么来呢?答案是来自 Resolver 函数。

    Resolver 的概念非常简单。Resolver 对应着 Schema 上的字段,当请求体查询某个字段时,对应的 Resolver 函数会被执行,由 Resolver 函数负责到数据库中取得数据并返回,最终将请求体中指定的字段返回。

    type Movie {
        name
        genre
    }
    type Query {
        movie: Movie!
    }
    

    当请求体查询movie时,同名的 Resolver 必须返回Movie类型的数据。当然你还可以单独为name字段使用独立的 Resolver 进行解析。

    以上是一些最基本的概念,最后我们来详细的分析一下,graphQL是如何定义并查询到数据的

    服务端的schema:

    //schema.js
    
    let categories = [
        { id: '1', name: '吃的' },
        { id: '2', name: '喝的' },
    ]
    let products = [
        { id: '1', name: '浪味仙', category: '1' },
        { id: '4', name: '茶颜悦色', category: '2' },
    ]
    //分类里定义每个字段
    const Category = new GraphQLObjectType({
        name: 'category',
        fields: () => ({
            id: { type: GraphQLString },
            name: { type: GraphQLString },
            products: {
                type: new GraphQLList(Product),//每个分类下是一个数组,而不是一个对象
                resolve(parent) {//parent代表上一层的查询结果
                    return products.filter(item => item.category === parent.id)
                }
            }
        })
    })
    //产品里定义每个字段
    const Product = new GraphQLObjectType({
        name: 'product',
        fields: () => ({
            id: { type: GraphQLString },
            name: { type: GraphQLString }
        })
    })
    //查询接口
    const RootQuery = new GraphQLObjectType({
        name: 'root',
        fields: {
            getCategories: {
                type: new GraphQLList(Category),
                args: {
                },
                resolve(parent, args) {
                    return categories
                }
            }
        }
    })
    module.exports = new GraphQLSchema({
        query: RootQuery,//查询
        mutation: RootMutation//修改
    })
    

    1.以上是一个schema文件, 导出了一个GraphQLSchema的实例,GraphQLSchema接收两个参数,一个是query,一个是mutation。
    2.RootQuery是一个GraphQLObjectType实例,name属性非必填,这个属性是最后生成接口文档的query接口名字。
    3.fields是解析函数,在这里可以理解为查询方法。
    4.getCategories就是我们定义查询的名称了。
    5.getCategories中有个type,定义了你使用getCategories能查询到的所有字段。当前查询结果是一个GraphQLList类型,也就是一个数组类型,数组的每一项就是Category。
    6.resolve中的内容为查询返回的数据。

    客户端对应的查询语法:

    query{
      getCategories {
        id,
        name,
        products{
          id,
          name,
        }
      }
    }
    

    1.首先进行第一层解析,查询类型是query同时需要它的子query名是getCategories。
    2.使用getCategories的Resolver获取解析数据,第一层解析完毕
    3.之后对第一层解析的返回值,进行第二层解析,当前getCategories还包含3个属性需要查询,分别是id、name、product。
    3.1 id和name在type Category中为标量类型,直接返回getCategories中的对应属性值。id,name的解析结束。
    3.2product在type Category类型中为对象类型,于是Granphql尝试使用Category的Resolver获取数据,当前field解析完毕。以此类推,直到所有的查询值都为标量的时候,查询结束。
    因此上例中的查询结果为:

    {
      "data": {
        "getCategories": [
          {
            "id": "1",
            "name": "吃的",
            "products": [
              {
                "id": "1",
                "name": "浪味仙"
              }
            ]
          },
          {
            "id": "2",
            "name": "喝的",
            "products": [
              {
                "id": "4",
                "name": "茶颜悦色"
              }
            ]
          }
        ]
      }
    }
    

    相关文章

      网友评论

          本文标题:GraphQL

          本文链接:https://www.haomeiwen.com/subject/ohogtktx.html