構建 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 測試應用程序端點的方法。