浅谈NodeJS搭建GraphQL API服务

GraphQL是一种通过强类型查询语言构建api的新方法。GraphQL于2015年由Facebook发布,目前正迅速获得关注,并被Twitter和Github等其他大型公司所采用。GraphQL API设计理念是有别于REST API,简单了解可以看看这篇文章《GraphQL与REST:两种API架构

在本文中,将带大家使用NodeJs 搭建一个简单的GraphQL API服务

  • WEB服务:node
  • 数据库:postgres
  • 数据查询:
    • express
    • apolo-server-express
    • Sequelize ORM
    • graphql schema language
    • graphql-sequelize

GraphQL是什么?

GraphQL

GraphQL 既是一种用于 API 的查询语言也是一个满足你数据查询的运行时。 GraphQL 对你的 API 中的数据提供了一套易于理解的完整描述,使得客户端能够准确地获得它需要的数据,而且没有任何冗余,也让 API 更容易地随着时间推移而演进,还能用于构建强大的开发者工具。

简单的说,它是API的可查询模式,允许客户只请求他们需要的数据,并提供了一个标准化的系统来设计API,而不需要参考文档。

GraphQL 已有多种编程语言支持。下表包含一些流行的服务端框架、客户端库、服务和其他有用的内容。

服务端库除了 GraphQL JavaScript 参考实现,还有其他服务端库:

  • C# / .NET
  • Clojure
  • Elixir
  • Erlang
  • Go
  • Groovy
  • Java
  • JavaScript
  • PHP
  • Python
  • Scala
  • Ruby

介绍:http://graphql.cn/

为什么选择GraphQL

之所以选择GraphQL,是因为前端很多项目获取数据需要通过多个API组装才能获取到所需要的数据,设计API的时候经常会考虑多应用场景,导致单个场景下调用会获得多余的数据。

出于这个考虑,看到GraphiQL介绍,能够为数据声明一个模式并让客户端根据需要查询所需要的数据的想法所吸引。喜欢通过网络传输最小数量的请求,将请求自由组合在一起以获得最佳的有效负载,并在客户端和服务器上进行缓存。

GraphQL 带来的最大好处是精简请求响应内容,不会出现冗余字段,前端可以决定后端返回什么数据。当然,前端的决定权取决于后端支持什么数据,因此 GraphQL 更像是精简了返回值的 REST,而后端接口也可以一次性定义完所有功能,而不需要逐个开发。

GraphQL API 的主要应用场景是 API 网关,在客户端和服务之间提供了一个抽象层。

GraphQL特色

Node服务

选择node作为服务器端语言,因为它拥有围绕GraphQL的非常强大的社区支持,并且高度可移植。

在新版本中支持 async / wait,同步模型更容易管理,这在构建高度异步的API时是一个巨大的优势。

ORM到GraphQL适配

graphql-sequelize,将序列化模型映射到GraphQL类型、查询和更新的代码。它提供了两个优秀的抽象:

  • 用于将GraphQL查询映射到Sequelize操作的解析器
  • 将模型定义作为GraphQL类型字段列表重用的attributeFields映射。

GraphQL schema

接下来创建查询类型,如下:

// 定义查询数据类型
const managerType = new GraphQLObjectType({
    name: "manager",
    description: "A manager",
    fields: {
        id: {
            type: new GraphQLNonNull(GraphQLInt),
            description: "The id of the manager."
        },
        username: {
            type: GraphQLString,
            description: "The username of the manager."
        },
        password: {
            type: GraphQLString,
            description: "The password of the manager."
        },
        email: {
            type: GraphQLString,
            description: "The email of the manager."
        }
    }
});
// 定义查询接口
const schema = new GraphQLSchema({
    query: new GraphQLObjectType({
        name: "root",
        fields: {
            managers: {
                type: new GraphQLList(managerType),
                resolve: resolver(manager)
            },
            manager: {
                type: new GraphQLList(managerType),
                args: {
                    username: {
                        description: "username of the manager",
                        type: new GraphQLNonNull(GraphQLString)
                    }
                },
                resolve: resolver(manager)
            }
        }
    })
});

Web服务器框架

选择express作为基本的web服务器框架,是因为它在节点生态系统、插件支持和简单API中无处不在。

express允许监听端口并响应HTTP请求,但是需要另一层来接收和响应GraphQL请求。

apollo-server-express,它有一个非常简单的API,并进行了一些映射,以允许节点GraphQL模式语言中定义模式。如下:

const express = require("express");
const { ApolloServer } = require("apollo-server-express");
const schema = require("./schema");

const server = new ApolloServer({ schema });

const app = express();

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

调试及文档

浏览器打开:http://localhost:3009/graphql,GraphiQL可以很容易地让人感受到”代码即文档”的快乐。

自动生成接口文档

GraphQL调试3

  • 查询列表数据:
{
  managers {
    username
    email
  }
}

GraphQL查询列表数据

  • 按条件查询:
{
  manager(username:"QuintionTang") {
    username
    email
  }
}

GraphQL按条件查询

AJAX方式调用:

const { createApolloFetch } = require("apollo-fetch");

const fetch = createApolloFetch({
    uri: "http://localhost:3009/graphql"
});

fetch({
    query: "{ managers { username }}"
}).then(res => {
    console.log(res.data);
});

fetch({
    query: `{
        manager(username: "QuintionTang") {
        email
        id
      }
    }`
}).then(res => {
    console.log(res.data);
});

客户端实现

客户端常见的框架有 RelayApollo Client

  • Relay 是由 Facebook 官方提供的解决方案

    使用 Relay 的好处是,许多 GraphQL 的服务端框架都会支持 Relay 的标准(比如数据的分页接口)。

  • Apollo 是在 GraphQL 方面热度超高的社区

    apollo-client的实现在诸多方面宣称自己兼容 Relay 的风格,所以使用起来应该也是大同小异。

总结

本文只是一个简单的实现,个人感觉概念很吸引,在复杂的项目中能否达到预期就需要在实践过程中去体验。

GraphQL