构建 Node.js Express API 以将 Markdown 转换为 HTML

已发表: 2022-03-10
快速总结 ↬了解如何使用 Node.js 和 Express 框架来创建 API 端点——在构建将 Markdown 语法转换为 HTML 的应用程序的上下文中。

Markdown 是一种轻量级的文本标记语言,允许将标记的文本转换为各种格式。 创建 Markdown 的最初目标是让人们“使用易于阅读和易于编写的纯文本格式进行编写”,并可选择将其转换为结构上有效的 XHTML(或 HTML)。 目前,随着 WordPress 支持 Markdown,该格式已得到更广泛的使用。

撰写本文的目的是向您展示如何使用 Node.js 和 Express 框架来创建 API 端点。 我们将通过构建一个将 Markdown 语法转换为 HTML 的应用程序来学习这一点。 我们还将向 API 添加身份验证机制,以防止滥用我们的应用程序。

一个 Markdown Node.js 应用程序

我们称为“Markdown 转换器”的小型应用程序将使我们能够发布 Markdown 样式的文本并检索 HTML 版本。 该应用程序将使用 Node.js Express 框架创建,并支持转换请求的身份验证。

我们将分小阶段构建应用程序——最初使用 Express 创建一个脚手架,然后随着我们的进展添加各种功能,例如身份验证。 因此,让我们通过创建脚手架从构建应用程序的初始阶段开始。

跳跃后更多! 继续往下看↓

第 1 阶段:安装 Express

假设您已经在系统上安装了 Node.js,创建一个目录来保存您的应用程序(我们称之为“ markdown-api ”),然后切换到该目录:

 $ mkdir markdown-api $ cd markdown-api

使用 npm init 命令为您的应用程序创建一个package.json文件。 此命令会提示您输入许多信息,例如应用程序的名称和版本。

现在,只需按 Enter即可接受其中大多数的默认值。 我已将默认入口点文件用作index.js ,但您可以根据自己的喜好尝试app.js或其他文件。

现在在markdown-api目录中安装 Express 并将其保存在依赖项列表中:

 $ npm install express --save

在当前目录( markdown-api )创建一个index.js文件,并添加以下代码来测试 Express 框架是否安装正确:

 Const express = require('express'); var app = express(); app.get('/', function(req, res){ res.send('Hello World!'); }); app.listen(3000);

现在浏览到 URL https://localhost:3000以检查测试文件是否正常工作。 如果一切正常,我们将看到一个 Hello World! 在浏览器中打招呼,我们可以继续构建一个基础 API 来将 Markdown 转换为 HTML。

第 2 阶段:构建基础 API

我们 API 的主要目的是将 Markdown 语法中的文本转换为 HTML。 API 将有两个端点:

  • /login
  • /convert

login端点将允许应用程序验证有效请求,而convert端点将(显然)将 Markdown 转换为 HTML。

下面是调用这两个端点的基本 API 代码。 login调用只返回一个“Authenticated”字符串,而convert调用返回你提交给应用程序的任何 Markdown 内容。 home 方法只返回一个“Hello World!” 细绳。

 const express = require("express"); const bodyParser = require('body-parser'); var app = express(); app.use(bodyParser.urlencoded({ extended: true })); app.use(bodyParser.json()); app.get('/', function(req, res){ res.send('Hello World!'); }); app.post('/login', function(req, res) { res.send("Authenticated"); }, ); app.post("/convert", function(req, res, next) { console.log(req.body); if(typeof req.body.content == 'undefined' || req.body.content == null) { res.json(["error", "No data found"]); } else { res.json(["markdown", req.body.content]); } }); app.listen(3000, function() { console.log("Server running on port 3000"); });

我们使用body-parser中间件来轻松解析应用程序的传入请求。 中间件将使您可以在req.body属性下使用所有传入的请求。 您可以不使用额外的中间件,但添加它可以更轻松地解析各种传入的请求参数。

您可以通过简单地使用 npm 来安装body-parser

 $ npm install body-parser

