如何使用 Fastify 構建 REST API?
Fastify 是一個主要用於 JavaScript 後端開發的框架。它是您可以使用的最輕量級的後端框架之一,也是在想要避免使用 Express 和 Hapi 等較重的 Node 框架時首選它的主要原因之一。
自誕生以來,Fastify 已釋出了多個版本。在最新版本中,我們甚至能夠驗證傳入和傳出的請求以及請求引數。毫不奇怪,開發 Fastify 的人員聲稱它是您可以使用的最快的 Node.js 框架,與 Koa、Hapi 和 Express 等其他框架相比。
Fastify 框架之所以廣受歡迎,主要是因為其輕量級的設計。Fastify 與原生框架的不同之處在於,它將所有內容都視為外掛,而在 JavaScript 中,我們將所有內容都視為物件。這反過來又使我們能夠快速將專案的特定功能封裝為外掛,並將其分發到其他專案中。
在本教程中,我們將透過示例學習 Fastify 框架的以下方面
如何建立一個簡單的 Fastify 伺服器
如何在 Fastify 中定義 API 路由
如何為我們的請求新增模式驗證
如何定義鉤子
需求和安裝
使用 Fastify 構建 REST API 的第一步是在專案中建立專案並安裝 Fastify 作為依賴項。
您首先需要以下內容:
最新版本的 Node.js
一個用於測試端點的工具,例如 PostMan 或 cURL。
要驗證 Node 版本,您可以執行下面顯示的命令。
node -v
執行上述命令後,您將在終端上獲得以下**輸出**。
v16.16.0
如果您以某種方式沒有獲得相同的輸出,則需要首先在本地機器上安裝“node”,然後繼續執行下面顯示的命令。
下一步是建立一個空的 Node 專案。如果您還沒有專案,則可以使用下面顯示的命令來初始化它:
npm init -y
在終端中執行上述命令後,將建立一個“package.json”檔案,該檔案將跟蹤所有依賴項以及您可能需要的指令碼。
為了能夠使用 Fastify 框架,我們需要將其匯入為依賴項,我們可以使用下面顯示的命令來實現:
npm i fastify --save
這樣做後,我們應該在“package.json”檔案中的依賴項中看到 Fastify。
現在我們已經準備好進入構建 REST API 的不同階段。
如何建立簡單的 Fastify 伺服器?
要建立簡單的 Fastify 伺服器,我們首先需要建立一個 JS 檔案。假設我們要將檔案命名為“index.js”。要建立同一個檔案,請在終端中執行以下命令:
touch index.js
index.js
現在在您喜歡的程式碼編輯器中開啟您的專案,並在“index.js”檔案中編寫以下程式碼。
// to require the framework
const app = require('fastify')({
logger: true
})
// to declare a single route
app.get('/', function (req, reply) {
reply.send({
Welcome: 'TutorialsPoint'
})
})
// Run the server!
app.listen({ port: 3000 }, (err, address) => {
if (err) {
app.log.error(err)
process.exit(1)
}
app.log.info(`The server is listening on ${address}`)
})
在上面的示例中,我載入了 Fastify 應用程式物件,然後在該物件中,我啟用了日誌記錄。稍後,我聲明瞭一個僅回覆單個響應的單個路由,即“Welcome: TutorialsPoint”。最後一個程式碼塊描述了我們在埠 3000 上偵聽的情況。
要執行上述程式碼,我們需要在終端中執行以下命令。
node index.js
執行上述命令後,我們的伺服器將在以下端點上啟動並執行。
https://:3000
現在要測試它,我們可以使用 PostMan 或 cURL,或者簡單地訪問瀏覽器,因為它是一個簡單的 GET 請求。
我將使用 cURL 命令。請考慮下面顯示的命令:
curl https://:3000
執行上述命令後,您將在終端上獲得以下**輸出**。
{"Welcome":"TutorialsPoint"}
建立簡單的 Fastify 伺服器的第一步已完成,現在讓我們學習如何在 API 中定義路由。
如何在 Fastify 中定義 API 路由?
如果 API 中沒有多個路由,那麼它就沒有意義。在我們的 API 中,我們將有多個路由,因為我們的 REST API 是關於獲取不同書籍及其作者和標題的詳細資訊。
在我們的 REST API 示例中,我們將定義以下路由。
**GET** – 所有書籍位於 /api/books
**GET** – 單本書位於 /api/book/:id
**POST** – 在 /api/books 新增一本書
**PUT** – 在 /api/books/:id 更新一本書
**DELETE** – 在 /api/delete/:id 刪除一本書
在定義路由之前,有必要為這些路由定義控制器。
建立書籍控制器
為了使我們的程式碼模組化和簡潔,讓我們建立一個名為 controller 的目錄,並在該目錄中建立一個名為 books.js 的檔案。
books.js
在 books.js 檔案中,貼上下面顯示的程式碼:
let books = [{
id: 1,
title: 'Maharana Pratap : The Invincible Warrior',
author: 'Rima Hooja'
},
{
id: 2,
title: 'Prithviraj Chauhan - A Light on the Mist in History',
author: 'Virendra Singh Rathore'
},
{
id: 3,
title: 'Rani Laxmibai: Warrior-Queen of Jhansi',
author: 'Pratibha Ranade'
}
]
// Handlers
const getAllBooks = async (req, reply) => {
}
const getBook = async (req, reply) => {
const id = Number(req.params.id)
const book = books.find(book => book.id === id)
return book
}
const addBook = async (req, reply) => {
const id = books.length + 1
const newBook = {
id,
title: req.body.title,
author: req.body.author
}
books.push(newBook)
return newBook
}
const updateBook = async (req, reply) => {
const id = Number(req.params.id)
books = books.map(book => {
if (book.id === id) {
return {
id,
title: req.body.title,
author: req.body.author
}
}
})
return {
id,
title: req.body.title
}
}
const deleteBook = async (req, reply) => {
const id = Number(req.params.id)
books = books.filter(book => book.id !== id)
return {
msg: `Blog with ID ${id} is deleted`
}
}
module.exports = {
getAllBooks,
getBook,
addBook,
updateBook,
deleteBook
}
在上面的程式碼中,定義了不同的處理程式。這些是:
**getAllBooks** – 獲取包含所有書籍的響應
**getBook** – 從書籍 ID 獲取特定書籍。
**addBook** – 將書籍新增到書籍物件的書籍陣列中。
**updateBook** – 更新書籍
**deleteBook** – 從書籍物件陣列中刪除書籍。
需要注意的是,為了節省時間並使控制器保持簡單,我使用物件陣列來儲存書籍資訊,而不是使用資料庫。
下一步是建立路由,以便我們可以在其中使用這些控制器函式。要建立路由,我們將遵循類似的資料夾結構。
讓我們在專案的根目錄中建立一個名為“routes”的目錄。在“routes”目錄中,讓我們建立一個名為“books.js”的檔案。
books.js
現在,將以下程式碼貼上到“books.js”檔案中。
const booksController = require('../controller/books');
const routes = [{
method: 'GET',
url: '/api/books',
handler: booksController.getAllBooks
},
{
method: 'GET',
url: '/api/books/:id',
handler: booksController.getBook
},
{
method: 'POST',
url: '/api/books',
handler: booksController.addBook
},
{
method: 'PUT',
url: '/api/books/:id',
handler: booksController.updateBook
},
{
method: 'DELETE',
url: '/api/books/:id',
handler: booksController.deleteBook
}
]
module.exports = routes
在上面的程式碼中,我們定義了上面提到的所有路由,並且在每個路由中,我都有一個關聯的處理程式來處理該路由。
現在,在我們能夠執行路由並對其進行測試之前,唯一剩下的步驟是首先將這些路由新增到 app 物件中,我們可以在專案根目錄中存在的 index.js 檔案中執行此操作。
index.js
// to require the framework
const app = require('fastify')({
logger: true
})
// to declare a single route
app.get('/', function (req, reply) {
reply.send({
Welcome: 'TutorialsPoint'
})
})
// Register routes to handle blog posts
const bookRoutes = require('./routes/books')
bookRoutes.forEach((route, index) => {
app.route(route)
})
// Run the server!
app.listen(3000, (err, address) => {
if (err) {
app.log.error(err)
process.exit(1)
}
app.log.info(`The server is listening on ${address}`)
})
現在,路由定義已完成。要測試這些路由,我們首先需要使用下面顯示的命令執行應用程式:
index.js
執行上述命令後,我們就可以開啟瀏覽器並點選 url **https://:3000/api/books/1**,這將呼叫控制器/books.js 檔案中的 **getBook** 處理程式函式,並將返回“id = 1”的書籍。
如何為我們的請求新增模式驗證?
在上一節中的程式碼中,我們沒有請求驗證,這意味著我們可以將任何內容傳遞到請求中,它將被視為有效並進入我們的程式碼,但這通常不是我們想要的。
現在,假設我們想要確保傳遞到 getBook 端點的 id 僅為物件型別,而不是任何其他型別,為此,我們可以在控制器中編寫請求驗證。
請考慮下面顯示的程式碼片段:
const getBookValidation = {
params: {
id: { type: 'object' }
},
response: {
200: {
type: 'object',
properties: {
id: { type: 'integer' },
title: { type: 'string' },
author: { type: 'string'}
}
}
}
}
在上面的驗證中,我們確保在 params 中傳遞的 id 欄位為物件型別,而不是任何其他型別。
此外,我們還需要在控制器/books.js 中的 modules.export 中新增函式 getBookValidation。
完成控制器部分後,下一步是將函式新增到路由中,以便當我們收到該路由的請求時,我們的驗證才能生效。為此,我們需要在 getBook 路由內部編寫下面顯示的以下行。
schema: booksController.getBookValidation,
books.js
const booksController = require('../controller/books');
const routes = [{
method: 'GET',
url: '/api/books',
handler: booksController.getAllBooks
},
{
method: 'GET',
url: '/api/books/:id',
schema: booksController.getBookValidation,
handler: booksController.getBook
},
{
method: 'POST',
url: '/api/books',
handler: booksController.addBook
},
{
method: 'PUT',
url: '/api/books/:id',
handler: booksController.updateBook
},
{
method: 'DELETE',
url: '/api/books/:id',
handler: booksController.deleteBook
}
]
module.exports = routes
現在,讓我們測試路由。我們需要執行 index.js 檔案,然後訪問 URL https://:3000/api/books/{1},這樣就能按預期工作。但是,如果你嘗試在 id 引數中傳遞一個物件,比如訪問 URL https://:3000/api/books/1, 那麼你將在瀏覽器中看到以下驗證錯誤。
{
"statusCode": 400,
"error": "Bad Request",
"message": "params/id must be object"
}
如何定義鉤子?
在 Fastify 中,我們可以透過使用 addHook 方法來定義鉤子。
考慮以下示例,我們將定義一個鉤子,列印我們 REST API 中註冊的所有路由。
index.js 新增鉤子
app.addHook('onRoute', (routeOptions) => {
console.log(`Routes that are registered are: ${routeOptions.url}`)
})
以上程式碼片段需要新增到 "index.js" 檔案中,然後當我們執行該檔案時,我們將獲得以下輸出
輸出
Routes that are registered are: / Routes that are registered are: / Routes that are registered are: /api/books Routes that are registered are: /api/books Routes that are registered are: /api/books/:id Routes that are registered are: /api/books/:id Routes that are registered are: /api/books Routes that are registered are: /api/books/:id Routes that are registered are: /api/books/:id
結論
在本教程中,我們學習瞭如何使用 Fastify 建立 REST API。
資料結構
網路
關係型資料庫管理系統
作業系統
Java
iOS
HTML
CSS
Android
Python
C 程式設計
C++
C#
MongoDB
MySQL
Javascript
PHP