Unlimited Plugins, WordPress themes, videos & courses! Unlimited asset downloads! From $16.50/m
Advertisement
  1. Code
  2. Node.js
Code

使用 AWS SimpleDB 和 Node.js 构建 REST API

by
Difficulty:IntermediateLength:LongLanguages:

Chinese (Simplified) (中文(简体)) translation by Fuhuan (you can also view the original English article)

SimpleDB 是 Amazon Web Services(AWS)提供的远程数据库。 基于 SQL 语言的使用或不使用,数据存储通常分为 SQL 和 NoSQL。  NoSQL 数据存储通常基于更简单的键 / 值设置。  SimpleDB 横跨这一行 - 它是一个键 / 值存储,也可以使用 SQL 的变体进行检索。 大多数 SQL 语言都基于一个模式,该模式列出了数据的行和列,但 SimpleDB 是一个无模式的数据库,这使得数据存储非常灵活。

在 SimpleDB 数据库模型中,有项目,属性和值。 在 SimpleDB 数据库模型中,有项目,属性和值。 每个项目最多可以有 256 对属性和值。 SimpleDB 的一个方面是每个项目的属性可以有多个对。 我认为考虑 SimpleDB 的最佳方法是考虑电子表格,但不是每个列 / 行交集代表一个值,它代表一个值数组。

Grid illustrating Item Name Attribute Value relationship

此图表表示存储在 SimpleDB 域中的两个项目。  术语域类似于其他数据库中的 “表”。

第一列是项目名称 - 这是唯一一个只能包含单个值的列,你可以将其视为唯一索引列。

其他四列(宠物,汽车,家具和电话)代表当前在此域中的属性 - 不限于此,因此每个项目都可以具有完全唯一的属性集。  在此数据中,项目 personInventory1 上的属性 pets 有三对; 用 JSON 表示,它看起来像这样:

另一方面,项目 personInventory2 只有一对:

虽然你不必为每个项目提供相同的属性,但你需要提供至少一对。  这意味着你不能拥有 “空” 项。 每个属性的大小最大可达 1kb,因此这意味着每个项目在功能上限制为 256kb,因为 1kb 的值限制和 256 对限制。

SimpleDB 是分布式的,你在设计应用程序时需要理解和记住 SimpleDB 的特性。  作为分布式数据库意味着整组计算机将响应你的请求,你的数据将在这些服务器中复制。 此分发对你的程序完全透明,但它确实引入了一致性问题的可能性 - 你的数据无法保证最初出现在所有服务器上。

不要惊慌:由于一些原因,它并没有听起来那么糟糕。  使用 SimpleDB,不保证一致性,但它通常非常好,并且快速到达所有节点。 设计这个也不是那么的难 - 通常你会尽量避免立即调阅你刚写的记录。 最后,SimpleDB 可以选择执行一致的读取,但它们速度较慢,可能会占用更多资源。 如果你的应用每次都需要一致的阅读,你可能需要重新考虑是否需要使用 SimpleDB 作为你的数据存储,但对于许多应用程序,这可以设计或甚至不担心。

从好的方面来说,分布式特性还为 SimpleDB 提供了一些与 Node.js 环境很好地融合的优点。  由于你没有单个服务器响应你的请求,因此你无需担心服务饱和,并且可以通过向 SimpleDB 发出许多并行请求来实现良好性能。 并行和异步请求是 Node.js 可以轻松处理的。

与许多 AWS 服务不同,没有用于管理 SimpleDB 的亚马逊控制台。 幸运的是,有一个很好的浏览器管理控制台,采用谷歌 Chrome 插件 SdbNavigator 的形式。 在 SdbNavigator 中,你可以添加或删除域,插入,更新和删除项,修改属性以及执行查询。

AWS 开发 SDK

现在我们已经了解了 SimpleDB 服务,让我们开始编写我们的 REST 服务器。 首先,我们需要安装 AWS SDK。 此 SDK 不仅处理 SimpleDB,还处理所有 AWS 服务,因此你可能已将其包含在 package.json 文件中。 要安装 SDK,请从命令行运行以下命令:

要使用 SimpleDB,你还需要获取 AWS 凭据,其中包括访问密钥和密钥。 SimpleDB 是一种即用即付服务,但 AWS 目前包含对 SimpleDB 的免费许可。

警告:与任何即用即付服务一样,请注意可以编写可以支付大笔账单的代码,因此你需要密切关注你的使用情况并将你的凭据保密而且安全。

一旦安装了 AWS SDK 并获得了凭据,就需要在代码中设置 SimpleDB。 在此示例中,我们将使用存储在主目录中的 JSON 文件中的 AWS 凭据。  首先,你需要包含 SDK 模块,创建 AWS 对象,最后设置 SimpleDB 接口。

