如何使用Fastify构建REST API

如何使用Fastify构建REST API

Fastify是一个主要用于JavaScript后端开发的框架。它是最轻量级的后端框架之一,如果你想避免使用像Express和Hapi这样更重量级的Node框架,那么Fastify是首选。

自其诞生以来,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 服务器,我们首先需要创建一个 JavaScript 文件。假设我们想将文件命名为 “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应用对象,并在该对象中启用了日志记录。接着,我声明了一个单一路由,响应的内容是”欢迎:TutorialsPoint”。最后一个代码块展示了我们监听端口3000的情况。

为了运行以上代码,我们需要在终端中运行以下命令。

node index.js

一旦我们运行上述命令,服务器将在以下端点上运行。

http://localhost:3000

现在,为了测试它,我们可以使用PostMan或cURL,或者只需访问浏览器,因为它是一个简单的GET请求。

我将使用cURL命令。考虑下面显示的命令:

curl http://localhost: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中删除一本书

在定义路由之前,有必要定义这些路由的控制器。

创建Books控制器

为了使我们的代码模块化和清晰,让我们创建一个名为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

一旦我们运行了上面的命令,我们就可以打开浏览器并访问以下网址: http://localhost:3000/api/books/1 这将调用我们控制器中的 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字段是对象类型,而不是其他任何类型。

同时,我们还需要在controller/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文件,然后我们需要访问以下网址, http://localhost:3000/api/books/{1} 一旦我们这样做,它将按预期工作。但是如果你尝试在id参数中传递一个对象,例如,如果你访问以下网址 http://localhost:3000/api/books/1 那么你将在浏览器中得到以下验证错误。

{
   "statusCode": 400,
   "error": "Bad Request",
   "message": "params/id must be object"
}

如何定义Hooks

我们可以通过使用addHook方法在Fastify中定义Hooks。

考虑下面的示例,我们将定义一个Hook,该Hook将打印出我们的REST API中注册的所有路由。

index.js addHook

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。

Camera课程

Python教程

Java教程

Web教程

数据库教程

图形图像教程

办公软件教程

Linux教程

计算机教程

大数据教程

开发工具教程