概述
现在是时候深入到数据源,我们将在这门课程中一直使用它。
在本课中,我们将
- 探索房源 REST API
- 创建一个可以管理我们对不同 REST 终结点的请求的类
探索真实数据
我们 解析器 获取的数据可以来自各种地方:数据库、第三方 API、Webhook 等等。这些被称为 数据源。GraphQL 的妙处在于,您可以混合使用任意数量的数据源来创建一个 API,满足您的客户端应用程序和图消费者需求。
在本课程的其余部分,我们将使用一个提供房源数据的 REST API。我们将通过以下 URL 访问它。
https://rt-airlock-services-listing.herokuapp.com/
不幸的是,我们的 数据源 缺少文档,并且包含一些不再积极使用的 字段。我们将使用 GraphQL 来创建一个更易访问且更直观的 API,供我们下游的消费者使用。
我们接下来需要回答的问题是,我们的数据在我们的 REST API 中是如何 结构化 的。这会影响我们如何检索和转换这些数据以匹配我们模式中的 字段。
我们的目标是检索精选房源的数据,并且有一个专门用于此的终结点GET /featured-listings
。让我们通过打开一个新的浏览器标签页并导航到以下 URL 来访问 /featured-listings
响应。
https://rt-airlock-services-listing.herokuapp.com/featured-listings
页面加载后,我们可以检查返回的响应的形状。
此终结点返回一个包含三个对象的数组,这些对象具有许多不同的属性。
注意: 看到了一些杂乱的 JSON 吗?单击屏幕顶部的“漂亮打印”复选框!
让我们将这些属性与我们在 GraphQL 模式 中定义的 Listing
类型进行比较:
type Listing {id: ID!title: String!numOfBeds: IntcostPerNight: FloatclosedForBookings: Boolean}
响应数组中的每个对象都包含所有这些 字段,以及我们目前不需要的其他属性——hostId
、latitude
和 longitude
等等!
{"id": "listing-1","title": "Cave campsite in snowy MoundiiX","description": "Enjoy this amazing cave campsite in snow MoundiiX, where you'll be one with the nature and wildlife in this wintery planet. All space survival amenities are available. We have complementary dehydrated wine upon your arrival. Check in between 34:00 and 72:00. The nearest village is 3AU away, so please plan accordingly. Recommended for extreme outdoor adventurers.","costPerNight": 120,"hostId": "user-1","locationType": "CAMPSITE","numOfBeds": 2,"photoThumbnail": "https://res.cloudinary.com/apollographql/image/upload/v1644350721/odyssey/federation-course2/illustrations/listings-01.png","isFeatured": true,"latitude": 1023.4,"longitude": -203.4,"closedForBookings": false,"amenities": [{"id": "am-2"} /* additional objects */]},
响应中包含我们不需要的 字段 也没关系。我们的 解析器 将负责挑选出与 查询 所需数据属性相匹配的数据属性。
设置我们的数据源
我们知道我们的数据在哪里,也知道它的结构。太棒了。现在,我们需要一种方法来请求它所提供的一切!
由于在构建 GraphQL API 时从 REST 中获取数据是一项非常常见的任务,因此 Apollo Server 提供了一个 专用 DataSource
类,专门用于此:RESTDataSource
。
让我们将这个 RESTDataSource
类添加到我们的项目中。
在终端中,在项目的根目录中,运行
npm install @apollo/datasource-rest
现在,我们应该首先创建一个可以保存所有特定于此房源服务的逻辑的文件——我们将称之为 listing-api.ts
,我们将把它存储在一个名为 datasources
的新文件夹中。
📂 src┣ 📂 datasources┃ ┗ 📄 listing-api.ts┣ 📄 graphql.d.ts┣ 📄 helpers.ts┣ 📄 index.ts┗ 📄 schema.graphql
首先,我们从 @apollo/datasource-rest
包中导入 RESTDataSource
类。
import { RESTDataSource } from "@apollo/datasource-rest";
我们将声明一个名为 ListingAPI
的类,它扩展了 RESTDataSource
。趁着现在,在我们忘记之前,先把它导出吧!
export class ListingAPI extends RESTDataSource {// ...}
接下来,让我们为我们的 REST API 的 baseURL
赋值。此属性用作所有调用的前缀。
export class ListingAPI extends RESTDataSource {baseURL = "https://rt-airlock-services-listing.herokuapp.com/";}
注意: 确保你的 ListingAPI
类 的 baseURL
值以 /
结尾。这将允许我们的辅助类发出请求并将新的路径追加到 baseURL
,而不会出现任何错误。
数据源方法
我们需要给我们的类一个方法,它可以访问返回房源数据的 REST API 终结点。让我们称它为 getFeaturedListings
。
getFeaturedListings() {// TODO}
RESTDataSource
类提供HTTP 请求的辅助方法。在我们的例子中,我们想要对 featured-listings
终结点执行 GET
请求。
getFeaturedListings() {this.get("featured-listings");}
this.get
方法是一个通用函数,允许我们为它传递一个手工制作的返回类型。从探索我们的 JSON 响应中,我们知道我们得到一个包含多个对象的数组。我们现在将返回类型定义为 any
类型的数组,但我们稍后会改进它。
getFeaturedListings() {this.get<any[]>("featured-listings");}
由于来自此终结点的响应是对象数组,因此我们可以直接返回它。
getFeaturedListings() {return this.get<any[]>("featured-listings");}
太棒了!我们的文件现在已经完成了。
练习
关键要点
- 将新的 数据源 带入我们的 GraphQL API,首先要评估其响应的形状,并确定如何最好地将其映射到我们模式中的 字段。
- 我们可以扩展
RESTDataSource
类来引入 REST API 作为 数据源 到我们的 GraphQL 服务器。
下一步
我们的 数据源 已经准备好了!但是我们如何在我们的 ListingAPI
类中实际使用它呢?在我们的 GraphQL 服务器 中?
在下一课中,我们将探索 解析器 函数,并了解如何为我们的 GraphQL 架构 中的 字段 填充数据。
分享您关于本课的疑问和评论
本课程目前处于
您需要一个 GitHub 帐户才能在下方发帖。没有吗? 请改为在 Odyssey 论坛发帖。