现在我们已经有了我们的虚拟存根函数,我们将使用 Postman 来测试它。 让我们首先从 Postman 的简要概述开始。

邮递员概述

Postman 是一种 API 开发工具,可以轻松地在浏览器中或通过下载桌面应用程序(浏览器版本现已弃用)来构建、修改和测试 API 端点。 它能够发出各种类型的 HTTP 请求,即 GET、POST、PUT、PATCH。 它适用于 Windows、macOS 和 Linux。

下面是 Postman 的界面体验:

邮递员界面
(大预览)

要查询 API 端点,您需要执行以下步骤:

  1. 在顶部的网址栏中输入您要查询的网址;
  2. 选择 URL 栏左侧的 HTTP 方法发送请求;
  3. 单击“发送”按钮。

Postman 会将请求发送到应用程序,检索任何响应并将其显示在下部窗口中。 这是如何使用 Postman 工具的基本机制。 在我们的应用程序中,我们还必须向请求中添加其他参数,这将在以下部分中进行介绍。

使用邮递员

现在我们已经看到了 Postman 的概述,让我们继续在我们的应用程序中使用它。

从命令行启动你的markdown-api应用程序:

 $ node index.js

为了测试基本 API 代码,我们从 Postman 对应用程序进行 API 调用。 请注意,我们使用 POST 方法将要转换的文本传递给应用程序。

应用程序目前接受 Markdown 内容通过content POST 参数进行转换。 我们将其作为 URL 编码格式传递。 目前,该应用程序以 JSON 格式逐字返回字符串——第一个字段始终返回字符串markdown ,第二个字段返回转换后的文本。 稍后,当我们添加 Markdown 处理代码时,它会返回转换后的文本。

第三阶段:添加 Markdown 转换器

现在构建了应用程序脚手架,我们可以查看Showdown JavaScript 库,我们将使用它来将 Markdown 转换为 HTML。 Showdown 是一个用 JavaScript 编写的双向 Markdown 到 HTML 转换器,它允许您将 Markdown 转换为 HTML 并返回。

使用 Postman 进行测试
(大预览)

使用 npm 安装包:

 $ npm install showdown

将所需的摊牌代码添加到脚手架后,我们得到以下结果:

 const express = require("express"); const bodyParser = require('body-parser'); const showdown = require('showdown'); var app = express(); app.use(bodyParser.urlencoded({ extended: true })); app.use(bodyParser.json()); converter = new showdown.Converter(); app.get('/', function(req, res){ res.send('Hello World!'); }); app.post('/login', function(req, res) { res.send("Authenticated"); }, ); app.post("/convert", function(req, res, next) { if(typeof req.body.content == 'undefined' || req.body.content == null) { res.json(["error", "No data found"]); } else { text = req.body.content; html = converter.makeHtml(text); res.json(["markdown", html]); } }); app.listen(3000, function() { console.log("Server running on port 3000"); });

主转换器代码位于/convert端点中,如下所示。 这会将您发布的任何 Markdown 文本转换为 HTML 版本,并将其作为 JSON 文档返回。

 ... } else { text = req.body.content; html = converter.makeHtml(text); res.json(["markdown", html]); }

进行转换的方法是converter.makeHtml(text) 。 我们可以使用setOption方法为 Markdown 转换设置各种选项,格式如下:

 converter.setOption('optionKey', 'value');

因此,例如,我们可以设置一个选项来自动插入和链接指定的 URL,而无需任何标记。

 converter.setOption('simplifiedAutoLink', 'true');

