个性化阅读
专注于IT技术分析

让LoopBack做到:Node API框架实战演练

本文概述

不用说Node.js在应用程序开发中的日益普及。自2011年以来, eBay一直在运行生产节点API服务。贝宝(PayPal)正在积极重建其在Node中的前端。在流量方面, 沃尔玛的移动站点已成为最大的Node应用程序。 2014年感恩节周末, 沃尔玛服务器处理了15亿个请求, 其中70%是通过移动设备交付的, 并由Node.js提供支持。在开发方面, Node软件包管理器(npm)继续快速增长, 最近已超过150, 000个托管模块。

尽管Ruby具有Rails, Python具有Django, 但尚未建立Node的主要应用程序开发框架。但是, 有一个强大的竞争者正在蒸蒸日上:LoopBack, 这是由加利福尼亚州圣马特奥市公司StrongLoop构建的开源API框架。 StrongLoop是最新Node版本的重要贡献者, 更不用说Express的长期维护者了, Express是目前最流行的Node框架之一。

通过将所有内容变成实践并构建示例应用程序, 让我们仔细了解LoopBack及其功能。

什么是LoopBack?它如何与Node一起使用?

LoopBack是用于创建API并将其与后端数据源连接的框架。它建立在Express之上, 可以采用数据模型定义, 并轻松生成可被任何客户端调用的功能齐全的端到端REST API。

LoopBack带有内置的客户端API Explorer。我们将使用它, 因为这样可以更轻松地查看我们的工作结果, 因此我们的示例可以专注于构建API本身。

当然, 你将需要在计算机上安装Node才能继续进行。在这里获取。 npm附带了它, 因此你可以轻松安装必要的软件包。让我们开始吧。

创建骨架

我们的应用程序将管理想要捐赠礼物的人或不再需要的东西, 捐赠给可能需要礼物的人。因此, 用户将是捐赠者和接收者。捐赠者可以创建新礼物并查看礼物列表。接收者可以看到所有用户的礼物清单, 也可以索取任何未领取的礼物。当然, 我们可以在同一实体(用户)上将捐赠者和​​接收者构建为单独的角色, 但让我们尝试将它们分开, 以便了解如何在LoopBack中建立关系。该突破性应用程序的名称为Givesomebody。

通过npm安装StrongLoop命令行工具:

$ npm install -g strongloop

然后运行LoopBack的应用程序生成器:

$ slc loopback

     _-----_
    |       |    .--------------------------.
    |--(o)--|    |  Let's create a LoopBack |
   `---------´   |       application!       |
    ( _´U`_ )    '--------------------------'
    /___A___\    
     |  ~  |     
   __'.___.'__   
 ´   `  |° ´ Y ` 

? What's the name of your application? Givesomebody

让我们添加一个模型。我们的第一个模型将被称为Gift。 LoopBack将询问数据源和基类。由于我们尚未设置数据源, 因此可以放入db(内存)。基类是一个自动生成的模型类, 在这种情况下, 我们想使用PersistedModel, 因为它已经包含了所有常用的CRUD方法。接下来, LoopBack询问是否应通过REST公开模型(是), 以及REST服务的名称。在此处按Enter键以使用默认值, 该默认值只是型号名称的复数形式(在我们的情况下为礼物)。

$ slc loopback:model

? Enter the model name: Gift
? Select the data-source to attach Gift to: (Use arrow keys)
❯ db (memory)
? Select model's base class: (Use arrow keys)
  Model
❯ PersistedModel
? Expose Gift via the REST API? (Y/n) Yes
? Custom plural form (used to build REST URL):

最后, 我们给出属性的名称, 它们的数据类型以及必需/不需要的标志。礼物将具有名称和描述属性:

Let's add some Gift properties now.

Enter an empty property name when done.
? Property name: name
   invoke   loopback:property
? Property type: (Use arrow keys)
❯ string
? Required? (y/N)Yes

输入一个空的属性名称, 以指示你已完成属性定义。

