本教程包括:
- 创建一个FeathersJS API
- 在Heroku上创建和设置一个项目
- 自动部署到Heroku
自动化不仅仅是构建解决方案,以取代复杂或耗时的手动流程。正如流行的说法,"任何可以自动化的东西都应该被自动化"。例如,向应用程序部署更新可以而且应该自动化。在本教程中,我将向你展示如何设置FeathersJS应用程序的免提部署到Heroku。我将指导你实现一个持续部署(CD)管道,以便在变化被推送后立即发布应用程序的更新。我们将使用的示例应用程序是一个管理测验问题的API。它提供了创建、读取、更新和删除测验题的端点。
前提条件
在你开始之前,确保这些项目已经安装在你的系统上。
npm install -g @feathersjs/cli
对于存储库管理和持续集成/持续部署,你需要。
- 一个GitHub账户。
- 一个CircleCI账户。为了方便连接你的GitHub项目,你可以用你的GitHub账户注册。
- 一个Heroku账户。
我们的教程是不分平台的,但以CircleCI为例。如果你没有CircleCI账户,请**在这里注册一个免费账户。**
为什么是FeathersJS和Heroku?
FeathersJS是一个轻量级的网络框架,用于使用JavaScript或TypeScript创建实时应用程序和REST APIs。FeathersJS的工具集包括一个架构模式,可以轻松地创建可扩展的REST API和实时应用程序。你可以在几分钟内建立原型,在几天内建立生产就绪的应用程序。
Heroku是一个平台即服务(PaaS),使开发者能够完全在云中构建、运行和操作应用程序。通过处理维护基于云的应用程序的更多要求,Heroku允许开发人员专注于构建应用程序而不是维护服务器。
开始使用
为该项目创建一个新的文件夹。
mkdir feathers_heroku
cd feathers_heroku
接下来,使用Feathers CLIgenerate 命令生成一个新的应用程序。
feathers generate app
对于这个项目,我们将使用JavaScript。另外,我们只想做一个REST API。响应CLI的问题,如这里所列。
? Do you want to use JavaScript or TypeScript? JavaScript
? Project name feathers-heroku
? Description
? What folder should the source files live in? src
? Which package manager are you using (has to be installed globally)? npm
? What type of API are you making? REST
? Which testing framework do you prefer? Jest
? This app uses authentication No
? Which coding style do you want to use? ESLint
在你做其他事情之前,更新索引页,让访问者知道API正在建设中。在public/index.html ,在main 元素中添加一个 "正在建设 "的信息。
<main class="container">
<!-- Image declaration-->
<h1 class="center-text">This API is under construction</h1>
<!-- Footer declaration-->
</main>
接下来,使用下面这个命令运行你的应用程序。
npm run dev
默认情况下,应用程序在3030端口运行。在你的浏览器中输入http://localhost:3030/ ,就可以去那里。

配置Heroku
你的下一步是在Heroku上创建一个新的应用程序。你可以在Heroku仪表板上完成这项工作。点击新建,然后点击**新建应用程序。**如图所示,填写表格。如果你愿意,你可以为应用程序使用不同的名称和地区。

单击 "创建应用程序"按钮。然后你将被转到新创建的应用程序的部署视图。
接下来,你需要添加一个构建包。单击 "设置"选项卡。在buildpacks部分,点击Add buildpack。

在打开的表格中,你可以选择一个官方支持的构建包,或者为你的构建包提供一个 URL。选择nodejs来使用官方支持的Heroku nodejs构建包。点击保存更改。Node.js将被用于构建你的下一个部署。
你需要的最后一件事是一个API密钥。你将用它来连接你的CircleCI管道和Heroku。为了得到你的API密钥,打开账户设置页面,向下滚动到API密钥部分。

