在现代的 Web 应用中,使用 RESTful 风格的 API 接口已经成为了一种标准。但是,在实现 RESTful 风格的 API 接口时,需要考虑到很多细节问题,包括路由、参数验证、错误处理等等,这对于开发人员来说是一项很大的工程。
Hapi 是一种流行的 Node.js Web 框架,它提供了丰富的功能和插件来简化 Web 应用的开发。但是,为了满足 RESTful 风格的 API 接口的需求,我们还需要对 Hapi 进行二次封装。在本文中,我们将介绍如何使用 Hapi 进行二次封装,实现 RESTful 风格的 API 接口。
为什么需要二次封装
如前所述,Hapi 提供了很多功能和插件来简化 Web 应用的开发。但是,在实现 RESTful 风格的 API 接口时,我们需要处理的问题比较多,包括路由、参数验证、错误处理等等,这些细节问题需要耗费大量的时间和精力。
此外,如果我们要实现多个 RESTful 风格的 API 接口,每个接口都需要进行重复的工作,这也是一种浪费。
因此,使用 Hapi 进行二次封装可以大大简化我们的工作,减少错误发生的可能性,同时也可以提高开发效率。
二次封装的实现
接下来,我们将介绍如何使用 Hapi 进行二次封装,实现 RESTful 风格的 API 接口。
首先,我们需要定义一些规则,以便我们可以快速而准确地生成 RESTful 风格的 API 接口。
基本规则
在 RESTful 风格的 API 接口中,我们通常会使用 HTTP 动词来定义操作。常见的 HTTP 动词有 GET、POST、PUT、DELETE 等等。因此,我们需要定义一个操作与 HTTP 动词对应的映射关系。
const methodsMap = { 'GET': 'get', 'POST': 'post', 'PUT': 'put', 'DELETE': 'delete', };
为了方便路由的处理,我们还需要定义一个路由的基本格式。
const routeFormat = { method: '', path: '', handler: ()=>{ // todo }, options: { auth: false, // ... }, };
在这个格式中,method
表示 HTTP 动词,path
表示路由路径,handler
表示路由处理程序,options
表示其他选项。
接下来,我们需要定义一些函数来生成各种类型的路由。
生成列表路由
RESTful 风格的 API 接口中,通常会有一种类型的路由是用来获取列表数据的。例如,我们可以通过 GET 请求获取用户列表:
GET /users
因此,我们需要定义一个函数来生成列表路由。
function getListRoute(url, handler) { return { ...routeFormat, method: methodsMap.GET, path: url, handler: (request, h) => handler(request.query), }; }
在这个函数中,url
表示路由路径,handler
表示用于处理请求的函数。在处理函数中,我们可以通过 request.query
参数来获取查询参数,然后进行相应的处理。
生成详情路由
另一种常见的路由类型是详情路由,用于获取单个资源的详细信息。例如,我们可以通过 GET 请求获取某个用户的详细信息:
GET /users/:id
因此,我们需要定义一个函数来生成详情路由。
function getDetailRoute(url, handler) { return { ...routeFormat, method: methodsMap.GET, path: url, handler: (request, h) => handler(request.params.id), }; }
在这个函数中,url
表示路由路径,handler
表示用于处理请求的函数。在处理函数中,我们可以通过 request.params.id
参数来获取查询参数,然后进行相应的处理。
生成创建路由
创建路由用于新建资源。例如,我们可以通过 POST 请求创建一个新的用户:
POST /users
因此,我们需要定义一个函数来生成创建路由。
function getCreateRoute(url, handler) { return { ...routeFormat, method: methodsMap.POST, path: url, handler: async (request, h) => handler(request.payload), }; }
在这个函数中,url
表示路由路径,handler
表示用于处理请求的函数。在处理函数中,我们可以通过 request.payload
参数来获取提交的数据,然后进行相应的处理。
生成更新路由
更新路由用于更新资源。例如,我们可以通过 PUT 请求更新某个用户的信息:
PUT /users/:id
因此,我们需要定义一个函数来生成更新路由。
function getUpdateRoute(url, handler) { return { ...routeFormat, method: methodsMap.PUT, path: url, handler: async (request, h) => handler(request.params.id, request.payload), }; }
在这个函数中,url
表示路由路径,handler
表示用于处理请求的函数。在处理函数中,我们可以通过 request.params.id
参数来获取更新的对象id和通过 request.payload
参数来获取提交的更新数据,然后进行相应的处理。
生成删除路由
删除路由用于删除资源。例如,我们可以通过 DELETE 请求删除某个用户的信息:
DELETE /users/:id
因此,我们需要定义一个函数来生成删除路由。
function getDeleteRoute(url, handler) { return { ...routeFormat, method: methodsMap.DELETE, path: url, handler: async (request, h) => handler(request.params.id), }; }
在这个函数中,url
表示路由路径,handler
表示用于处理请求的函数。在处理函数中,我们可以通过 request.params.id
参数来获取删除对象id,然后进行相应的处理。
生成路由表
有了上面的路由生成函数,我们可以很容易地生成各种类型的路由了。在实际应用中,我们可能需要定义多个路由表,用于不同的API接口
const userRoutes = [ getListRoute('/users', userListHandler), // 获取列表 getDetailRoute('/users/{id}', userDetailHandler), // 获取详情 getCreateRoute('/users', createUserHandler), // 创建资源 getUpdateRoute('/users/{id}', updateUserHandler), // 更新资源 getDeleteRoute('/users/{id}', deleteUserHandler), // 删除资源 ]; const orderRoutes = [ getListRoute('/orders', orderListHandler), // 获取列表 getDetailRoute('/orders/{id}', orderDetailHandler), // 获取详情 getCreateRoute('/orders', createOrderHandler), // 创建资源 getUpdateRoute('/orders/{id}', updateOrderHandler), // 更新资源 getDeleteRoute('/orders/{id}', deleteOrderHandler), // 删除资源 ];
注册路由
有了路由表,我们还需要将路由表注册到 Hapi 中。
const server = Hapi.server({ port: 3000, host: 'localhost', }); await server.register([ { plugin: require('hapi-auth-jwt2') }, { plugin: require('hapi-pagination') }, { plugin: require('hapi-cors') }, { plugin: require('inert') }, { plugin: require('vision') }, { plugin: require('hapi-swagger') }, ]); // 注册路由 server.route([...userRoutes, ...orderRoutes]); // 启动服务 await server.start();
在上面的代码中,server.route
函数将路由表注册到 Hapi 中。在实际应用中,我们可能需要注册多个路由表,具体视情况而定。
总结
使用 Hapi 进行二次封装可以大大简化我们的工作,同时还可以提高开发效率。在本文中,我们介绍了如何使用 Hapi 进行二次封装,实现 RESTful 风格的 API 接口,包括路由、参数验证、错误处理等细节问题。希望对您有所帮助。
完整示例代码:
const Hapi = require('@hapi/hapi'); // HTTP 动词与操作名称的映射关系 const methodsMap = { 'GET': 'get', 'POST': 'post', 'PUT': 'put', 'DELETE': 'delete', }; // 路由格式 const routeFormat = { method: '', path: '', handler: ()=>{ // todo }, options: { auth: false, // ... }, }; // 获取列表路由 function getListRoute(url, handler) { return { ...routeFormat, method: methodsMap.GET, path: url, handler: (request, h) => handler(request.query), }; } // 获取详情路由 function getDetailRoute(url, handler) { return { ...routeFormat, method: methodsMap.GET, path: url, handler: (request, h) => handler(request.params.id), }; } // 创建资源路由 function getCreateRoute(url, handler) { return { ...routeFormat, method: methodsMap.POST, path: url, handler: async (request, h) => handler(request.payload), }; } // 更新资源路由 function getUpdateRoute(url, handler) { return { ...routeFormat, method: methodsMap.PUT, path: url, handler: async (request, h) => handler(request.params.id, request.payload), }; } // 删除资源路由 function getDeleteRoute(url, handler) { return { ...routeFormat, method: methodsMap.DELETE, path: url, handler: async (request, h) => handler(request.params.id), }; } // 定义路由表 const userRoutes = [ getListRoute('/users', userListHandler), // 获取列表 getDetailRoute('/users/{id}', userDetailHandler), // 获取详情 getCreateRoute('/users', createUserHandler), // 创建资源 getUpdateRoute('/users/{id}', updateUserHandler), // 更新资源 getDeleteRoute('/users/{id}', deleteUserHandler), // 删除资源 ]; const orderRoutes = [ getListRoute('/orders', orderListHandler), // 获取列表 getDetailRoute('/orders/{id}', orderDetailHandler), // 获取详情 getCreateRoute('/orders', createOrderHandler), // 创建资源 getUpdateRoute('/orders/{id}', updateOrderHandler), // 更新资源 getDeleteRoute('/orders/{id}', deleteOrderHandler), // 删除资源 ]; // 创建 Hapi 服务并注册插件 const server = Hapi.server({ port: 3000, host: 'localhost', }); await server.register([ { plugin: require('hapi-auth-jwt2') }, { plugin: require('hapi-pagination') }, { plugin: require('hapi-cors') }, { plugin: require('inert') }, { plugin: require('vision') }, { plugin: require('hapi-swagger') }, ]); // 注册路由 server.route([...userRoutes, ...orderRoutes]); // 启动服务 await server.start();
来源:JavaScript中文网 ,转载请注明来源 本文地址:https://www.javascriptcn.com/post/65a628caadd4f0e0ffed9340