sql server 本地数据源_Apollo入门引导(二):连接数据源

本文介绍了如何在Apollo GraphQL服务中连接到SQL Server和REST API数据源。首先,通过扩展`RestDataSource`类连接到SpaceX v2 REST API,实现了数据获取方法。接着,创建了一个自定义数据源以连接SQLite数据库,用于处理可写操作。最后,将这两个数据源添加到Apollo Server中,使得GraphQL API能够与多种数据源交互。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1f6b99835fdccddd0cdf442de7b3e923.png

接上篇 —— Apollo 入门引导(一):构建 schema —— 继续翻译 Apollo 的官网入门引导。

从多个数据源获取数据。

Apollo 入门引导 - 目录:

  1. 介绍
  2. 构建 schema
  3. 连接数据源
  4. 编写查询解析器
  5. 编写变更解析器
  6. 连接 Apollo Studio
  7. 创建 Apollo 客户端
  8. 通过查询获取数据
  9. 通过变更修改数据
  10. 管理本地状态
完成时间:10 分钟

现在已经构建了 schema,接下来需要将数据源连接到 Apollo 服务。数据源是存储用于填充 schema 字段数据的任何数据库、服务或 API。 GraphQL API 可以与几种数据源的任何组合进行交互。

Apollo 提供了一个 DataSource 类,可以扩展该类以处理特定类型数据源的交互逻辑。在本节中,将扩展 DataSource 以将 REST API 和 SQL 数据库都连接到 Apollo 服务。不用担心,无需熟悉这些任一技术中就可以跟随示例一起学习。

连接 REST API

先将SpaceX v2 REST API连接到服务。为此,将使用 apollo-datasource-rest 包中的 RESTDataSource 类。此类是 DataSource 的扩展,用于从 REST API 获取数据。要使用该类,可以对其进行“继承(extend)”,并为其提供与之通信的 REST API 的基础 URL。

Space-X API 的基础 URL 为 https://api.spacexdata.com/v2/。通过将以下代码添加到 src/datasources/launch.js 中来创建一个名为 LaunchAPI 的数据源:

const { RESTDataSource } = require('apollo-datasource-rest');

class LaunchAPI extends RESTDataSource {
  constructor() {
    super();
    this.baseURL = 'https://api.spacexdata.com/v2/';
  }
}

module.exports = LaunchAPI;

RESTDataSource 类无需其他设置即可自动缓存来自 REST 资源的响应。我们称此功能为“局部查询缓存(partial query caching)”。它使你能够利用 REST API 已经公开的缓存逻辑。

要了解有关使用 Apollo 数据源进行局部查询缓存的更多信息,请查看此博客文章。

编写数据获取方法

LaunchAPI 数据源需要能够获取数据的方法,这些数据是接下来的查询将请求的数据。

getAllLaunches方法

根据 schema,需要一种方法来获取所有 SpaceX 发射的列表。在 LaunchAPI 类中添加 getAllLaunches 方法:

async getAllLaunches() {
  const response = await this.get('launches');
  return Array.isArray(response)
    ? response.map(launch => this.launchReducer(launch))
    : [];
}

RESTDataSource 类提供与 HTTP 动词相对应的辅助方法,例如 GETPOST。在上面的代码中:

  1. 调用 this.get('launches')https://api.spacexdata.com/v2/launches 发送了一个 GET 请求,并将返回的launch数组存在 response 中。
  2. 使用this.launchReducer(将在下面编写)将每个返回的 launch 转换为 schema 所期望的格式。如果没有 launch,则返回一个空数组。

接下来需要编写 launchReducer 方法,该方法将返回的 launch 数据转换为 schema 期望的格式。这种方法使 schema 的结构与填充字段的数据源的结构脱钩。

首先,回想一下 Launch 对象类型在 schema 中的样子:

# YOU DON'T NEED TO COPY THIS CODE.
type Launch {
  id: ID!
  site: String
  mission: Mission
  rocket: Rocket
  isBooked: Boolean!
}

现在编写一个 launchReducer 方法,该方法将 launch 数据从 REST API 转换为上面的格式。将以下代码复制到LaunchAPI类中:

launchReducer(launch) {
  return {
    id: launch.flight_number || 0,
    cursor: `${launch.launch_date_unix}`,
    site: launch.launch_site && launch.launch_site.site_name,
    mission: {
      name: launch.mission_name,
      missionPatchSmall: launch.links.mission_patch_small,
      missionPatchLarge: launch.links.mission_patch,
    },
    rocket: {
      id: launch.rocket.rocket_id,
      name: launch.rocket.rocket_name,
      type: launch.rocket.rocket_type,
    },
  };
}

