10. 使用真实数据源

我们已经学习不少关于GraphQL的知识了。在之前的例子中,使用的都是存储在内存中的数据,但在现实开发中,你需要使用的是GraphQL模式后的真实数据源。

这也正是本节课所要完成的目标。我们将选择MongoDB作为数据源,并在课程的最后演示如何集成其他数据源。

现在就开始吧!


准备工作

首先你需要一个MongoDB数据库。 我们建议下载MongoDB并在本地运行它。 如果不能正常下载的话,你可以使用任何提供MongoDB服务的云解决方案

然后,复制GraphQL Sandbox项目到本地:

git clone https://github.com/kadirahq/graphql-blog-schema.git
cd graphql-blog-schema

接着,切换到server-side-schema分支。

git checkout server-side-schema

最后,安装依赖项并启动它:

npm install
npm start

我们就可以在3000端口访问shandbox项目了,http:// localhost:3000

这版的sandbox与之前的稍有不同。在前几节课的例子中,我们都是在客户端里定义schema,但这次,我们要在服务器端来定义它。

为此,我们将使用express-graphql项目。

模式文件

在本项目中,schema文件位于server / schema.js中,并且已经定义好了一个authors的根查询字段和一个名为createAuthor的mutation。

如果你学习了之前的课程的话,相信对这些东东都不会陌生吧:)


Async / promises

回想之前的例子,我们只是在resolve函数中简单地返回一个值。由于数据都在内存中,所以并不会导致什么问题。但当我们访问一个真实的数据源时,立即返回结果几乎是不可能的,因此必须有异步的处理。

ES2015 promise能帮助我们解决这个问题。我们可以在resolve函数里返回一个promise, 然后GraphQL就能快速有效的处理它们。

访问MongoDB

我们需要一个支持promise的MongoDB驱动程序来访问MongoDb,这本项目中,将使用promised-mongo,它已经安装在我们的repo里了


实现mutation

首先,需要创建一个MongoDB的连接,我们在schema.js的顶部添加下面的代码:

const mongo = require('promised-mongo');
// You can use any MONGO_URL here, whether it's locally or on cloud.
const db = mongo('mongodb://localhost/mydb');
const authorsCollection = db.collection('authors');

然后实现createAuthor的处理逻辑。so,我们使用promised-mongo这个包来提供promise的API。

mutation与mongoDB相关的代码如下:

const Mutation = new GraphQLObjectType({
  name: "Mutations",
  fields: {
    createAuthor: {
      type: Author,
      args: {
        _id: {type: new GraphQLNonNull(GraphQLString)},
        name: {type: new GraphQLNonNull(GraphQLString)},
        twitterHandle: {type: GraphQLString}
      },
      resolve: function(rootValue, args) {
        let author = Object.assign({}, args);
        return authorsCollection.insert(author)
          .then(_ => author);
      }
    }
  }
});

现在你可以按照下面的方法在GraphQL Sandbox里调用mutation了

mutation _ {
  createAuthor(
    _id: "john",
    name: "John Carter"
  ) {
    name
  }
}

代码执行后,你会得到以下结果:

{
  "data": {
    "createAuthor": {
      "name": "John Carter"
    }
  }
}

任务时间!

试试再次调用上面的mutation。 会得到什么结果咧?

  • It was successful as usual.
  • Got an empty response.
  • Got an error stating that the insert had been forbidden.
  • Got an error citing a duplicate key error.

实现根查询字段

通过上一节课,我们完成了添加新作者的方法,现在就让我们来实现authors查询字段。

这将是根查询类与MongoDB的集成哦。

const Query = new GraphQLObjectType({
  name: "RootQuery",
  fields: {
    authors: {
      type: new GraphQLList(Author),
      resolve: function() {
        return authorsCollection.find().toArray();
      }
    }
  }
});

然后,你就可以在GraphQL SandBox中检索作者了:

{
  authors {
    name
  }
}

ok的话,你能够从Mongo数据库中获取到所有作者的名字。

运行似乎很顺利嘛,可是却有一个小问题哦。看看你是否发现它了:

  • It can’t do field filtering in MongoDB level.
  • It can't limit the result.
  • It can't sort the result.
  • There is no such issue.

即使没有排序和限制功能,我们仍然可以通过传递一些参数来简单的实现这些效果。 但是如何过滤出那些在查询中提及的字段呢?

这正是本节课我们要完成的内容。

字段过滤

虽然没有直接的方法从resolve函数检索字段。 但仍有解决办法。看看修改后的resolve函数吧:

const Query = new GraphQLObjectType({
  name: "Queries",
  fields: {
    authors: {
      type: new GraphQLList(Author),
      resolve: function(rootValue, args, info) {
        let fields = {};
        let fieldASTs = info.fieldASTs;
        fieldASTs[0].selectionSet.selections.map(function(selection) {
          fields[selection.name.value] = 1;
        });
        return authorsCollection.find({}, fields).toArray();
      }
    }
  }
});

我们使用了传给resolve函数的第三个参数:info。它有该查询解析后的AST数据。通过它,我们就可以检索字段啦,如上面的代码所示。

不止于此

即使仅使用promised-mongo,我们也可以很容易地将Mongo数据库与GraphQL模式集成。当然,这只是方法之一,还有好几种方式能够将现有数据源集成到GraphQL中,让我来告诉你它们中的一些吧:

这仅仅是个开始。 将来会有有越来越多的方法实现GraphQL与不同类型数据源的集成。

results matching ""

    No results matching ""