本文面向刚接触 LoopBack 3 的 Node.js 开发者。 假设你已经会写一点 Express,想要少写点样板代码,快点把 REST API 搭起来。

LoopBack 3 是什么?

简单粗暴地说:LoopBack 3 就是一个帮你把数据模型直接变成 REST API 的 Node.js 框架

它帮你做了几件平时总是做,却很烦的事情:

  • 一堆 CRUD 路由和控制器的样板代码;
  • Model → 数据库的持久化和数据自动迁移;
  • 内置 API Explorer,当场点点按钮就能试接口;
  • 各种数据库和服务的 connector:MySQL、MongoDB、REST、SOAP 等。

官方的 Getting Started 用一杯 CoffeeShop 做例子:我们会建一个 CoffeeShop 模型,把它暴露成 REST API, 先放在内存里玩一玩,再挂到 MySQL 上,顺手再写个 remote method、静态页面和自定义路由。

下面按这个顺序简单介绍一下 Loopback。

环境准备

你需要:

  • Node.js & npm(任一长期支持版本即可);
  • LoopBack 命令行工具(下面用 lb 作为示例命令)。

全局安装 CLI(不同年代的工具名字略有区别,你可以选一个用即可):

npm install -g loopback-cli

安装完成后,命令行里敲一句 lb -h 能看到帮助信息,就说明工具就绪了。

用 lb 命令创建一个 LoopBack 应用

在你准备放代码的目录里执行:

lb

命令会一路问你几个问题,大致是:

  1. 项目名: 比如输入 loopback-getting-started(你也可以叫别的,只要自己记得替换即可)。

  2. 项目目录名: 直接回车,默认就是同名目录。

  3. 应用类型

    • 想完全自己来:选 empty-server(空 API 服务器);
    • 想先看看“Hello World”:可以选一个带示例的模板。

官方 Getting Started 示例会根据你用的是 lb / apic / slc,让你选略微不同的模板, 本质都是帮你把标准目录结构和配置文件搭好。

生成器跑完后,目录里大概会多出这些东西:

  • server/:应用入口、数据源、模型绑定、中间件配置;
  • common/:通用模型定义和扩展;
  • client/:以后放静态资源或前端代码;
  • 一堆 JSON 配置文件:datasources.jsonmodel-config.jsonmiddleware.json 等。

你可以先 npm install 把依赖装好:

cd loopback-getting-started
npm install

创建 CoffeeShop 模型并自动生成 REST API

模型在 LoopBack 里是核心概念:一个模型 = 一张表 + 一组 REST 接口 + 一堆逻辑扩展点

在项目根目录:

lb model

按照提示填写:

  1. 模型名CoffeeShop
  2. 数据源:选默认的 db (memory),内存数据库,开发测试用刚好;
  3. 基类(base class):选 PersistedModel,表示这个模型未来要落到持久化数据源,比如 MySQL;
  4. 是否暴露为 REST API:选 Yes;
  5. 复数形式:按回车,LoopBack 会自动加个 s,变成 CoffeeShops
  6. 模型存放位置:选 common,以后前后端共享模型定义会更方便;
  7. 属性(properties)

    • name: string,Required? 选 Yes
    • city: string,Required? 选 Yes
    • 按回车结束属性添加。

做完这套之后,LoopBack 帮你:

  • common/models/ 下建好了 coffee-shop.jsoncoffee-shop.js
  • 在 REST 层自动挂了 CRUD 接口(后面会在 API Explorer 里看到)。

启动应用,并使用 API Explorer 预览

先启动应用:

node .

控制台里会出现类似的信息:

Web server listening at: http://0.0.0.0:3000/
Browse your REST API at http://0.0.0.0:3000/explorer

打开浏览器访问:

http://localhost:3000/explorer

你会看到一个 Swagger 风格的界面,里面列着当前应用里的模型,比如:

  • Users(内置用户模型);
  • CoffeeShops(刚才创建的模型)。

点开 CoffeeShops,可以看到整套 API:

  • POST /CoffeeShops:创建一条记录;
  • GET /CoffeeShops:查所有;
  • GET /CoffeeShops/{id}:按 id 查详情;
  • ……

随便试一个 POST /CoffeeShops,在请求体里填:

{
  "name": "My Coffee Shop",
  "city": "Shanghai"
}

点 “Try it out”,你会看到 Response 里返回刚刚创建的那条数据。再去点 GET /CoffeeShops,就能把刚才的数据查出来。 如果需要按条件过滤,还可以在 filter 参数里加上 where / limit / order 之类的查询。

到这里,我们已经有了一个真正能用的 REST API,只是数据还在内存里,重启就没了。

把 CoffeeShop 挂到 MySQL 上

在实际生产环境中,使用内存数据库是远远不够的,是时候接上真数据库了。 官方教程用的是 MySQL,我们也跟着它走一遍。

创建 MySQL 数据源

在项目根目录:

lb datasource

按提示:

  1. 数据源名:mysqlDs
  2. 选择 connector:选 MySQL 对应的那一项;
  3. 配置连接信息:可以用自己的 MySQL,也可以参考官方教程里的 demo 设置(host、port、user、password、database)。

完成后,生成器会:

  • 安装 loopback-connector-mysql
  • server/datasources.json 里追加一个类似这样的配置(示意):
{
  "db": {
    "name": "db",
    "connector": "memory"
  },
  "mysqlDs": {
    "name": "mysqlDs",
    "connector": "mysql",
    "host": "localhost",
    "port": 3306,
    "database": "getting_started",
    "user": "demo",
    "password": "secret"
  }
}

让 CoffeeShop 用上这个数据源