请注意的是,我们正在使用特定的端点和区域。 每个数据中心都是完全独立的,因此如果你在北弗吉尼亚州创建名为 “ mysuperawesomedata ” 的域,则不会将其复制到圣保罗数据中心,也不会出现在其中。

你使用新的 aws.SimpleDB 创建的 SimpleDB 对象是你与 SimpleDB 交互的所有方法都将基于的位置。 在 AWS SDK 的 SimpleDB 的只有几个方法:

批量操作

  • batchDeleteAttributes
  • batchDeleteAttributes

域名管理和信息

  • 则 createdomain
  • deleteDomain
  • domainMetadata
  • listDomains

项目 / 属性操作

  • deleteAttributes
  • getAttributes
  • putAttributes

查询

  • 选择

在本教程中,我们将只处理项目 / 属性操作和查询; 虽然其他类别很有用,但许多应用程序对它们没有任何用处。

测试数据

使用 SdbNavigator,在工具中输入访问和安全密钥,选择 “US-East”,然后单击 “连接”。

Connection UI to SdbNavigator

成功连接后,让我们创建一个用于测试的域。 单击 “ 添加域”。

Adding a domain via the SdbNavigator

然后输入域名'sdb-rest-tut'并单击 OK。

Entering the name of the new domain

现在你已经创建了一个域,让我们输入一些测试数据。 单击 “ 添加属性” 并添加名为 “colors” 的属性。 作为惯例,我通常以复数形式命名属性以反映 SimpleDB 的多值性质。

Adding a property name to the record

最后,我们将单击 Add record 以创建我们的第一个 SimpleDB 项。  在 ItemName()列中,输入你的唯一项名称。  SdbNavigator 的一个特点是,默认情况下,它只接受每个项目的单个值,但这掩盖了属性可以包含多个值的事实。 要输入多个值,请单击属性列右边缘的 S.

Entering a unique item name

在新框中,选择 Array 以输入多个值。 在 “ 值” 列中,输入 “red”,然后单击 “ 添加值” 并输入 “blue”。

Entering the data type of the item

最后,单击 “ 更新” 以将更改保存到此行。

Updating the data type of the item

现在我们输入了一些测试数据,让我们从 Node 发出第一个 SimpleDB 请求。 我们将只获取 Domain 中的所有内容,此时,它只是一行。

响应将记录到控制台。 这是回复,注释如下:

REST 服务器

由于我们将构建一个在 SimpleDB 中存储数据的 REST 服务器,因此了解 REST 服务器的功能很重要。 REST 代表 RE 表示 S tate T ransfer。 REST 服务器实际上只是一个使用 HTTP 标准机制作为数据接口的服务器。  通常,REST 用于服务器到服务器的通信,但你可以通过 JavaScript 库(如 jQuery 或 Angular)将 REST 服务器与客户端一起使用。  但是,通常终端用户不会直接与 REST 服务器交互。

有趣的是,AWS SDK 实际上使用 REST 协议与 SimpleDB 交互,因此向另一个 REST 服务器创建 REST 服务器似乎很奇怪。 你不希望直接使用 SimpleDB REST API,因为你需要对请求进行身份验证,这可能会危及你的 AWS 账户的安全性。   此外,通过编写服务器,你将能够为数据存储添加一层抽象和验证,这将使整个应用程序的其余部分更容易处理。

在本教程中,我们将构建基本的 CRUD + L 函数,即 C reate,R ead,U pdate,D elete 和 L ist。  如果你考虑一下,你可以将大多数应用程序分解为 CRUD + L.  使用 REST,你将使用有限数量的路径和多个 HTTP 方法或动词来创建直观的 API。 大多数开发人员都熟悉一些 HTTP 动词,即 GET 和 POST,因为它们最常用于 Web 应用程序,但还有其他几个。

手术 HTTP 动词
创建 POST
得到
更新
删除 删除
名单 得到

请注意,Read 和 List 都使用相同的动词; 我们将使用稍微不同的路径来区分两者。 我们使用 POST 来表示 Create,因为创建不被视为幂等。 幂等意味着多个相同的调用将对用户和数据产生相同的结果,因此更新(也称为 PUT)将被视为幂等的。

作为我们的例子,我们将构建一个个人库存服务器 - 一个数据库来保存你拥有的任何内容。  以下是路径的外观:

手术 HTTP 动词 路径
创建 POST / 存货
得到 / 存货 / 1234
更新 / 存货 / 1234
删除 删除 / 存货 / 1234
名单 得到 / 库存

1234 是人员标识符(ID)的占位符 - “创建”和 “列表” 没有 ID 的注释。 在 create 的情况下,将生成 ID,并且使用 list,我们将获得所有名称,因此我们不需要特定的 ID。