点击 "揭示"按钮,复制显示的API密钥。
配置CircleCI
接下来,我们需要添加CircleCI的管道配置。对于这个项目,管道将由两个步骤组成。
- 建立:在这里,我们构建项目并安装项目的依赖性。理想情况下,我们应该在这个阶段运行项目测试。然而,为了保持本教程的合理长度,我们将跳过测试。
- 部署到Heroku:如果构建阶段成功完成,你可以将最新的变化部署到Heroku。
在你项目的根部,创建一个名为.circleci 的文件夹。在其中,创建一个名为config.yml 的文件。在这个新创建的文件中,添加这个配置。
# Use the latest 2.1 version of CircleCI pipeline process engine.
version: 2.1
orbs:
heroku: circleci/heroku@1.2.6
node: circleci/node@4.7.0
jobs:
build:
executor: node/default
steps:
- checkout
- node/install-packages:
cache-path: ~/project/node_modules
override-ci-command: npm install
workflows:
sample:
jobs:
- build
- heroku/deploy-via-git:
force: true # this parameter instructs the push to use a force flag when pushing to the heroku remote, see: https://devcenter.heroku.com/articles/git
requires:
- build
这个配置拉入了Heroku的球体circleci/heroku 。这个球体使你能够访问一组强大的Heroku工作和命令。其中一个作业,heroku/deploy-via-git ,将你的应用程序从GitHub repo直接部署到你的Heroku账户。该配置使用Node.js orbcircleci/node ,它允许你安装默认启用缓存的软件包。
在配置中还指定了一个名为build 的工作,检查最新的代码并安装package.json 文件中指定的包。
最后,有一个工作流程,运行build 工作,然后是heroku/deploy-via-git 工作。注意,有一个requires 选项,告诉CircleCI只有在构建工作完成后才运行deploy-via-git 。
接下来,在GitHub上建立一个仓库,并将该项目链接到CircleCI。
登录你的CircleCI账户。如果你用GitHub账户注册,你所有的仓库将显示在你的项目仪表板上。
在你的feathers_heroku 项目旁边,点击Set Up Project。
CircleCI会检测项目中的config.yml 文件。点击使用现有的配置,然后开始构建。您的第一个工作流程将开始运行,然而,它将失败!这是预料之中的。这是预料之中的事。