打开 server/model-config.json,找到 CoffeeShop 这一段,把数据源从 db 改成 mysqlDs

"CoffeeShop": {
  "dataSource": "mysqlDs",
  "public": true
}

改完后,CoffeeShop 的 CRUD 就会直接落到 MySQL 里了。

用 boot 脚本自动建表

LoopBack 有一个“自动迁移(auto-migrate)”机制,可以根据模型定义在数据库里建表。 我们借这个机会顺便认识一下 boot 脚本

server/boot/create-sample-models.js 里写一个简单脚本(示意代码,可以按自己喜好改名):

// server/boot/create-sample-models.js
module.exports = function (app) {
  const mysql = app.dataSources.mysqlDs;
  const CoffeeShop = app.models.CoffeeShop;

  mysql.automigrate("CoffeeShop", function (err) {
    if (err) throw err;

    CoffeeShop.create(
      [
        { name: "Bel Cafe", city: "Vancouver" },
        { name: "Three Bees Coffee House", city: "San Mateo" },
        { name: "Caffe Artigiano", city: "Vancouver" },
      ],
      function (err, shops) {
        if (err) throw err;
        console.log("Sample CoffeeShops:", shops.map((s) => s.name).join(", "));
      }
    );
  });
};

这个脚本会在应用启动时执行:

  • automigrate 会根据 CoffeeShop 模型重建表结构;
  • 然后插入几条示例数据。

注意:

  • automigrate 是“先删表再建表”,适合开发环境,千万别直接拿去跑生产
  • 生产环境更常用的是 “autoupdate”,或者手写 SQL / 使用迁移工具。

重新跑 node .,看一下控制台和 MySQL 里的数据表,再用 API Explorer 请求 GET /CoffeeShops,数据就真落到数据库里了。

用 remote method 扩展 CoffeeShop 的业务逻辑

LoopBack 自动帮你生成了 CRUD 接口,但你总得写点“自己的业务逻辑”。 在 LoopBack 3 里,这类“自定义方法 + 暴露为 REST”叫 remote method

我们给 CoffeeShop 加一个很轻量的接口:告诉你“现在是不是营业时间”。

在模型 JS 里添加方法

打开 common/models/coffee-shop.js,加上类似这样的代码:

// common/models/coffee-shop.js
module.exports = function (CoffeeShop) {
  CoffeeShop.status = function (cb) {
    const hour = new Date().getHours();
    const openHour = 6;
    const closeHour = 20;

    const isOpen = hour >= openHour && hour < closeHour;
    const message = isOpen
      ? "We are open for business."
      : "Sorry, we are closed. Open daily from 6am to 8pm.";

    cb(null, { status: message });
  };

  CoffeeShop.remoteMethod("status", {
    http: { path: "/status", verb: "get" },
    returns: { arg: "result", type: "object" },
  });
};

这里做了两件事:

  • 定义了一个普通的 Node 函数 CoffeeShop.status
  • remoteMethod 把它挂成一个 GET /CoffeeShops/status 的 REST 接口。

重启应用,打开 API Explorer:

  • 进入 CoffeeShops
  • 你会看到多了一个 GET /CoffeeShops/status
  • 点 “Try it out” 就能看到返回的状态文案。

注意:

  • remote method 的 http.path 要以 / 开头;
  • returns 里记得指定 argtype,否则 API Explorer 展示会比较奇怪。

加一个静态页面,以及自定义 Express 路由

LoopBack 3 是构建在 Express 之上的,所以它既能当 API 框架,也可以帮你顺手把静态资源和自定义路由搞定。

用中间件服务静态页面

目标:访问 http://localhost:3000/ 时,不再返回一堆 JSON 状态,而是能看到一个简陋的 HTML 页面。

  1. 禁用默认的 root 状态脚本

    server/boot/root.js 里默认装了一个 / 路由,返回服务器状态。 你可以直接把这个文件删掉,或者改成 root.js.bak 之类的名字,让它不再被执行。

  2. 在 middleware.json 里配置静态文件中间件

    打开 server/middleware.json,找到 files 这一节,把它改成类似这样:

    "files": {
      "loopback#static": {
        "params": "$!../client"
      }
    }
    

    $! 表示这个路径相对于 middleware.json 所在目录。 配置好之后,/client 目录里的文件就会被当作静态资源来服务。

  3. 加一个简单的首页

    client/index.html 写点最基础的东西,例如:

    <head>
      <title>LoopBack CoffeeShop</title>
    </head>
    <body>
      <h1>LoopBack CoffeeShop</h1>
      <p>Hello, LoopBack 3!</p>
    </body>
    

    重新跑 node .,打开 http://localhost:3000/,你就能看到这段页了。

写一个自定义 Express 路由(/ping)

现在来加一个很经典的 /ping 路由,顺便认识一下 boot 脚本 的另外一个用途。

新建 server/boot/routes.js

// server/boot/routes.js
module.exports = function (app) {
  // 安装一个 "/ping" 路由,返回 "pong"
  app.get("/ping", function (req, res) {
    res.send("pong");
  });
};

重启应用,访问:

http://localhost:3000/ping

就能看到简洁的 "pong" 了。

boot 脚本能干什么:

  • 在应用启动时做初始化工作(连数据库、迁移、写样例数据);
  • 注册自定义路由或中间件;
  • 任何需要“启动就跑一次”的逻辑,都可以丢进 server/boot

至此,一个简单的 Loopback 应用就搭好了。之后还有更复杂的,比如:

  • 使用多数据源;
  • 模型之间的关系;
  • Remote hooks;
  • 权限控制。

参考资料