构建服务器

首先,让我们安装一个 Node.js HTTP 服务器框架 Express:

Express 在设置服务器时管理大部分细节,但它不包括处理 HTTP 请求体的任何工具,因此我们需要安装另一个模块,body-parser,以使我们能够读取请求体。

Body-parser 有一些不同的选项可用于解析 HTTP 请求的主体。 我们只需要在 create 和 update 方法上使用 bodyParser 方法,因此我们可以将它包含在那些特定的路由中。 我们只需要在 create 和 update 方法上使用 bodyParser 方法,因此我们可以将它包含在那些特定的路由中。

创建

由于每个 SimpleDB itemName 都必须是唯一的,因此我们可以为每个新创建的项自动生成一个新的 itemName。 我们将使用 cuid 模块,这是一种生成唯一标识符的轻量级方法。

SimpleDB 期望属性采用属性名称 / 值对格式:

你的服务器当然可以直接接受并将这种格式的值直接传递给 SimpleDB,但是对于数据的常常结构化而言,这是违反直觉的,并且这是一个难以理解的概念。  我们将使用更直观的数据结构,一个对象 / 值数组:

这是一个基于 Express 的基本服务器,具有 create 操作:

让我们启动你的服务器并尝试一下。 与 REST 服务器交互的一种好方法是使用 cURL 工具。 此工具允许你从命令行使用任何动词发出 HTTP 请求。  要尝试使用我们的 REST 服务器创建项目,我们需要激活一些额外的选项:

选项 目的
-H 在 HTTP 标题中添加一行
-X 定义将使用哪个动词
-d 要在 HTTP 请求正文中发送的数据

运行该命令后,你将看到包含新创建的 itemName 或 ID 的 JSON 响应。 如果切换到 SdbNavigator,则在查询所有项目时应该会看到新数据。

读取调阅

现在让我们构建一个从 SimpleDB 读取项目的基本函数。  为此,我们不需要执行查询,因为我们将从请求的路径获取 itemName 或 ID。 我们可以使用该 itemName 或 ID 执行 getAttributes 请求。

如果我们停在这里,我们将拥有一个功能性但不是非常友好的数据形式。  让我们将 Name / Value 数组转换为我们用于接受数据的相同形式(属性:值数组)。 为此,我们需要遍历每个名​​称 / 值对,并将其添加到每个唯一名称的新数组中。

最后,让我们添加 itemName 并返回结果。

为了测试这个,我们需要再次使用 curl。 尝试使用本教程前面创建项目示例中返回的 itemName 或 ID 替换 [cuid]。

请注意,我们使用的是 -D- 选项。 这将转储 HTTP 头,以便我们可以看到响应代码。

REST 的另一个方面是使用你的响应代码。 在当前示例中,如果你提供不存在的 ID 以进行 curl,则上述服务器将崩溃,因为你尝试 forEach 一个不存在的数组。  我们需要考虑到这一点并返回一个有意义的 HTTP 响应代码,表明找不到该项。

为了防止错误,我们应该测试变量 awsResp.Attributes 的存在。 如果它不存在,让我们将状态代码设置为 404 并结束 http 请求。 如果存在,那么我们可以使用属性来提供响应。

尝试使用新代码和不存在的 ID,你将看到服务器返回 404。

现在我们知道如何使用 status 来更改值,我们还应该更新我们对 POST / create 的响应方式。  虽然 200 响应在技术上是正确的,因为它意味着'OK',但更具洞察力的响应代码将是 201,表示'已创建'。 要进行此更改,我们会在发送之前将其添加到状态方法中。

更新

更新通常是任何系统最困难的操作,此 REST 服务器也不例外。

SimpleDB 的本质使得这个操作也更具挑战性。 对于 REST 服务器,更新是替换整个存储数据的地方; 另一方面,SimpleDB 表示 itemName 下的各个属性 / 值对。

为了允许更新来表示单个数据而不是名称 / 值对的集合,我们需要为代码的目的定义模式(即使 SimpleDB 不需要)。  如果现在还不清楚,请不要担心,请继续阅读,我会说明要求。

在我们的例子中,我们有四个我们关注的领域:宠物,汽车,家具和手机: 在我们的例子中,我们有四个我们关注的领域:宠物,汽车,家具和手机:

使用 SimpleDB,你不能存储空属性 / 值对,SimpleDB 也没有任何单个项的概念,因此我们假设如果 SimpleDB 没有返回值,则它不存在。 同样,如果我们尝试使用空属性 / 值对更新 SimpleDB 项,它将忽略该数据。 以这个数据为例:

从逻辑上讲,我们知道作为一个空阵列的汽车应该没有价值,宠物应该有两个值,但手机和家具呢? 你对那些人做了什么?  以下是我们如何翻译此更新请求以使用 SimpleDB:

  • 将具有值的属性 pet 放入 cat。
  • 将带有值的属性 pet 放到 dog 上。
  • 删除汽车的属性。
  • 删除手机的属性。
  • 删除家具的属性。

如果没有至少定义属性的某种形式的架构,我们就不会知道需要删除手机和家具。 幸运的是,我们可以将此更新操作合并为两个 SimpleDB 请求而不是五个:一个用于放置属性,另一个用于删除属性。 现在是从 post / create 函数中提取代码的好时机,该函数将 values 对象的属性 / 数组转换为属性 / 值对数组。

我们还将对 create 函数进行重要更改。 我们将为所有项添加新的属性 / 值。  此属性不会添加到架构中,并且实际上是只读的。

我们将添加一个名为 created 的属性并将值设置为 1。 使用 SimpleDB,在添加属性和值之前检查项是否存在的能力有限。 在每个 putAttributes 请求中,你可以检查单个属性的值和是否存在 - 在我们的示例中,我们将使用 created 并检查值为 1。  虽然这可能看起来像一个奇怪的解决方法,但它提供了一个非常重要的安全措施,以防止更新操作能够创建具有任意 ID 的新项目。

由于我们将执行几个异步 HTTP 请求,让我们安装异步模块以简化这些回调的处理。

请记住,由于 SimpleDB 是分布式的,因此没有理由按顺序放置我们的属性然后删除。 我们将使用函数 async.parallel 来运行这两个操作,并在两个操作完成时获得回调 来自 AWS 表单 putAttributes 和 deleteAttributes 的响应不提供重要信息,因此如果没有错误,我们将发送状态代码为 200 的空响应。

为了实现这一点,让我们更新以前创建的条目。  这一次,我们将使库存只包括一个 “狗”,删除所有其他项目。 再次,使用 cURL,运行命令,用 [cuid] 替换你的一个项目 ID。

删除

SimpleDB 没有项目删除的概念,但它可以删除属性,如上所述。 要删除项目,我们需要删除所有属性,“项目” 将不再存在。

由于我们已经在模式中定义了属性列表,因此我们将使用 deleteAttributes 调用来删除所有这些属性以及创建的属性。 根据我们的计划,此操作将与 Update 处于相同的路径,但使用动词删除。

名单

列出我们的 REST 动词。  为了实现列表操作,我们将使用 select 命令和类似 SQL 的查询语言。  我们的列表函数将是准系统,但将作为稍后进行更复杂检索的良好基础。 我们将做一个非常简单的查询:

当我们遇到 get / read 操作时,SimpleDB 的响应不是很有用,因为它专注于属性 / 值对。  为了避免重复,我们将把 get / read 操作的部分重构为一个单独的函数并在此处使用它。 虽然我们在这里,但我们也会过滤掉创建的属性(因为它将显示在 get 操作中)。

通过 select 操作,SimpleDB 返回 Items 数组中的值。 每个项目由一个对象表示,该对象包含 itemName(简称为 Name)和属性 / 值对。

为简化此响应,让我们返回单个对象中的所有内容。 首先,我们将属性 / 值对转换为属性 / 值数组,就像我们在 read / get 操作中所做的那样,然后我们可以添加 itemName 作为属性 ID。

要查看我们的结果,我们可以使用 curl:

验证

验证完全是它自己的主题,但是使用我们已经编写的代码,我们可以开始使用简单的验证系统。

目前,我们要确保的是,除了架构中的内容之外,用户无法提交任何内容。 回顾为 update / put 编写的代码,forEach over the schema 将防止添加任何未经授权的属性,因此我们实际上只需要应用类似于我们的 create / post 操作的东西。 在这种情况下,我们将过滤属性 / 值对,从而消除任何非模式属性。

在你的生产代码中,你可能需要一个更强大的验证系统。 我建议集成一个 JSON 模式验证器,如 ajv,并在创建和更新操作上构建位于 bodyParser 和路由功能之间的中间件。

下一步

使用本文中概述的代码,你可以获得存储,读取和修改数据所需的所有操作,但这只是你旅程的开始。 在大多数情况下,你需要开始考虑以下主题:

  • 认证
  • 分页
  • 复杂的列表 / 查询操作
  • 其他输出格式(xml,csv 等)

这个由 SimpleDB 支持的 REST 服务器的基础允许你添加中间件和其他逻辑,以便为你的应用程序构建主干。

最终的服务器代码可以在 GitHub 上的 simpledb-rest-api 上找到。

关注我们的公众号
Advertisement
Advertisement
Advertisement
Advertisement
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.