部署过程失败是因为你没有提供你的Heroku API密钥。现在就去解决这个问题吧。点击项目设置按钮,然后点击环境变量。添加两个新的变量,如下所示。
HEROKU_APP_NAME变量是Heroku中的应用程序名称(deno-heroku-circleci)。HEROKU_API_KEY变量是你从账户设置页面获取的Heroku API密钥。
选择RerunWorkflow from Failed选项,重新运行Heroku部署。为了确认你的工作流是成功的,你可以在浏览器中打开你新部署的应用程序。你的应用程序的URL应该是这样的格式:https://<HEROKU_APP_NAME>.herokuapp.com/ 。
迎接你的将是正在建设中的索引页面。
实施questions 服务
现在是时候在我们的API上添加处理问题的功能了。在本教程中,一个问题将有这些属性的字段。
- 难度
- 问题
- 正确答案
在创建问题时,默认分配一个唯一的主键。
使用这个命令创建一个数据库支持的服务。
feathers generate service
对于这个服务,使用NeDB ,你可以直接按回车键来确认。使用Questions 作为服务名称,并以默认值确认所有其他提示。只需按下Enter键。
? What kind of service is it? NeDB
? What is the name of the service? Questions
? Which path should the service be registered on? /questions
? What is the database connection string? nedb://../data
通过这个命令,FeathersJS已经提供了你对问题进行CRUD操作所需要的一切。在这一点上,你有一个带有这些端点的API。
GET /questions逐页列出所有问题。POST /questions创建一个新的问题。GET questions/123返回id为123的问题的细节。你也可以在这个请求中包括查询: 。questions/123?difficulty=mediumPATCH /questions/123和 更新id为123的问题的细节。PUT /questions/123DELETE /questions/123删除ID为123的问题。
你可以为你的应用程序提供服务,并向任何一个端点发出请求。在本教程中,在使用你闪亮的新API之前,先对数据库进行播种并覆盖一些默认功能。
当你收到一个添加问题的请求时,你想在把它们保存到数据库之前,只从请求中检索出先前指定的三个值。通过重写create 服务方法来做到这一点。打开src/services/questions/questions.class.js ,并编辑它以匹配这段代码。
// src/services/questions/questions.class.js
const { Service } = require("feathers-nedb");
exports.Questions = class Questions extends Service {
create(data, params) {
const { question, correctAnswer, difficulty } = data;
const quizData = { question, correctAnswer, difficulty };
return super.create(quizData, params);
}
};
接下来,创建一个播种机,它将给你一些样本问题。在src/services/questions 目录中,创建一个名为questions.seed.js 的新文件。将这段代码添加到新创建的文件中。
// src/services/questions/questions.seed.js
exports.seedQuestions = [
{
difficulty: "medium",
question: "The HTML5 standard was published in 2014.",
correctAnswer: "True",
},
{
difficulty: "medium",
question:
"Which computer hardware device provides an interface for all other connected devices to communicate?",
correctAnswer: "Motherboard",
},
{
difficulty: "medium",
question: "On which day did the World Wide Web go online?",
correctAnswer: "December 20, 1990",
},
{
difficulty: "medium",
question: "What is the main CPU is the Sega Mega Drive / Sega Genesis?",
correctAnswer: "Motorola 68000",
},
{
difficulty: "medium",
question: "Android versions are named in alphabetical order.",
correctAnswer: "True",
},
{
difficulty: "medium",
question:
"What was the first Android version specifically optimized for tablets?",
correctAnswer: "Honeycomb",
},
{
difficulty: "medium",
question:
"Which programming language shares its name with an island in Indonesia?",
correctAnswer: "Java",
},
{
difficulty: "medium",
question: "What does RAID stand for?",
correctAnswer: "Redundant Array of Independent Disks",
},
{
difficulty: "medium",
question:
"Which of the following computer components can be built using only NAND gates?",
correctAnswer: "ALU",
},
{
difficulty: "medium",
question:
"What was the name of the security vulnerability found in Bash in 2014?",
correctAnswer: "Shellshock",
},
];
接下来,打开src/services/questions/questions.service.js ,编辑它以匹配这段代码。
// src/services/questions/questions.service.js
// Initializes the `Questions` service on path `/questions`
const { Questions } = require("./questions.class");
const createModel = require("../../models/questions.model");
const hooks = require("./questions.hooks");
const { seedQuestions } = require("./questions.seed");
module.exports = async function (app) {
const options = {
Model: createModel(app),
paginate: app.get("paginate"),
};
// Initialize our service with any options it requires
app.use("/questions", new Questions(options, app));
// Get our initialized service so that we can register hooks
const service = app.service("questions");
//get the total number of questions in the database
const { total: totalQuestions } = await service.find({
query: {
$limit: 0,
},
});
//seed the database if there are no questions saved
if (totalQuestions === 0) {
await seedQuestions.forEach((question) => {
service.create(question);
});
}
service.hooks(hooks);
};
请注意,这段代码首先检查数据库中的问题数量,只有在没有问题时才进行播种。这可以避免每次启动本地服务器时都运行播种机。
使用Postman测试FeathersJS的API
现在你可以使用Postman来测试你的API。
发送一个POST 请求到http://localhost:3030/questions 。

发送一个GET 请求到http://localhost:3030/questions ,以检索问题列表。

很好!最后,用最新的代码更新git仓库。不要忘记删除索引页上的 "正在建设中 "的信息。
git add .
git commit -m "Implement CRUD functionality for questions"
git push origin main
你的CircleCI构建再次运行,完成后,你的Heroku应用将以最新代码更新。干得好!
总结
在本教程中,我向您展示了如何使用GitHub、CircleCI和Heroku为FeathersJS API建立一个CI/CD管道。