介绍
待办事项清单已成为“ Hello,World!”比较并演示新的JS前端框架的示例。但是,本教程不同,因为它不涉及前端框架,而是将用于用户界面(UI)的Vanilla Web Technologies。这样做是为了使我们可以整体上关注堆栈以及层之间的接口,我认为这是堆栈中最重要的元素。
to to Application是一个很好的例子,是其中包括许多业务系统常见的四个基本数据操作(或CRUD)操作。 Crud首字母缩写代表:
- 创建:在存储中添加新项目。
- 阅读:从存储中检索一个或多个项目。
- 更新:更改一个或多个存储项目的数据。
- 删除:从存储中删除一个或多个项目。
在我们的示例中,更新和删除操作只能一次应用于一个待办事项,并且读取操作将用于检索存储中的所有托尔多商品。
此类系统中的另一个常见首字母缩写词是REST或RESTful,它描述了一种用于在Web浏览器和服务器(或API)之间进行通信的方法。休息比我们在这篇文章中需要讨论的要多得多,但是值得一提的是CRUD操作如何与休息策略保持一致。 REST使用HTTP(超文本传输协议)将请求发送到服务器并在客户端/浏览器中接收响应(通常按照该顺序)。有多种请求类型用于指示服务器所需的内容,称为HTTP动词或方法。
这就是可以将Crud操作映射到HTTP动词的方式:
创建 - >发布
阅读 - >获取
更新 - >补丁(也可以使用put,但意味着略有不同)
删除 - >删除,很明显。
如果您想了解有关HTTP动词/方法的更多信息,这是指向MDN page的链接。
从内而外发展
通过早期定义甚至实现两个子系统之间的接口,建立了一个更坚定的基础,以构建界面的两侧。正如将证明的那样,在三层体系结构(FRANTEND(Fe),后端(BE)和数据库(db))中有两个子系统边界; fe/be and be/db。
我们的后端只不过是数据库和用户界面(UI)之间的双向翻译层。在本文的稍后,我们将确定后端的其他职责,但我们的实施将保持简单,以证明基本的机械和概念。值得注意的是,后端有两个部分,网络服务器和应用程序服务器。 json-server和Express都能够从同一URL中促进这些角色。这对于我们的教程非常有用,因为我们不必配置服务器来管理交叉原始资源共享(CORS)。生产系统出于各种充分的理由将这些服务器角色分开是很典型的,但是现在它将造成额外的并发症。
源代码(警告空器)
我已经在GitHub repo中发布了本文的源代码,但我必须谨慎行事。这不是生产代码。出于本文结尾处讨论的原因,该守则仅用于教育目的,不应用于生产中。
分步教程
我们的示例应用程序将基于m*n堆栈,其中m是MongoDB(但可能是mySQL或任何其他)数据库。 e为Express,这是一个位于Node.js顶部的后端框架。还有其他,但Express非常普遍,可以很好地满足我们的需求。 N适用于JavaScript Runtime Node.js,但Deno和Bun是可能的替代方法。最后, *用于前端框架,例如Angular(Mean),React(Mern)或Vue(Mevn),仅举几例。但是,在我们的示例中,我们将不会使用框架(以使其不可知,此外不是那么复杂),我们将使用本机Web Technologies(HTML,CSS和JS)。
。本教程中有六个步骤,在上一个教程中,每座建筑物都有:
- 简单基于数组的接口模块 - 确定要求,但在页面上(丢失的页面刷新)存储。
- 基于Web存储的修订界面 - 提供本地数据持久性(在浏览器会话期间,但可能更长)。
- 用户界面(UI),使用API模块修订以与基于JSON服务器进行交互的API模块 - 建立Fe/Be接口的最终版本,但具有模拟后端和存储。
- UI与以前相同的Fe/be接口模块连接到节点表达后端,并将第一个接口模块(基于数组)作为临时后端存储。有一个轻微的变化使它起作用,但它很小。
- 上一步的演变再次采用JSON服务器,但仅用于数据存储。这将从第三步重复使用Fe/Be接口模块,再次发生略有更改。
- 最后,我们将JSON服务器交换为MongoDB数据库,该数据库由MongoDB Atlas提供,该数据库将需要基于JSON-Server版本的新接口模块。
在前两个步骤中,我们将使用嘲笑和简单的集成测试(线束)使用HTML文件提供单位测试。您将观察到UI是原始的,并使用开发工具(浏览器控制台)呈现测试结果。为第三步开发的UI要好一些,并使用户互动以更现实的方式行使CRUD操作。
增量发展
本教程围绕着fe/be and be/db(crud-interface.js)之间接口的开发和演变。该界面采用揭示模块模式(RMP)公开功能:
- createtododo
- readtodolist
- updateTododo
- 删除方法
RMP还可以以依赖性注射的形式提供依赖关系,例如数据集,功能和其他模块;我们将用来模拟外部设施的机制。
第一步:第一个接口模块 - 保持简单
为了开始开发,我们将首先使用JEST测试框架创建单元测试,以采用测试驱动的开发(TDD)方法。但是,我们的Fe/BE接口将使用ES6模块(ESM)语法,而不是通用JS(CJS)语法默认为Node.js。因此,我们需要(从节点19.7.0开始)我们需要使用命令行开关来启用ESM如下。
node --experimental-vm-modules node_modules/jest/bin/jest.js
Crud-interface单元测试将首先以以下JSON文档的形式导入接口模块和数据集。
{
"toDos": [
{
"text": "Task One",
"done": true,
"id": "1"
},
{
"text": "Task Two",
"done": false,
"id": "2"
}
]
}
单位测试将执行四个正测试用例,每次暴露方法,以及列表为空的三个负面测试用例,然后在更新或删除时找到待办事项。 CRUD接口模块的初始实现基于一个简单的数组,该数组可以在实例化时提供。这意味着当我们执行模块的默认方法时,单位测试可以传递上述测试数据的托多属性。数组CRUD操作很简单,但我们无法替换数组本身,否则单位测试将丢失参考,而是我们必须替换其内容。
除了单位测试外,我们还具有索引。HTML测试线束的形式的集成/功能测试能力。该测试不是在Web浏览器中进行的,而不是使用Jest Framework,而不是预期模块运行的方式。因此,我们将使用JSON-Server软件包作为代理Web服务器,以使所有资源可用于浏览器在线;我们将在前三个步骤中使用类似的策略。
第二步:改善数据持久性的较小增强
在第二步中,我们修改了接口模块的内部工作,以将数组与Windows Session Web Storage交换。外部/公共接口将保持不变,因此单位测试将基本保持不变。两个关键区别是:
- 接口模块依赖关系将是
window.sessionStorage
名称空间。 - 单位测试将模拟依赖性,这使测试用例可以确认接口两侧的操作。
和以前一样,模块的实现将使用ESM语法,并且将有一个基于HTML的测试安全带,以提供更大的上下文并将Jest框架排除在测试环境中,但将再次使用JSON服务器来交付内容到浏览器。
第三步:添加使用代理后端的用户界面
我们将继续使用第三步的两层测试方法,但是这次我们将更广泛地使用JSON服务器。 JSON-Server将同时提供Web服务器以交付页面和应用程序服务器以访问数据存储(以JSON文件的形式)。为了执行单元和集成测试,我们需要使用启动脚本运行服务器。服务器完成加载后,测试脚本将执行修订后的接口模块的单元测试。完成后,可以通过像以前一样加载http://localhost:3000’来访问浏览器的测试线束来执行集成测试。
接口模块的级三版本的关键差异是它使用fetch API与服务器进行交互。模块唯一的依赖性是API的URL,但可以扩展到包含fetch API。这将使可以在设备测试中交换实际的获取机制,以换取模拟等效物,并避免运行实际的服务器。相反,开始脚本将重置源数据并启动服务器。还扩展了集成测试以提供更具交互性(和现实的)用户界面。
UI介绍了存储的任务列表和输入字段,以输入新任务的名称。可以预期的是,添加按钮在存储中创建了一个新任务,完成了更新关联的任务以将其标记为删除,并且删除按钮从存储中删除了关联的任务。当输入字段为空时,添加按钮将被禁用。
该模块的精确版本将用于接下来三个步骤的Fe/是接口。
第四步:将UI连接到具有简单存储的生产级后端
在此和以下步骤中,我们将使用后端和前端中的接口模块。在可能的情况下,BE/DB接口将基于先前开发的FE/实现,并具有较小的差异。 Fe/BE模块使用标准化的Ecmasixt模块(ESM)语法,该语法需要对Nodejs进行某种配置以促进测试。 BE/DB模块将采用NodeJS环境原产的通用JS(CSJ)模块系统。
在此步骤中,从现在开始,将使用NodeJS顶部的ExpressJS框架实现中间层(后端)。 Express组件揭示了从前端到BE/db接口的映射请求的安息。第四步使用基于第一个实现(第一个)的BE/DB接口模块。两种实现之间的唯一区别是从ESM语法进行更改,
export default function (toDoList = []) {
和CJS模块语法
module.exports = function (toDoList = []) {
都期望Todolist数组作为依赖性。
第五步:调整JSON服务器FE/BE接口模块用于/db使用
类似于上一个步骤,下一步重新启动了Fe/Bd接口模块的早期实现(从步骤3)用作BE/DB接口,使用JSON-Server作为代理数据库。
再次真正的区别是模块语法的更改。
来自export default function (endpointUrl = 'http://localhost:3000/toDos')
,
到module.exports = function (endpointUrl = 'http://localhost:3300/toDos')
。
您也可能会注意到唯一的区别是端口号从3000变为3300。这反映了我们直接与数据库(代理)而不是后端服务器进行通信的事实。
第六步:用生产级云服务器替换代理存储
最后,我们用实际内容替换BE/DB接口和代理数据库。
在我们的示例中,我们与他们的Atlas服务托管的MongoDB数据库建立了联系。需要确保连接,以便参数存储在以下结构的.env文件中。
USER_ID=userId
USER_PWD=userPassword
DB_NAME=databaseName
DB_COLLECTION=databaseCollection
制作示例堆栈的生产级版本
Me*n堆栈的实现非常容易受到攻击。没有通过FE进行错误或滥用的保护,通过使用FE框架(例如React,Angular,Vue等)将大大改善,Fe/BE接口也对恶意演员开放。可以通过使用HTTP来加密通信路径并进行中间攻击来改善这一点。 JWT也可以用于建立用户身份验证。通过使用两个Express中间件包(头盔和Mongoose),也可以使堆栈更加健壮,可维护。
Helmet有助于消毒的输入,这可能不是直接来自UI。 Mongoose是所谓的对象文档建模(ODM),它定义了存储数据的结构(架构),从而更易于在Express中管理。我们的示例堆栈中省略了这些添加,以简化教程并关注基本层和接口。