7. 房源 REST API
10m

概述

现在是时候深入到,我们将在这门课程中一直使用它。

在本课中,我们将

  • 探索房源 REST API
  • 创建一个可以管理我们对不同 REST 终结点的请求的类

探索真实数据

我们 获取的数据可以来自各种地方:数据库、第三方 API、Webhook 等等。这些被称为 的妙处在于,您可以混合使用任意数量的数据源来创建一个 API,满足您的客户端应用程序和图消费者需求。

在本课程的其余部分,我们将使用一个提供房源数据的 REST API。我们将通过以下 URL 访问它。

我们的 REST API 数据源
https://rt-airlock-services-listing.herokuapp.com/

不幸的是,我们的 缺少文档,并且包含一些不再积极使用的 。我们将使用 来创建一个更易访问且更直观的 API,供我们下游的消费者使用。

我们接下来需要回答的问题是,我们的数据在我们的 REST API 中是如何 结构化 的。这会影响我们如何检索和转换这些数据以匹配我们模式中的

我们的目标是检索精选房源的数据,并且有一个专门用于此的终结点GET /featured-listings。让我们通过打开一个新的浏览器标签页并导航到以下 URL 来访问 /featured-listings 响应。

GET /featured-listings 终结点
https://rt-airlock-services-listing.herokuapp.com/featured-listings

页面加载后,我们可以检查返回的响应的形状。

此终结点返回一个包含三个对象的数组,这些对象具有许多不同的属性。

https://rt-airlock-services-listing.herokuapp.com/featured-listings

A screenshot of the featured listings endpoint response

注意: 看到了一些杂乱的 JSON 吗?单击屏幕顶部的“漂亮打印”复选框!

让我们将这些属性与我们在 中定义的 Listing 类型进行比较:

type Listing {
id: ID!
title: String!
numOfBeds: Int
costPerNight: Float
closedForBookings: Boolean
}

响应数组中的每个对象都包含所有这些 ,以及我们目前不需要的其他属性——hostIdlatitudelongitude 等等!

响应中的第一个对象,突出显示与我们的模式匹配的字段
{
"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 */]
},

响应中包含我们不需要的 也没关系。我们的 将负责挑选出与 所需数据属性相匹配的数据属性。

设置我们的数据源

我们知道我们的数据在哪里,也知道它的结构。太棒了。现在,我们需要一种方法来请求它所提供的一切!

由于在构建 API 时从 REST 中获取数据是一项非常常见的任务,因此 提供了一个 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 类。

listing-api.ts
import { RESTDataSource } from "@apollo/datasource-rest";

我们将声明一个名为 ListingAPI 的类,它扩展了 RESTDataSource。趁着现在,在我们忘记之前,先把它导出吧!

listing-api.ts
export class ListingAPI extends RESTDataSource {
// ...
}

接下来,让我们为我们的 REST API 的 baseURL 赋值。此属性用作所有调用的前缀。

listing-api.ts
export class ListingAPI extends RESTDataSource {
baseURL = "https://rt-airlock-services-listing.herokuapp.com/";
}

注意: 确保你的 ListingAPI 类 的 baseURL 值以 / 结尾。这将允许我们的辅助类发出请求并将新的路径追加到 baseURL,而不会出现任何错误。

数据源方法

我们需要给我们的类一个方法,它可以访问返回房源数据的 REST API 终结点。让我们称它为 getFeaturedListings

listing-api.ts
getFeaturedListings() {
// TODO
}

RESTDataSource 类提供HTTP 请求的辅助方法。在我们的例子中,我们想要对 featured-listings 终结点执行 GET 请求。

listing-api.ts
getFeaturedListings() {
this.get("featured-listings");
}

this.get 方法是一个通用函数,允许我们为它传递一个手工制作的返回类型。从探索我们的 JSON 响应中,我们知道我们得到一个包含多个对象的数组。我们现在将返回类型定义为 any 类型的数组,但我们稍后会改进它。

listing-api.ts
getFeaturedListings() {
this.get<any[]>("featured-listings");
}

由于来自此终结点的响应是对象数组,因此我们可以直接返回它。

listing-api.ts
getFeaturedListings() {
return this.get<any[]>("featured-listings");
}

太棒了!我们的文件现在已经完成了。

练习

关于数据源,以下哪些说法是正确的?

关键要点

  • 将新的 带入我们的 API,首先要评估其响应的形状,并确定如何最好地将其映射到我们模式中的
  • 我们可以扩展 RESTDataSource 类来引入 REST API 作为 到我们的

下一步

我们的 已经准备好了!但是我们如何在我们的 ListingAPI 类中实际使用它呢?在我们的 中?

在下一课中,我们将探索 函数,并了解如何为我们的 中的 填充数据。

上一页

分享您关于本课的疑问和评论

本课程目前处于

测试版
.您的反馈有助于我们改进!如果您遇到困难或感到困惑,请告诉我们,我们会帮助您。所有评论都是公开的,必须遵循 Apollo 行为准则。请注意,已解决或已解决的评论可能会被删除。

您需要一个 GitHub 帐户才能在下方发帖。没有吗? 请改为在 Odyssey 论坛发帖。