模型生成器将创建两个文件, 用于在应用程序的common / models中定义模型:gift.json和gift.js。 JSON文件指定有关实体的所有元数据:属性, 关系, 验证, 角色和方法名称。 JavaScript文件用于定义其他行为, 并指定在某些操作(例如, 创建, 更新或删除)之前或之后要调用的远程挂钩。

其他两个模型实体将是我们的捐助者和接收者模型。我们可以使用相同的过程来创建它们, 除了这次我们将User作为基类。它将为我们提供一些属性, 例如开箱即用的用户名, 密码, 电子邮件。例如, 我们可以仅添加名称和国家/地区, 以拥有完整的实体。对于接收方, 我们也想添加收货地址。

项目结构

让我们看一下生成的项目结构:

项目结构

三个主要目录为:-/ server-包含节点应用程序脚本和配置文件。 -/ client –包含.js, .html, .css和所有其他静态文件。 -/ common –服务器和客户端都共用该文件夹。模型文件在这里。

以下是每个目录内容的详细分类, 摘自LoopBack文档:

文件或目录 描述 如何使用代码访问
顶级应用程序目录
package.json 标准npm软件包规范。见package.json 不适用
/ server目录-节点应用程序文件
server.js 主应用程序文件。 不适用
config.json 应用程序设置。请参阅config.json。 app.get(‘设置名称’)
datasources.json 数据源配置文件。参见datasources.json。有关示例, 请参阅创建新数据源。 app.datasources [‘datasource-name’]
model-config.json 模型配置文件。请参阅model-config.json。有关更多信息, 请参阅将模型连接到数据源。 不适用
middleware.json 中间件定义文件。有关更多信息, 请参见定义中间件。 不适用
/ boot目录 添加脚本以执行初始化和设置。请参阅启动脚本。 脚本以字母顺序自动执行。
/ client目录-客户端应用程序文件
README.md LoopBack生成器以markdown格式创建空的README文件。 不适用
其他 添加你的HTML, CSS, 客户端JavaScript文件。  
/ common目录-共享的应用程序文件
/ models目录 自定义模型文件:按照惯例, 模型定义JSON文件名为model-name.json;例如customer.json。根据惯例, 自定义模型脚本名为model-name.js;例如, customer.js。有关更多信息, 请参阅模型定义JSON文件和定制模型。 节点:myModel = app.models.myModelName

建立关系

在我们的示例中, 我们需要建模一些重要的关系。捐赠者可以捐赠许多礼物, 这与捐赠者拥有许多礼物的关系有关。接收者也可以接收许多礼物, 因此我们也具有接收者具有许多礼物的关系。另一方面, Gift属于Donor, 如果Receiver选择接受, Gift也可以属于Receiver。让我们用LoopBack的语言。

$ slc loopback:relation

? Select the model to create the relationship from: Donor
? Relation type: has many
? Choose a model to create a relationship with: Gift
? Enter the property name for the relation: gifts
? Optionally enter a custom foreign key:
? Require a through model? No

注意, 没有直通模型。我们只是持有礼物的参考。

如果我们对Receiver重复上述过程, 并将两个属于关系的关系添加到Gift, 则将在后端完成模型设计。 LoopBack自动为模型更新JSON文件, 以准确表达我们通过这些简单对话框所做的工作:

// common/models/donor.json
  ...
  "relations": {
    "gifts": {
      "type": "hasMany", "model": "Gift", "foreignKey": ""
    }
  }, ...

添加数据源

现在, 让我们看看如何附加一个真实的数据源来存储我们所有的应用程序数据。就本示例而言, 我们将使用MongoDB, 但LoopBack具有与Oracle, MySQL, PostgreSQL, Redis和SQL Server连接的模块。

首先, 安装连接器:

$ npm install --save loopback-connector-mongodb

然后, 将数据源添加到你的项目中:

$ slc loopback:datasource

? Enter the data-source name: givesomebody
? Select the connector for givesomebody: MongoDB (supported by StrongLoop)

