Node.js 是一个快速构建高性能的、可扩展的后端系统的优秀工具,它是使用大多数前端开发人员都已熟悉的核心语言 JavaScript 开发的。Node.js 正积极地进军企业领域,许多重要企业正在 Node.js 基础架构之上构建他们完整的 Web 系统和 API 服务。
StrongLoop 的 LoopBack 框架使您能够轻松地连接数据并将数据公开为 REST 服务。它能够在图形(或命令行)界面中以可视方式创建数据模型,可以使用这些模型自动生成 REST API - 从而为您的 REST 服务层生成 CRUD 操作,无需编写任何代码。
为什么这很重要?它使 API 开发变得更容易,并显著减少了从概念到实现所需的时间。观看下面的视频,了解它能为您做什么。
IBM Cloudant 是 IBM 的 NoSQL 数据库即服务,它提供了大规模可伸缩性、强大的搜索特性、高可用性,可以帮助您更快交付解决方案,降低维护成本。
尽管对 StrongLoop 的收购仍只是“热门新闻”,但您现在可以结合使用 LoopBack 和 Cloudant 来加速高度安全的 REST 应用层的开发。将这一点与IBM MobileFirst 平台相结合,您将拥有一个更全面、更安全的移动应用程序解决方案。事实上,StrongLoop/LoopBack 和 Cloudant 现在都是 MobileFirst Platform 的一部分,但您仍能够以独立服务的形式在 IBM Bluemix 上获取它们。
在本文中,我们将介绍如何借助 LoopBack 框架和 Strongloop Arc 工具,利用 IBM Cloudant 作为后端数据存储。
在 LoopBack 框架中,是通过所谓的“数据连接器”来获取和持久化数据。StrongLoop 维护着多个数据连接器,拥有针对开发人员社区所提供的更多后端数据存储的连接器。
Cloudant 是一个 DBaaS 服务,是一个衍生的 Apache CouchDB,所以将 LoopBack 连接器连接到 Cloudant 很简单,只需在您应用程序中使用现有的社区驱动的 CouchDB LoopBack Connector。我们来了解一下如何为您自己的应用程序执行此设置。
设置 Cloudant 很简单。MobileFirst Platform Foundation Server 提供了 Cloudant 的一个有限的内部部署许可,或者您可以将 Cloudant 服务添加到 Bluemix 上的任何应用程序:您可以通过 REST 接口单独使用 Cloudant,或者使用 Node.js/Cloudant Web Starter 模板 来获得 Node.js + Cloudant 多层解决方案。
我们来了解一下如何使用 Bluemix Starter 模板设置 Cloudant。在浏览器中导航到 Node.js/Cloudant Web Starter 模板,然后输入一个应用程序名称和应用程序主机(此信息将用在应用程序的 URL 前缀中),然后点击“Create”按钮。
图 1.Node.js Cloudant Starter模板
点击“Create”按钮会创建一个 Cloudant NoSQL 数据库实例以及 Bluemix 上的一个 Node.js 服务实例,我们以后可以将应用程序部署到该实例上。在您的应用程序正常运行后,会显示一条消息。
您的服务在 Bluemix 上正常运行后,您将能够直接使用 Cloud Foundry 命令行 工具 部署 Node.js 应用程序,使用 IBM Devops Services 或 Bluemix Live Sync & GIT 进行部署,或者使用 Eclipse Tools for Bluemix 。
接下来,我们需要创建我们的 Cloudant 数据库实例,以便将它用于我们的 Node.js/LoopBack 应用程序。在您的 Bluemix 仪表板中,单击“Cloudant NoSQL DB”服务链接来查看细节,然后单击右上角的“Launch”按钮来查看 Cloudant 仪表板。
进入 Cloudant 仪表板中后,您需要创建一个用于该应用程序的数据库实例。选择右上角的“Add New Database”链接。系统会提示您输入一个数据库名称,然后点击“Create”。
图 2.创建一个新 Cloudant 数据库
创建数据库后,就可以设置您的本地开发环境并开始构建应用程序了。
回页首
如果还没有安装以下工具,需要下载并安装它们:
回页首
在安装了您环境所需的软件后,现在可以开始创建您的 API 应用程序了。
我们需要做的第一件事是从命令行终端使用 LoopBack 应用程序生成器 设置应用程序。您需要指定应用程序名称和将创建该应用程序的子目录。
$ slc loopback
_-----_ | | .--------------------------. |--(o)--| | Let's create a LoopBack | `---------?′ | application! | ( _?′U`_ ) '--------------------------' /___A___/ | ~ | __'.___.'__ ?′ ` |?° ?′ Y ` ?What's the name of your application? business-directory ?Enter name of the directory to contain the project: business-directory
创建应用程序后,下一步是创建 连接器 ,使 LoopBack 框架能够将数据存储在 Cloudant 数据库中。因为 Cloudant 是 CouchDB 的衍生产品,所以我们将使用 Community Connectors 下的 Apache CouchDB LoopBack 连接器 。
在终端窗口中,使用 cd 命令进入刚生成的项目目录中,然后使用 npm 安装 loopback-couch-connector。
$ cd business-directory $ npm install loopback-connector-couch
安装连接器后,需要将 Cloudant 配置为可用于 LoopBack 框架的数据源。可以通过编程方式完成此设置,以便从环境配置中提取凭据。但是,为了简便起见,我将展示该配置以及 datasource.json 配置文件中的凭据。
使用 JavaScript/text 编辑器打开 server/datasources.json 文件,添加“cloudant”,如下所示。您需要指定您的 Cloudant 主机 URL,以及访问数据库所需的身份验证凭据。
{ "db":{ "name":"db", "connector":"memory" }, "cloudant":{ "host":"your-database-host-bluemix.cloudant.com", "port":443, "name":"cloudant", "connector":"couch", "db":"business-directory", "protocol":"https", "auth":{ "admin":{ "username":"your Cloudant admin user name", "password":"your admin password" }, "reader":{ "username":"your reader user name", "password":"your reader password" }, "writer":{ "username":"your writer username", "password":"your writer password" } } } }
您可以查看 GitHub 上的 LoopBack CouchDB Connector 项目 ,了解更多的配置和使用信息。
LoopBack 框架拥有两种构建数据模型的方式:命令行界面和 Arc Composer,后者是一种构建数据模型和 API 的图形界面。
首先,我们将使用命令行工具设置一个数据模型。使用 slc loopback:model 生成器 ,执行以下步骤,在数据模型中创建一个“Company”条目。
$ slc loopback:model ?Enter the model name:Company ?Select the data-source to attach Company to: cloudant (couch) ?Select model's base class:PersistedModel ?Expose Company via the REST API?Yes ?Custom plural form (used to build REST URL):Companies Let's add some Company properties now. Enter an empty property name when done. ?Property name: name ?Property type: string ?Required?Yes Let's add another Company property. Enter an empty property name when done. ?Property name: address ?Property type: string ?Required?Yes Let's add another Company property. Enter an empty property name when done. ?Property name: city ?Property type: string ?Required?Yes Let's add another Company property. Enter an empty property name when done. ?Property name: state ?Property type: string ?Required?Yes Let's add another Company property. Enter an empty property name when done. ?Property name: zip ?Property type: string ?Required?Yes
这将生成数据模型的 Company.json 配置和 Company.js 类,您能够扩展该类来添加自己的自定义逻辑。
Company.json:
{ "name":"Company", "plural":"Companies", "base":"PersistedModel", "idInjection": true, "options":{ "validateUpsert": true }, "properties":{ "name":{ "type":"string", "required": true }, "address":{ "type":"string", "required": true }, "city":{ "type":"string", "required": true }, "state":{ "type":"string", "required": true }, "zip":{ "type":"string", "required": true } }, "validations":[], "relations":{}, "acls":[], "methods":{} }
Company.js:
module.exports = function(Company) { //add your custom extension logic here };
接下来,使用 Arc Composer 界面在我们的数据模型中创建更多的类。从终端窗口运行下面这个命令:
$ slc arc
这将启动 StrongLoop Arc 图形界面来与 LoopBack API/应用程序交互,然后为本地服务打开一个浏览器窗口。浏览器窗口打开后,单击“Composer”图标进入 GUI 来管理您的数据模型。
图3
在 Composer 界面中,单击“Add New Model”链接开始构建下一个类。输入一个模型名称“Employee”和复数形式“Employees”,然后确保选中了“PersistedModel”作为基础模型,并选择“cloudant”作为数据源。
接下来,将以下 3 个属性添加到 Employee 模型中:
保存模型后,将会生成两个 JavaScript 文件:Employee.json 和 Employee.js。就像从命令行创建的 Company 模型一样(上文),这两个文件表示数据模型定义,以及一个可用来扩展模型来添加自己的自定义逻辑或行为的类。
Employee.json:
{ "name":"Employee", "base":"PersistedModel", "strict": false, "idInjection": false, "options":{ "validateUpsert": true }, "properties":{ "name":{ "type":"string", "required": true }, "title":{ "type":"string", "required": true }, "companyId":{ "type":"number", "required": true } }, "validations":[], "relations":{}, "acls":[], "methods":[] }
Employee.js:
module.exports = function(Employee) { //add your custom extension logic here };
现在我们已经创建了两个数据对象定义,接下来要在两个对象之间定义一种关系。在命令行上,使用“slc loopback:relation”生成器命令创建一种关系。
slc loopback:relation ?Select the model to create the relationship from:Company ?Relation type: has many ?Choose a model to create a relationship with:Employee ?Enter the property name for the relation: employees ?Optionally enter a custom foreign key: company ?Require a through model?No
现在我们已经定义了数据并定义了一种关系,接下来开始与从数据模型自动生成的 REST API 交互。
如果您想知道这些关系的工作原理,因为我们没有在模型中定义 id 值,所以这些 id 属性会自动生成。
回页首
LoopBack 框架自动为您数据模型中的所有对象生成 REST 端点。它还会自动生成 Swagger API 文档。这将为您项目生成的所有服务提供一个简单易用的界面。我们现在来看一下生成的文档……
在浏览器中返回到 Arc Composer 界面,单击“App Controller”按钮(右上角的三角形“play”按钮)并启动您的应用程序。运行您的应用程序后,在一个新浏览器窗口中打开 API 文档: http://localhost:3000/explorer/(使用默认的本地配置)。
图 4.自动生成的 Swagger 交互式文档
从生成的文档中,您可以看到所有已公开的与数据模型交互的 REST 方法。在这里,您还可以直接与这些服务交互和测试它们。单击“Get /Companies”条目展开服务细节。使用“Try it out!”按钮调用此服务。但是,您需要先使用“POST /Companies”方法插入一些数据,然后才能查询它。
您可以转到“POST /Companies”服务来插入一条包含以下数据的新记录:
{ "name":"IBM", "address":"1 New Orchard Road", "city":"Armonk", "state":"NY", "zip":"10504" }
这个服务可直接使用 REST 请求进行调用。
现在,我们查询该数据,确保它已插入到数据库中。从命令行终端,输入下面的命令来查看 /Companies 查询的输出:
$ curl http://localhost:3000/api/Companies
您会看到与下面的结果类似的查询结果,除了 id 和 _rev 值会有所不同。
[{"name":"IBM","address":"1 New Orchard Road","city":"Armonk","state":"NY", "zip":"10504","id":"a5bee38b6ce94b163de664fd5b7bc9f0","_rev":"1-646f0565f4abc14a3bc6876e05f23ef0"}]
接下来,使用“POST /Companies/{id}/employees”方法添加一些员工。您可以使用资源管理器来提交数据,或者直接向 REST 服务提交数据。在本例中,我直接使用 curl 向 API 插入数据,但我将“{id}”替换成了数据库实际生成的公司 ID。
点击查看代码清单
关闭 [x]
$ curl -H "Content-Type: application/json" -X POST -d '[{ "name":"Andrew Trice","title":"Developer Advocate"}, { "name":"Ray Camden","title":"Developer Advocate"},{ "name":"Marek Sadowski","title":"Developer Advocate"}, { "name":"Kevin Hoyt","title":"Developer Advocate"},{ "name":"Ken Parmelee","title":"Program Director"}]' http://localhost:3000/api/Companies/a5bee38b6ce94b163de664fd5b7bc9f0/employees
这些服务可用作 RESTful 端点,也可由任何应用程序使用,无论是移动应用程序、桌面应用程序,还是基于 Web 的应用程序。
回页首
您可以调用 GET /Companies 来查询所有公司,调用 GET /Employees 来查询所有员工,或者调用 /Companies/{id}/employees 来查询某个特定公司的所有员工,但 99.99% 的时间您都不希望这么做 - 它太一般化了,会返回太多数据,而且在逻辑或区分化的结构中没有必要。
所以让我们使用 LoopBack 框架的过滤器来缩小搜索结果范围。LoopBack 框架支持使用 [where] 过滤器来缩小返回的记录范围,使用 [limit] 过滤器限制返回的结果数量,使用 [fields] 过滤器限制返回的一个对象的属性,使用 [order] 确定结果顺序,使用 [include] 过滤器包含相关模型,并使用 [skip] 过滤器跳过结果(用于数据分页)。所有这些都可作为 REST 请求的参数来指定。
我们看看一些例子。
首先,返回所有头衔为“Developer Advocate”的员工:
$ curl -g 'http://localhost:3000/api/employees?filter[where][title]=Developer%20Advocate' [{"name":"Andrew Trice","title":"Developer Advocate","company":"a5bee38b6ce94b163de664fd5b7bc9f0", "id":"31c71d93e2ff40c1f789e4d46cd7f2a0","_rev":"1-582ef49e3963af0f0ab6f4d97f1038c6"}, {"name":"Marek Sadowski","title":"Developer Advocate","company":"a5bee38b6ce94b163de664fd5b7bc9f0", "id":"63d7631797106ddfafcae31d2bc70ced","_rev":"1-0967f7cb1b26f9ee619e8c76e3e08e74"}, {"name":"Kevin Hoyt","title":"Developer Advocate","company":"a5bee38b6ce94b163de664fd5b7bc9f0", "id":"732ad7d6c368579caea6aa7caea89e4b","_rev":"1-8e220575e11c3973a2b6a3bca02658d5"}, {"name":"Ray Camden","title":"Developer Advocate","company":"a5bee38b6ce94b163de664fd5b7bc9f0", "id":"8436dee94003f63667657b2a78b2170c","_rev":"1-c0d797c65fec2e2e2cc3497a589ef2f2"}]
但是,这些数据对我当前的需求而言太多了。让我们仅返回同一个结果集中的 name 字段:
点击查看代码清单
关闭 [x]
$curl -g 'http://localhost:3000/api/employees?filter[fields][name]=true&filter[where][title]=Developer%20Advocate' [{"name":"Andrew Trice"}, {"name":"Marek Sadowski"}, {"name":"Kevin Hoyt"}, {"name":"Ray Camden"}]
现在,想想您可能希望进一步限制返回的记录数量:
$ curl -g 'http://localhost:3000/api/employees?filter[fields][name]=true &filter[where][title]=Developer%20Advocate&filter[limit]=3' [{"name":"Andrew Trice"}, {"name":"Marek Sadowski"}, {"name":"Kevin Hoyt"}]
如果您希望以不同顺序排列这些结果,该怎么办?我们可添加过滤器来提供按名称的升序重新排列后的前 3 个结果:
curl -g 'http://localhost:3000/api/employees?filter[fields][name]=true &filter[where][title]=Developer%20Advocate&filter[limit]=3&filter[order]=name%20DESC' [{"name":"Ray Camden"}, {"name":"Marek Sadowski"}, {"name":"Kevin Hoyt"}]
回页首
可以向 API/id 发送 PUT 请求来轻松地更新数据。所以,如果您希望更新一位员工,可以向 /employees/{id} 发送一个仅包含您想要更新的值的 PUT 请求。
我们假设我想更新我的员工条目中的名称……在本例中,我仅将包含“name”属性的新值的 PUT 请求发送给 /Employees/{id}:
点击查看代码清单
关闭 [x]
$ curl -H "Content-Type: application/json" -X PUT -g -d '{"name":"Andy Trice"}' 'http://localhost:3000/api/Employees/31c71d93e2ff40c1f789e4d46cd7f2a0'
{"name":"Andy Trice","title":"Developer Advocate","company":"a5bee38b6ce94b163de664fd5b7bc9f0", "id":"31c71d93e2ff40c1f789e4d46cd7f2a0","_rev":"6-88e83684b52cde686c08a84555e36d34"}
回页首
目前为止,我们已在本地开发机器上测试了所有代码。如果您管理着自己的 Node.js 服务器,那么可以简单地将您的代码部署到生产环境。
我们还可以通过多种选择将此应用程序迁移到云中。首先让我们来看看 Node.js 即时运行时,它包含在本文之前使用的 Cloudant 应用程序模板中。我们还可以选择将此 API 部署到在 Bluemix 上一个容器中运行的 StrongLoop Process Manager。
因为在本文开头我们在 Bluemix 上创建了一个应用程序,所以我们继续将它部署到该 Bluemix 即时运行时。
我们将使用 Cloud Foundry 命令行 API 将 Node.js 应用程序部署到 Bluemix,但需要先对 package.json 文件进行一些细微更改。在代码编辑器中打开 package.json 后,添加“dependencies”和“bundle dependencies”,如下面的示例 package.json 所示:
{ "name":"business-directory", "version":"1.0.0", "main":"server/server.js", "scripts":{ "pretest":"jshint ." }, "dependencies":{ "compression":"^1.0.3", "cors":"^2.5.2", "errorhandler":"^1.1.1", "loopback":"^2.14.0", "loopback-boot":"^2.6.5", "loopback-datasource-juggler":"^2.19.0", "serve-favicon":"^2.0.1", "loopback-connector-couch":"*", "cfenv":"1.0.x" }, "optionalDependencies":{ "loopback-explorer":"^1.1.0" }, "devDependencies":{ "jshint":"^2.5.6" }, "repository":{ "type":"", "url":"" }, "description":"business-directory", "bundleDependencies":[ "compression", "cors", "errorhandler", "loopback", "loopback-boot", "loopback-connector-couch", "loopback-datasource-juggler", "loopback-explorer", "serve-favicon" ] }
接下来,我们需要在终端窗口中使用 CF CLI 登录:
$ cf login
按照提示登录到 Bluemix。
接下来,使用“cf push {app name}”将应用程序部署到 Bluemix。请注意“-c”选项,它会告诉节点从哪个命令开始。需要指定此选项是因为,它与默认的 Bluemix Node.js 应用程序配置稍微不同:
$ cf push LoopBack-Directory -c "node server/server.js"
将应用程序部署到 Bluemix 后,您会看到一个类似下文的摘要:
requested state: started instances:1/1 usage:512M x 1 instances urls: loopback-directory.mybluemix.net last uploaded:Wed Aug 26 03:48:50 UTC 2015 stack: lucid64 buildpack:SDK for Node.js(TM) (ibm-node.js-0.12.7)
state since cpu memory disk details #0 running 2015-08-25 11:50:29 PM 0.1% 120.5M of 512M 119.8M of 1G
在将应用程序部署到 Bluemix 后,就可以将 API 服务用在您的应用程序中。您可以自行查看 API 资源管理器和 API 端点:loopback-directory.mybluemix.net/explorer
备注:我限制了写入访问,所以您只能读取数据。
回页首
将 LoopBack 应用程序部署到生产中的第二个选择是,使用 Bluemix 上的 StrongLoop Process Manager 容器。首先,导航到 Bluemix Catalog 并选择“ibm-node-strong-pm”镜像。
在获得提示时,输入一个容器名称,然后确保请求并绑定了一个公共 IP,然后选择应用程序要使用的端口。您需要使用端口 8701(由 Process Manager 使用),您的应用程序运行时默认情况下使用的端口为 3001,但您可以在 server/config.json 文件中配置您应用程序的端口。
图 5.StrongLoop Process Manager 容器创建
确保请求的容器端口与 config.json 中应用程序使用的端口匹配,否则您无法访问部署后的应用程序。这可能是像 HTTP 端口 80 这样的标准端口,或者是像默认的 3001 这样的一次性端口,后者一般用于开发。
在创建容器后,您就能够使用本地机器上的 StrongLoop Process Manager 工具将应用程序部署到 Bluemix 上的远程实例。
如果浏览器中仍打开着 StrongLoop Arc/Composer 工具,现在转到该工具。如果没有运行它,可以转到命令行终端,并从您应用程序的目录运行“slc arc”。
$ cd business-directory $ slc arc
Arc 工具会自动在浏览器中启动。接下来,我们需要为我们的远程容器设置一个 PM 主机。转到“Process Manager”视图,选择“Add PM Host”选项来按 IP 地址和端口添加新创建的容器。
图 6.添加新 PM 主机
您可以在 Bluemix 仪表板中查看您的容器镜像来获得该 IP 地址和验证绑定的端口。
图 7.新建的 Docker Container 信息
接下来,转到 Arc 工具中的 Build & Deploy 模块。从这里选择或构建一个您想要部署的归档文件,然后选择您想要将应用程序部署到哪个主机。点击“Deploy”按钮后,就会部署该应用程序。
图 8.使用 StrongLoop Arc 进行构建和部署
部署您的应用程序后,即可在指定的 IP 和端口上使用它。如果无法直接点击您的应用程序,您可能需要跳回到 Process Manager 模块来确保它的实例在正常运行。
回页首
在将您应用程序的 API 应用到生产中后,您可以在任何可使用 REST 服务的应用程序中使用它,无论是移动应用程序、桌面应用程序,还是基于 Web 的应用程序。
我在上面已提到,您已经能够利用 IBM MobileFirst 将 LoopBack 框架生成的 API 与应用程序集成。请查阅“ 使用 LoopBack 构建的 IBM MobileFirst 和 Node.js API 入门 ”,更详细地了解如何配置 MobileFirst Platform Foundation 服务器和 LoopBack/Node.js 应用程序,让 MobileFirst 能够管理身份验证和对 Node.js API 的访问,并捕获将在 MobileFirst Analytics 控制台中报告的分析信息。
本文最先发表于 IBM dW Developer Center: Getting Started with Node.js LoopBack Framework and IBM Cloudant