与 Postman 示例一样,如果我们向应用程序传递一个简单的字符串(例如Google home https://www.google.com/ ),如果启用了simplifiedAutoLink自动链接,它将返回以下字符串:

 <p>Google home <a href="https://www.google.com/">https://www.google.com/</a></p>

如果没有该选项,我们将不得不添加标记信息以实现相同的结果:

 Google home <https://www.google.com/>

有许多选项可以修改 Markdown 的处理方式。 完整列表可在 Showdown 网站上找到。

所以现在我们有了一个带有单个端点的 Markdown-to-HTML 转换器。 让我们进一步并添加身份验证以具有应用程序。

第 4 阶段:使用 Passport 添加 API 身份验证

在没有适当身份验证的情况下向外界公开您的应用程序 API 将鼓励用户无限制地查询您的 API 端点。 这将邀请不道德的元素滥用您的 API,并且还会给您的服务器带来未经审核的请求。 为了缓解这种情况,我们必须添加适当的身份验证机制。

我们将使用 Passport 包向我们的应用程序添加身份验证。 就像我们之前遇到的body-parser中间件一样,Passport 是 Node.js 的身份验证中间件。 我们将使用 Passport 的原因是它有多种身份验证机制可供使用(用户名和密码、Facebook、Twitter 等),这使用户可以灵活地选择特定机制。 Passport 中间件可以轻松地放入任何 Express 应用程序中,而无需更改太多代码。

使用 npm 安装包。

 $ npm install passport

我们还将使用local策略(稍后将解释)进行身份验证。 所以也安装它。

 $ npm install passport-local

您还需要为 Passport 使用的 Node.js 添加 JWT(JSON Web Token) 编码和解码模块:

 $ npm install jwt-simple

护照策略

Passport 使用策略的概念来验证请求。 策略是多种方法,可让您对请求进行身份验证,包括验证用户名和密码凭据、使用 OAuth(Facebook 或 Twitter)进行身份验证或使用 OpenID 等简单情况。 在对请求进行身份验证之前,必须配置应用程序使用的策略。

在我们的应用程序中,我们将使用简单的用户名和密码验证方案,因为它易于理解和编码。 目前,Passport 支持 300 多种策略,可在此处找到。

虽然 Passport 的设计看似复杂,但代码中的实现却非常简单。 这是一个示例,展示了我们的/convert端点是如何进行身份验证的。 正如您将看到的,向方法添加身份验证非常简单。

 app.post("/convert", passport.authenticate('local',{ session: false, failWithError: true }), function(req, res, next) { // If this function gets called, authentication was successful. // Also check if no content is sent if(typeof req.body.content == 'undefined' || req.body.content == null) { res.json(["error", "No data found"]); } else { text = req.body.content; html = converter.makeHtml(text); res.json(["markdown", html]); }}, // Return a 'Unauthorized' message back if authentication failed. function(err, req, res, next) { return res.status(401).send({ success: false, message: err }) });

现在,连同要转换的 Markdown 字符串,我们还必须发送用户名和密码。 这将使用我们的应用程序用户名和密码进行检查并进行验证。 由于我们使用本地策略进行身份验证,因此凭据存储在代码本身中。

尽管这听起来像是一场安全噩梦,但对于演示应用程序来说,这已经足够好了。 这也使我们更容易理解我们示例中的身份验证过程。 顺便说一句,一种常用的安全方法是将凭据存储在环境变量中。 尽管如此,很多人可能不同意这种方法,但我觉得这种方法相对安全。

带有身份验证的完整示例如下所示。

 const express = require("express"); const showdown = require('showdown'); const bodyParser = require('body-parser'); const passport = require('passport'); const jwt = require('jwt-simple'); const LocalStrategy = require('passport-local').Strategy; var app = express(); app.use(bodyParser.urlencoded({ extended: true })); app.use(bodyParser.json()); converter = new showdown.Converter(); const ADMIN = 'admin'; const ADMIN_PASSWORD = 'smagazine'; const SECRET = 'secret#4456'; passport.use(new LocalStrategy(function(username, password, done) { if (username === ADMIN && password === ADMIN_PASSWORD) { done(null, jwt.encode({ username }, SECRET)); return; } done(null, false); })); app.get('/', function(req, res){ res.send('Hello World!'); }); app.post('/login', passport.authenticate('local',{ session: false }), function(req, res) { // If this function gets called, authentication was successful. // Send a 'Authenticated' string back. res.send("Authenticated"); }); app.post("/convert", passport.authenticate('local',{ session: false, failWithError: true }), function(req, res, next) { // If this function gets called, authentication was successful. // Also check if no content is sent if(typeof req.body.content == 'undefined' || req.body.content == null) { res.json(["error", "No data found"]); } else { text = req.body.content; html = converter.makeHtml(text); res.json(["markdown", html]); }}, // Return a 'Unauthorized' message back if authentication failed. function(err, req, res, next) { return res.status(401).send({ success: false, message: err }) }); app.listen(3000, function() { console.log("Server running on port 3000"); });

显示添加了身份验证的转换的 Postman 会话如下所示。

使用 Postman 进行最终应用程序测试
使用 Postman 进行最终应用程序测试(大预览)

在这里,我们可以看到我们已经从 Markdown 语法中获得了正确的 HTML 转换字符串。 虽然我们只要求转换一行 Markdown,但是 API 可以转换大量的文本。

这结束了我们使用 Node.js 和 Express 构建 API 端点的简短尝试。 API 构建是一个复杂的主题,在构建 API 时应该注意一些更细微的细微差别,遗憾的是我们没有时间在这里讨论,但可能会在以后的文章中介绍。

从另一个应用程序访问我们的 API

现在我们已经构建了一个 API,我们可以创建一个小的 Node.js 脚本来向您展示如何访问该 API。 对于我们的示例,我们需要安装request npm 包,它提供了一种简单的方式来发出 HTTP 请求。 (您很可能已经安装了这个。)

 $ npm install request --save

下面给出了向我们的 API 发送请求并获取响应的示例代码。 如您所见, request包大大简化了问题。 要转换的降价在textToConvert变量中。

在运行以下脚本之前,请确保我们之前创建的 API 应用程序已经在运行。 在另一个命令窗口中运行以下脚本。

注意我们使用(back-tick)符号来跨越textToConvert变量的多个 JavaScript 行。 这不是单引号。

 var Request = require("request"); // Start of markdown var textToConvert = `Heading ======= ## Sub-heading Paragraphs are separated by a blank line. Two spaces at the end of a line produces a line break. Text attributes _italic_, **bold**, 'monospace'. A [link](https://example.com). Horizontal rule:`; // End of markdown Request.post({ "headers": { "content-type": "application/json" }, "url": "https://localhost:3000/convert", "body": JSON.stringify({ "content": textToConvert, "username": "admin", "password": "smagazine" }) }, function(error, response, body){ // If we got any connection error, bail out. if(error) { return console.log(error); } // Else display the converted text console.dir(JSON.parse(body)); });

当我们向 API 发出 POST 请求时,我们会提供要转换的 Markdown 文本以及凭证。 如果我们提供了错误的凭据,我们将收到一条错误消息。

 { success: false, message: { name: 'AuthenticationError', message: 'Unauthorized', status: 401 } }

对于正确授权的请求,上述示例 Markdown 将转换为以下内容:

 [ 'markdown', `<h1>Heading</h1> <h2>Sub-heading</h2> <p>Paragraphs are separated by a blank line.</p> <p>Two spaces at the end of a line<br /> produces a line break.</p> <p>Text attributes <em>italic</em>, <strong>bold</strong>, 'monospace'. A <a href="https://example.com">link</a>. Horizontal rule:</p>` ]

尽管我们在这里对 Markdown 进行了硬编码,但文本可以来自各种其他来源——文件、Web 表单等。 请求过程保持不变。

请注意,由于我们将请求作为application/json内容类型发送; 我们需要使用 json 对主体进行编码,因此需要调用JSON.stringify函数。 如您所见,测试或 API 应用程序需要一个非常小的示例。

结论

在本文中,我们开始了一个教程,目的是学习如何使用 Node、js 和 Express 框架来构建 API 端点。 我们决定创建一个将 Markdown 语法转换为 HTML 的 API,而不是毫无目的地构建一些虚拟应用程序,从而在有用的上下文中锚定或学习。 在此过程中,我们向 API 端点添加了身份验证,并且我们还看到了使用 Postman 测试应用程序端点的方法。