下一步是在server / datasources.json中配置数据源。将此配置用于本地MongoDB服务器:

  ...
  "givesomebody": {
    "name": "givesomebody", "connector": "mongodb", "host": "localhost", "port": 27017, "database": "givesomebody", "username": "", "password": ""
  }
  ...

最后, 打开server / model-config.json并将我们要保留在数据库中的所有实体的数据源更改为” givesomebody”。

{
  ...
  "User": {
    "dataSource": "givesomebody"
  }, "AccessToken": {
    "dataSource": "givesomebody", "public": false
  }, "ACL": {
    "dataSource": "givesomebody", "public": false
  }, "RoleMapping": {
    "dataSource": "givesomebody", "public": false
  }, "Role": {
    "dataSource": "givesomebody", "public": false
  }, "Gift": {
    "dataSource": "givesomebody", "public": true
  }, "Donor": {
    "dataSource": "givesomebody", "public": true
  }, "Receiver": {
    "dataSource": "givesomebody", "public": true
  }
}

测试你的REST API

现在该看看我们到目前为止的构建!我们将使用强大的内置工具API Explorer, 该工具可用作我们刚刚创建的服务的客户端。让我们尝试测试REST API调用。

在一个单独的窗口中, 使用以下命令启动MongoDB:

$ mongod

使用以下命令运行应用程序:

$ node .

在浏览器中, 转到http:// localhost:3000 / explorer /。你可以通过可用的操作列表查看你的实体。尝试通过POST / Donors呼叫添加一个供体。

测试你的API 2
测试你的API 3

API Explorer非常直观;选择任何公开的方法, 相应的模型架构将显示在右下角。在数据文本区域中, 可以编写自定义HTTP请求。填写请求后, 点击”试用”按钮, 服务器的响应将显示在下方。

测试你的API 1

用户认证

如上所述, 使用LoopBack预先构建的实体之一是User类。用户拥有登录和注销方法, 并且可以绑定到保留特定用户令牌的AccessToken实体。实际上, 一个完整的用户身份验证系统已准备就绪, 可以立即使用。如果我们尝试通过API Explorer调用/ Donors / login, 则将获得以下响应:

{
  "id": "9Kvp4zc0rTrH7IMMeRGwTNc6IqNxpVfv7D17DEcHHsgcAf9Z36A3CnPpZJ1iGrMS", "ttl": 1209600, "created": "2015-05-26T01:24:41.561Z", "userId": ""
}

该id实际上是AccessToken的值, 它是自动生成并持久保存在数据库中的。如你在此处看到的, 可以设置访问令牌并将其用于每个后续请求。

用户认证

远程方法

远程方法是在自定义REST端点上公开的模型的静态方法。远程方法可用于执行LoopBack的标准模型REST API未提供的操作。

除了开箱即用的CRUD方法之外, 我们还可以添加任意数量的自定义方法。所有这些都应该放入[model] .js文件。在我们的例子中, 让我们为”礼物”模型添加一种远程方法, 以检查礼物是否已被保留, 并列出所有未被保留的礼物。

首先, 让我们为模型添加一个名为reserved的附加属性。只需将其添加到gift.json的属性中:

    ...
    "reserved": {
      "type": "boolean"
    }
    ...

gift.js中的远程方法应如下所示:

module.exports = function(Gift) {

    // method which lists all free gifts
    Gift.listFree = function(cb) {
        Gift.find({
            fields: {
                reserved: false
            }
        }, cb);
    };

    // expose the above method through the REST
    Gift.remoteMethod('listFree', {
        returns: {
            arg: 'gifts', type: 'array'
        }, http: {
            path: '/list-free', verb: 'get'
        }
    });

    // method to return if the gift is free
    Gift.isFree = function(id, cb) {
        var response;
        Gift.find({
            fields: {
                id: id
            }
        }, function(err, gift) {
            if (err) return cb(err);

            if (gift.reserved)
                response = 'Sorry, the gift is reserved';
            else
                response = 'Great, this gift can be yours';

        });
        cb(null, response);
    };

    // expose the method through REST
    Gift.remoteMethod('isFree', {
        accepts: {
            arg: 'id', type: 'number'
        }, returns: {
            arg: 'response', type: 'string'
        }, http: {
            path: '/free', verb: 'post'
        }
    });
};