因为对 Launch 的定义可能会随着时间的推移而变化,所以使用这样的 reducer 可以使 getAllLaunches 方法保持简洁。它还有助于测试 LaunchAPI 类,这将在后面介绍。

getLaunchById方法

schema 还支持通过 ID 提取单次发射的信息。为了支持这一点,将 2 个方法添加到 LaunchAPI 类中:getLaunchByIdgetLaunchesByIds

async getLaunchById({ launchId }) {
  const response = await this.get('launches', { flight_number: launchId });
  return this.launchReducer(response[0]);
}

getLaunchesByIds({ launchIds }) {
  return Promise.all(
    launchIds.map(launchId => this.getLaunchById({ launchId })),
  );
}

getLaunchById 方法接收发射的航班号参数,并返回相关发射的数据。getLaunchesByIds 方法将多次调用 getLaunchById,并将结果拼成数组后返回。

LaunchAPI类已完成!接下来,将数据库连接到服务。

连接数据库

SpaceX API 是用于获取发射数据的只读数据源。所以还需要一个 可写(writable) 数据源,该数据源允许存储应用程序数据,例如用户身份和预订的座位。为此,将连接到 SQLite 数据库并用 Sequelize 来操作 ORM。package.json 文件包含了这些依赖关系,因此它们已经通过在 npm install 中一起被安装了。

对于理解 Apollo 数据源来说,由于本节包含的 SQL 特定代码不是必需的,因此 UserAPI 的数据源已经提前写在了 src/datasources/user.js。导航到该文件,以便我们介绍更高级概念。

构建自定义数据源

目前,Apollo 还没有为 SQL 数据库提供规范的 DataSource 子类(如果你有兴趣提供帮助,我们很乐意为你提供指导)。因此,本节通过继承通用的 DataSource 类为 SQLite 数据库创建自定义数据源。

以下是 src/datasources/user.js 中演示的 DataSource 子类的核心概念:

  • initialize 方法:如果要将任何配置选项传递给子类,必须实现此方法。UserAPI 类使用 initialize 来访问我们的 API 的 上下文(context)
  • this.context:graph API 的上下文是在 GraphQL 请求中的每个 解析器(resolver) 之间共享的对象。在下一节中将详细介绍解析器。现在,只需要知道上下文对于存储和共享用户信息很有帮助。
  • 缓存:尽管 RESTDataSource 类提供了内置的缓存,但是通用的 DataSource 类却 没有 提供。可以使用cache primitives构建自己的缓存功能。

让我们看一下 src/datasources/user.js 中的一些方法,这些方法用于获取和更新数据库中的数据。将在下一部分中引用这些内容:

  • findOrCreateUser({email}):在数据库中查找或创建具有给定 email 的用户。
  • bookTrips({launchIds}):接收一个带有 launchIds 数组的对象参数,并给已登录的用户预定它们。
  • cancelTrip({launchId}):接收一个带有 launchId 的对象参数,并取消登录用户的发射预定。
  • getLaunchIdsByUser():返回已登录用户的所有预订行程。
  • isBookedOnLaunch({launchId}):确定登录用户是否已预订特定发射的行程。

将数据源添加到 Apollo Server

现在已经建立了两个数据源,需要将它们添加到 Apollo 服务中。

dataSources 选项传给 ApolloServer 构造函数。此选项是一个函数,返回包含新的实例化后的数据源对象。

导航到 src/index.js 并添加新加的代码:

const { ApolloServer } = require('apollo-server');
const typeDefs = require('./schema');
const { createStore } = require('./utils');

const LaunchAPI = require('./datasources/launch');
const UserAPI = require('./datasources/user');

const store = createStore();

const server = new ApolloServer({
  typeDefs,
  dataSources: () => ({
    launchAPI: new LaunchAPI(),
    userAPI: new UserAPI({ store }),
  }),
});

server.listen().then(({ url }) => {});

首先,导入并调用 createStore 函数启动 SQLite 数据库。然后将 dataSources 函数添加到 ApolloServer 构造函数中,以将 LaunchAPIUserAPI 的实例连接到 graph。并确保将数据库传递给了 UserAPI 构造函数。

如果在数据源中使用 this.context,则需要注意,在 dataSources 函数中创建 新(new) 的实例而不能共享单个实例。否则,在为特定用户执行异步代码时可能会调用 initialize,将 this.context 替换为了 其他 用户的上下文。

现在已经将数据源连接到 Apollo 服务,是时候进入下一部分,学习如何从解析器内部与数据源进行交互。


前端记事本,不定期更新,欢迎关注!

  • 微信公众号: 林景宜的记事本
  • 博客:林景宜的记事本
  • 掘金专栏:林景宜的记事本
  • 知乎专栏: 林景宜的记事本
  • Github: MageeLin

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值