使用 Node.JS 和 express 構建 REST API:連接數據庫
在第一個教程“了解 restful API”中,我們了解了 REST 架構是什么、http 請求方法和響應是什么,以及如何了解 RESTful API 端點。在第二個教程“如何設置 Express API 服務器”中,我們學習了如何使用 Node 的內置 http 模塊和 Express 框架構建服務器,以及如何將我們創建的應用程序路由到不同的 URL 端點。
目前,當 API 端點被 GET 請求命中時,我們使用靜態數據以 json 源的形式顯示用戶信息。在本教程中,我們將設置一個 mysql 數據庫來存儲所有數據,從 node.js 應用程序連接到數據庫,并允許 API 使用 GET、POST、PUT,和 delete 方法創建完整的 API。
安裝
到目前為止,我們還沒有使用數據庫來存儲或操作任何數據,因此我們將設置一個。本教程將使用 MySQL,如果您的計算機上已安裝 MySQL,則可以繼續下一步。
如果您沒有安裝 MySQL,您可以下載適用于 macos 和 windows 的 MAMP,它提供免費的本地服務器環境和數據庫。下載完成后,打開程序并單擊啟動服務器啟動 MySQL。
除了設置 MySQL 本身之外,我們還需要 GUI 軟件來查看數據庫和表。對于 Mac,請下載 SequelPro,對于 Windows,請下載 SQLyog。下載并運行 MySQL 后,您可以使用 SequelPro 或 SQLyog 在端口 3306 上使用用戶名 root 和密碼 root 連接到 localhost。
在此處設置完所有內容后,我們就可以繼續為 API 設置數據庫。
設置數據庫
在數據庫查看軟件中,添加一個新數據庫并將其命名為 api。確保 MySQL 正在運行,否則您將無法連接到 localhost。
創建 api 數據庫后,移入該數據庫并運行以下查詢來創建新表。
CREATE TABLE `users` ( `id` int(11) unsigned NOT NULL AUTO_INCREMENT, `name` varchar(30) DEFAULT '', `email` varchar(50) DEFAULT '', PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
此 SQL 查詢將創建 users 表的結構。每個用戶都會有一個自動遞增的 ID、姓名和電子郵件地址。
我們還可以通過運行 INSERT 查詢,使用當前通過靜態 JSON 數組顯示的相同數據填充數據庫。
INSERT INTO users (name, email) VALUES ('Richard Hendricks', 'richard@piedpiper.com'), ('Bertram Gilfoyle', 'gilfoyle@piedpiper.com');
id字段不需要輸入,因為它是自動遞增的。此時,我們已經有了表的結構以及一些可以使用的示例數據。
連接到 MySQL
回到我們的應用程序,我們必須從 Node.js 連接到 MySQL 才能開始處理數據。之前,我們安裝了 mysql npm 模塊,現在我們要使用它。
創建一個名為data的新目錄并創建一個config.js文件。
我們首先需要 data/config.js 中的 mysql 模塊。
const mysql = require('mysql');
讓我們創建一個 config 對象,其中包含主機、用戶、密碼和數據庫。這應該引用我們制作的api數據庫并使用默認的localhost設置。
// Set database connection credentials const config = { host: 'localhost', user: 'root', password: 'root', database: 'api', };
為了提高效率,我們將創建一個 MySQL 池,它允許我們一次使用多個連接,而不必手動打開和關閉多個連接。
// Create a MySQL pool const pool = mysql.createPool(config);
最后,我們將導出 MySQL 池,以便應用程序可以使用它。
// Export the pool module.exports = pool;
您可以在我們的 github 存儲庫中查看完整的數據庫配置文件。
現在我們正在連接到 MySQL 并且設置已完成,我們可以繼續通過 API 與數據庫進行交互。
從 MySQL 獲取 API 數據
目前,我們的 routes.js 文件正在手動創建用戶的 JSON 數組,如下所示。
const users = [{ ...
由于我們不再使用靜態數據,因此我們可以刪除整個數組并將其替換為指向 MySQL 池的鏈接。
// Load the MySQL pool connection const pool = require('../data/config');
以前,/users 路徑的 GET 發送靜態 users 數據。我們更新后的代碼將改為在數據庫中查詢該數據。我們將使用 SQL 查詢 select 來自 users 表,如下所示。
SELECT * FROM users
這是我們新的 /users 獲取路由的樣子,使用 pool.query() 方法。
// Display all users app.get('/users', (request, response) => { pool.query('SELECT * FROM users', (error, result) => { if (error) throw error; response.send(result); }); });
在這里,我們運行 SELECT 查詢,然后通過 /users 端點將結果以 JSON 形式發送到客戶端。如果您重新啟動服務器并導航到 /users 頁面,您將看到與以前相同的數據,但現在它是動態的。
使用 URL 參數
到目前為止,我們的端點都是靜態路徑 – / root 或 /users – 但是當我們只想查看有關特定用戶的數據時該怎么辦?我們需要使用可變端點。
對于我們的用戶,我們可能希望根據每個用戶的唯一 ID 檢索有關每個用戶的信息。為此,我們將使用冒號 (:) 來表示它是一個路由參數。
// Display a single user by ID app.get('/users/:id', (request, response) => { ... }); });
我們可以使用 request.params 屬性檢索此路徑的參數。由于我們的名稱為 id,因此我們將這樣引用它。
const id = request.params.id;
現在,我們將在 SELECT 語句中添加 WHERE 子句,以僅獲取具有指定 id 的結果。
我們將使用 ? 作為占位符以避免 SQL 注入,并將 id 作為參數傳遞,而不是構建一個連接字符串,這會降低安全性。
pool.query('SELECT * FROM users WHERE id = ?', id, (error, result) => { if (error) throw error; response.send(result); });
我們個人用戶資源的完整代碼現在如下所示:
// Display a single user by ID app.get('/users/:id', (request, response) => { const id = request.params.id; pool.query('SELECT * FROM users WHERE id = ?', id, (error, result) => { if (error) throw error; response.send(result); }); });
現在您可以重新啟動服務器并導航到 https://localhost/users/2 以僅查看 Gilfoyle 的信息。如果出現 Cannot GET /users/2 之類的錯誤,則說明您需要重新啟動服務器。
訪問此 URL 應返回一個結果。
[{ id: 2, name: "Bertram Gilfoyle", email: "gilfoyle@piedpiper.com" }]
如果您看到的是這樣的內容,那么恭喜您:您已成功設置動態路由參數!
發送 POST 請求
到目前為止,我們所做的一切都使用了 GET 請求。這些請求是安全的,這意味著它們不會改變服務器的狀態。我們只是查看 JSON 數據。
現在我們將開始通過使用 POST 請求添加新數據來使 API 真正動態化。
我之前在理解 REST 文章中提到,我們不會在 URL 中使用 add 或 delete 等動詞來執行操作。為了向數據庫添加新用戶,我們將 POST 到我們查看它們的同一 URL,但只需為其設置一個單獨的路由。
// Add a new user app.post('/users', (request, response) => { ... });
請注意,我們現在使用 app.post() 而不是 app.get()。
由于我們是創建而不是讀取,因此我們將在此處使用 INSERT 查詢,就像我們在數據庫初始化時所做的那樣。我們將整個 request.body 發送到 SQL 查詢。
pool.query('INSERT INTO users SET ?', request.body, (error, result) => { if (error) throw error;
我們還將指定響應的狀態為 201,它代表 Created。為了獲取最后插入的項目的 id,我們將使用 insertId 屬性。
response.status(201).send(`User added with ID: ${result.insertId}`);
我們的整個 POST 接收代碼將如下所示。
// Add a new user app.post('/users', (request, response) => { pool.query('INSERT INTO users SET ?', request.body, (error, result) => { if (error) throw error; response.status(201).send(`User added with ID: ${result.insertId}`); }); });
現在我們可以通過發送一個 POST 請求了。大多數情況下,當您發送 POST 請求時,您是通過 Web 表單執行的。我們將在本文末尾學習如何進行設置,但發送測試 POST 的最快、最簡單的方法是使用 cURL,使用 -d (–data) 標志。
我們將運行 curl -d,后跟包含所有鍵/值對和請求端點的查詢字符串。
curl -d "name=Dinesh Chugtai&email=dinesh@piedpiper.com" http://localhost:3002/users
發送此請求后,您應該會從服務器收到響應。
User added with ID: 3
如果您導航到 http://localhost/users,您將看到添加到列表中的最新條目。
發送 PUT 請求
POST 對于添加新用戶很有用,但我們希望使用 PUT 來修改現有用戶。 PUT 是冪等的,這意味著您可以多次發送相同的請求,并且只會執行一個操作。這與 POST 不同,因為如果我們多次發送新用戶請求,它會不斷創建新用戶。
對于我們的 API,我們將設置 PUT 以便能夠處理編輯單個用戶,因此這次我們將使用 :id 路由參數。
讓我們創建一個 UPDATE 查詢,并確保它僅適用于帶有 WHERE 子句的請求 ID。我們使用兩個 ? 占位符,我們傳遞的值將按順序排列。
// Update an existing user app.put('/users/:id', (request, response) => { const id = request.params.id; pool.query('UPDATE users SET ? WHERE id = ?', [request.body, id], (error, result) => { if (error) throw error; response.send('User updated successfully.'); }); });
在我們的測試中,我們將編輯用戶 2 并將電子郵件地址從 gilfoyle@piedpiper.com 更新為 bertram@piedpiper.com。我們可以再次使用 cURL,并使用 [-X (–request)] 標志來明確指定我們要通過其發送 PUT 請求。
curl -X PUT -d "name=Bertram Gilfoyle" -d "email=bertram@piedpiper.com" http://localhost:3002/users/2
請確保在發送請求之前重新啟動服務器,否則您將收到 Cannot PUT /users/2 錯誤。
你應該看到這個:
User updated successfully.
現在應該更新 ID 為 2 的用戶數據。
發送刪除請求
我們完成 API 的 CRUD 功能的最后一個任務是選擇從數據庫中刪除用戶。此請求將使用 DELETE SQL 查詢和 WHERE,并且它將刪除由路由參數指定的單個用戶。
// Delete a user app.delete('/users/:id', (request, response) => { const id = request.params.id; pool.query('DELETE FROM users WHERE id = ?', id, (error, result) => { if (error) throw error; response.send('User deleted.'); }); });
我們可以再次使用 -X 和 cURL 來發送刪除。讓我們刪除我們創建的最新用戶。
curl -X DELETE http://localhost:3002/users/3
您將看到成功消息。
User deleted.
導航到 http://localhost:3002,您會看到現在只有兩個用戶。
恭喜!至此,API就完成了。訪問 GitHub 存儲庫以查看 routes.js 的完整代碼。
通過request模塊發送請求
在本文的開頭,我們安裝了四個依賴項,其中之一是 request 模塊。您可以創建一個包含所有數據的新文件并將其發送,而不是使用 cURL 請求。我將創建一個名為 post.js 的文件,該文件將通過 POST 創建一個新用戶。
const request = require('request'); const json = { "name": "Dinesh Chugtai", "email": "dinesh@piedpiper.com", }; request.post({ url: 'http://localhost:3002/users', body: json, json: true, }, function (error, response, body) { console.log(body); });
我們可以在服務器運行時在新的終端窗口中使用 node post.js 來調用它,它與使用 cURL 具有相同的效果。如果 cURL 出現問題,request 模塊很有用,因為我們可以查看錯誤、響應和正文。
通過 Web 表單發送請求
通常,POST 和其他改變服務器狀態的 HTTP 方法是使用 html 表單發送的。在這個非常簡單的示例中,我們可以在任何地方創建一個 index.html 文件,并為姓名和電子郵件地址創建一個字段。表單的操作將指向資源,在本例中為 http//localhost:3002/users,我們將方法指定為 post。
創建index.html并向其中添加以下代碼:
<meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Node.js Express REST API</title>
在瀏覽器中打開此靜態 HTML 文件,填寫該文件,然后在服務器在終端中運行時發送它。您應該會看到 添加了 ID 為 4 的用戶的響應,并且您應該能夠查看新的用戶列表。
結論
在本教程中,我們學習了如何將 Express 服務器連接到 MySQL 數據庫,并設置與路徑和動態路由的 GET、POST、PUT 和 DELETE 方法相對應的路由參數。我們還學習了如何使用 cURL、Node.js request 模塊和 HTML 表單向 API 服務器發送 HTTP 請求。
此時,您應該非常了解 RESTful API 的工作原理,并且您現在可以使用 Express 和 MySQL 在 Node.js 中創建自己的成熟 API!