因此, 要确定是否有特定的礼物可用, 客户端现在可以向/ api / Gifts / free发送POST请求, 并传递有问题的礼物的ID。

遥控钩

有时需要在远程方法之前或之后执行某些方法。你可以定义两种远程挂钩:

  • beforeRemote()在远程方法之前运行。
  • afterRemote()在远程方法之后运行。

在这两种情况下, 你都提供两个参数:一个与要”挂钩”函数的远程方法匹配的字符串, 以及一个回调函数。远程挂钩的强大功能是字符串可以包含通配符, 因此可以通过任何匹配方法来触发它。

就我们而言, 我们设置一个钩子, 以便在创建新的Donor时将信息打印到控制台。为此, 我们在donor.js中添加一个” before create”挂钩:

module.exports = function(Donor) {
    Donor.beforeRemote('create', function(context, donor, next) {
        console.log('Saving new donor with name: ', context.req.body.name);
    
        next();
    });
};

该请求在给定的上下文中被调用, 并且在挂钩运行之后调用中间件中的next()回调(在下面讨论)。

访问控制

LoopBack应用程序通过模型访问数据, 因此控制对数据的访问意味着定义对模型的限制。也就是说, 指定谁或什么可以读取和写入数据或执行模型上的方法。回送访问控制由访问控制列表或ACL确定。

让我们允许未登录的捐赠者和接收者查看礼物, 但仅允许登录的捐赠者创建和删除礼物。

$ slc loopback:acl

首先, 让我们拒绝所有人访问所有端点。

? Select the model to apply the ACL entry to: Gift
? Select the ACL scope: All methods and properties
? Select the access type: All (match all types)
? Select the role: All users
? Select the permission to apply: Explicitly deny access

接下来, 允许所有人阅读Gift模型:

$ slc loopback:acl

? Select the model to apply the ACL entry to: Gift
? Select the ACL scope: All methods and properties
? Select the access type: Read
? Select the role: All users
? Select the permission to apply: Explicitly grant access

然后, 我们要允许经过身份验证的用户创建礼物:

$ slc loopback:acl

? Select the model to apply the ACL entry to: Gift
? Select the ACL scope: A single method
? Enter the method name: create
? Select the role: Any authenticated user
? Select the permission to apply: Explicitly grant access

最后, 让礼物的所有者进行任何更改:

$ slc loopback:acl

? Select the model to apply the ACL entry to: Gift
? Select the ACL scope: All methods and properties
? Select the access type: Write
? Select the role: The user owning the object
? Select the permission to apply: Explicitly grant access

现在, 当我们查看gift.json时, 所有内容都应该准备就绪:

"acls": [
  {
    "accessType": "*", "principalType": "ROLE", "principalId": "$everyone", "permission": "DENY"
  }, {
    "accessType": "READ", "principalType": "ROLE", "principalId": "$everyone", "permission": "ALLOW"
  }, {
    "accessType": "EXECUTE", "principalType": "ROLE", "principalId": "$authenticated", "permission": "ALLOW", "property": "create"
  }
], 

这里的一个重要说明:$ authenticated是预定义的角色, 它对应于系统中的所有用户(捐赠者和接收者), 但是我们只希望捐赠者创建新的礼物。因此, 我们需要一个自定义角色。由于Role是另外一个实体, 我们可以立即使用它, 我们可以利用其API调用在启动功能中创建$ authenticatedDonor角色, 然后只需在gift.json中修改pricipalId。

必须创建一个新文件server / boot / script.js, 并添加以下代码:

Role.create({
    name: 'authenticatedDonor'
}, function(err, role) {
    if (err) return debug(err);
})

RoleMapping实体将角色映射到用户。确保Role和RoleMapping都通过REST公开。在server / model-config.json中, 检查Role实体的” public”设置为true。然后, 在donor.js中, 我们可以编写一个” before create”挂钩, 该挂钩将映射RoleMapping POST API调用中的userID和roleID。

中间件

中间件包含在向REST端点发出请求时执行的功能。由于LoopBack基于Express, 因此它使用Express中间件和一个附加概念, 称为”中间件阶段”。阶段用于明确定义中间件中的函数调用的顺序。

这是LoopBack文档中提供的预定义阶段的列表:

  1. 初始-中间件可以运行的第一点。
  2. session-准备会话对象。
  3. auth-处理身份验证和授权。
  4. parse-解析请求主体。
  5. 路由-实现你的应用程序逻辑的HTTP路由。通过Express API app.use, app.route, app.get(和其他HTTP动词)注册的中间件在此阶段的开始运行。将此阶段也用于子应用程序, 例如loopback / server / middleware / rest或loopback-explorer。
  6. 文件-提供静态资产(请求在此处到达文件系统)。
  7. final-处理错误和对未知URL的请求。

每个阶段都有三个子阶段。例如, 初始阶段的子阶段为:

  1. 首字母缩写:之前
  2. 初始
  3. 初始:之后

让我们快速浏览一下我们的默认middleware.json:

{
  "initial:before": {
    "loopback#favicon": {}
  }, "initial": {
    "compression": {}, "cors": {
      "params": {
        "origin": true, "credentials": true, "maxAge": 86400
      }
    }
  }, "session": {
  }, "auth": {
  }, "parse": {
  }, "routes": {
  }, "files": {
  }, "final": {
    "loopback#urlNotFound": {}
  }, "final:after": {
    "errorhandler": {}
  }
}

在初始阶段, 我们调用loopback.favicon()(loopback#favicon是该调用的中间件ID)。然后, 调用第三方npm模块压缩和cors(带有或不带有参数)。在最后阶段, 我们还有两个电话。 urlNotFound是一个LoopBack调用, 而errorhandler是第三方模块。该示例应证明, 可以使用许多内置调用, 就像外部npm模块一样。当然, 我们总是可以创建自己的中间件, 并通过此JSON文件调用它们。

回送启动

最后, 我们提到一个模块, 该模块可导出用于初始化应用程序的boot()函数。在server / server.js中, 你将找到以下代码, 用于引导应用程序:

boot(app, __dirname, function(err) {
    if (err) throw err;
  
    // start the server if `$ node server.js`
    if (require.main === module)
        app.start();
});

该脚本将搜索服务器/引导文件夹, 并按字母顺序加载在那里找到的所有脚本。因此, 在服务器/引导中, 我们可以指定任何应在启动时运行的脚本。一个示例是explorer.js, 它运行API Explorer, 这是我们用来测试API的客户端。

有重复的忧郁吗?不要再次从头开始构建该Node API。让LoopBack做到!

鸣叫

总结

在离开你之前, 我想提到StrongLoop Arc, 这是一个图形用户界面, 可以用作slc命令行工具的替代方法。它还包括用于构建, 分析和监视Node应用程序的工具。对于那些不喜欢命令行的人, 这绝对值得尝试。但是, StrongLoop Arc即将被弃用, 并且其功能已集成到IBM API Connect Developer Toolkit中。

总结

一般来说, LoopBack可以节省大量的手工工作, 因为你可以立即使用很多东西。它使你可以专注于特定于应用程序的问题和业务逻辑。如果你的应用程序基于CRUD操作并处理预定义的实体, 那么当成千上万的开发人员在编写你的身份验证和授权基础结构之前就厌倦了重写用户的身份验证和授权基础结构, 或者你想利用诸如此类的出色Web框架的所有优点时, Express, 然后使用LoopBack构建REST API可以实现你的梦想。很简单的!

赞(0)
未经允许不得转载:srcmini » 让LoopBack做到:Node API框架实战演练

评论 抢沙发

评论前必须登录!