使用 hapi 创建 restfulAPI
Posted 之梦科技公司
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了使用 hapi 创建 restfulAPI相关的知识,希望对你有一定的参考价值。
搜了国内的文章 使用 `Hapi` 开发 `RESTful API` 的很少很少,一些 社区介绍的部分在新版本中已经不在适用,新版本中有很多变化
## 什么是 `RESTful API`
>RESTful API: REST -- REpresentational State Transfer,英语的直译就是“表现层状态转移”
可以参考下面理解:
- 理解本身的 REST 架构风格:http://www.infoq.com/cn/articles/understanding-restful-style/
- 理解 RESTful 架构:http://www.ruanyifeng.com/blog/2011/09/restful.html
- Restful API 设计指南:http://www.ruanyifeng.com/blog/2014/05/restful_api.html
## Hapi
Hapi 是一个 Node.js 的 web 框架,即一个构建应用程序和服务丰富的框架。
目前 Hapi v17 仅支持 node v8.9.0 及以上版本
- 了解:[Node.js中 hapi-express-restify-koa 性能对比](https://raygun.com/blog/nodejs-vs-hapi-express-restify-koa/)
## Hapi 特性
- 认证和授权:内置的验证和授权方案
- 缓存:提供客户端和服务端缓存,[catbox](https://github.com/hapijs/catbox)
- 路由: 内置路由
- 验证:使用 Joi
- Cookies:提供了配置选项处理 cookie
- 日志:置的日志记录
- 错误处理:[boom](https://github.com/hapijs/boom)
- 进程监控:hapi 插件 [good](https://github.com/hapijs/good)
## 使用 Hapi 的必要条件
- 安装 Node.js v8.9.0 及以上
- 安装 MongoDB
- 熟悉数据库概念和 javascript 的应用知识
## Hapi v17 新的变化
- server.connection 方法移除,现在使用
```
const server = new Hapi.Server({
host: 'localhost',
port: 3000
})
```
- 开启关闭服务方法 完全异步,没有回调
```
try {
await server.start()
}
catch (err) {
console.log(err)
}
try {
await server.stop()
}
catch (err) {
console.log(err)
}
```
- reply() 回调方法移除,response.hold() 和 response.resume() 方法不在可用
```
// 以前
const handler = function (request, reply) {
return reply('ok');
};
// 现在
const handler = function (request, h) {
return 'ok';
};
```
更多使用 h 的示例如下:
```
const handler = (request, h) => {
// return a string
return 'ok'
// return an object and hapi creates JSON out of it
return { name: 'Authentication Library', library: true }
// redirect to 404
return h.redirect('/404')
// return a view
return h.view('index', { name: 'Authentication Library' })
// use the "h" response toolkit to create a response
return h
.response(thisHTML)
.type('text/html')
.header('X-Custom', 'my-value')
.code(201)
}
```
- 三个请求事件类型 request, request-interval, request-error 合并成一个单一的 request 事件
- 触发的方法 像 server.on, request.on, response.on 被替换,使用server.events.on(), request.events.on(), response.events.on() 替代
- 新的请求扩展:
```
server.ext('onPreAuth', (request, h) => { … })
server.ext('onCredentials', (request, h) => { … })
server.ext('onPostAuth', (request, h) => { … }) ]
```
- 在路由定义的时候 替换 config 为 options
```
server.route({
method: 'POST',
path: '/',
options: { … }
})
```
- 插件
目前使用
```
exports.plugin = { register, name, version, multiple, dependencies, once, pkg }
```
-
更多变化详见[GitHub 完整的更新日志](https://github.com/hapijs/hapi/issues/3658)
## 正题:使用 Hapi 构建一个简单的 api
在这个示例中提供 CURD 操作
- Get all demos - GET /demos
- Get one demo - GET /demo/11
- Create a demo - POST /demos
- Edit a demo - PUT /demos/11
- Delete a demo - DELETE /demos/11
A demo 有下面的属性:
- name
- age
### 1 创建项目目录 demo,最后结构如下:
```
demo
├── package.json
├── server.js
├── .gitignore (可选)
└── src
├
├── controller
| └── test.js
└─── models
└── test.js
```
### 2 编写 model
```
src/models/test.js
'use strict';
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const demoModel = new Schema({
name: { type: String, required: true, index: { unique: true } },
age: { type: Number, required: true }
});
module.exports = mongoose.model('Demo', demoModel, 'demos');
```
### 编写 controllers
```
src/controllers/test.js
var Demo = require('../models/test');
/**
* List Demos
*/
exports.list = (req, h) => {
return Demo.find({}).exec().then((demo) => {
return { demos: demo };
}).catch((err) => {
return { err: err };
});
}
/**
* Get Demo by ID
*/
exports.get = (req, h) => {
return Demo.findById(req.params.id).exec().then((demo) => {
if(!demo) return { message: 'Demo not Found' };
return { demos: demo };
}).catch((err) => {
return { err: err };
});
}
/**
* POST a Demo
*/
exports.create = (req, h) => {
const demoData = {
name: req.payload.name,
age: req.payload.age
};
return Demo.create(demoData).then((demo) => {
return { message: "Demo created successfully", demo: demo };
}).catch((err) => {
return { err: err };
});
}
/**
* PUT | Update Demo by ID
*/
exports.update = (req, h) => {
return Demo.findById(req.params.id).exec().then((demo) => {
if (!demo) return { err: 'Demo not found' };
demo.name = req.payload.name;
demo.breed = req.payload.breed;
demo.age = req.payload.age;
demo.image = req.payload.image;
demo.save(dogData);
}).then((data) => {
return { message: "Demo data updated successfully" };
}).catch((err) => {
return { err: err };
});
}
/**
* Delete Demo by ID
*/
exports.remove = (req, h) => {
return Demo.findById(req.params.id).exec(function (err, demo) {
if (err) return { dberror: err };
if (!demo) return { message: 'Demo not found' };
demo.remove(function (err) {
if (err) return { dberror: err };
return { success: true };
});
});
}
```
### 编写 server.js
```
'use strict';
const Hapi = require('hapi');
const mongoose = require('mongoose');
const DemoController = require('./src/controllers/test');
const MongoDBUrl = 'mongodb://localhost:27017/demoapi';
const server = new Hapi.Server({
port: 3000,
host: 'localhost'
});
server.route({
method: 'GET',
path: '/demos',
handler: DemoController.list
});
server.route({
method: 'GET',
path: '/demos/{id}',
handler: DemoController.get
});
server.route({
method: 'POST',
path: '/demos',
handler: DemoController.create
});
server.route({
method: 'PUT',
path: '/demos/{id}',
handler: DemoController.update
});
server.route({
method: 'DELETE',
path: '/demos/{id}',
handler: DemoController.remove
});
(async () => {
try {
await server.start();
// Once started, connect to Mongo through Mongoose
mongoose.connect(MongoDBUrl, {}).then(() => { console.log(`Connected to Mongo server`) }, err => { console.log(err) });
console.log(`Server running at: ${server.info.uri}`);
}
catch (err) {
console.log(err)
}
})();
```
### 测试 API
使用 postman 测试 `http://localhost:3000/demos`
- [demo](https://github.com/fairyly/Hapi-demo)
### 增加授权验证
目前步骤有点多,还需要注册一个平台,暂不做详细说明了
## 参考
- GitHub:https://github.com/hapijs/hapi
- website: https://hapijs.com/
- issue:https://github.com/hapijs/discuss/issues
- [developing-restful-apis-with-hapi v17](https://auth0.com/blog/developing-restful-apis-with-hapijs/)
- https://github.com/hapijs/hapi/issues/3658
## 仅供学习交流
以上是关于使用 hapi 创建 restfulAPI的主要内容,如果未能解决你的问题,请参考以下文章
ionic 后台Api服务, 使用rest-hapi , node.js 创建 RESTful API Service , 附完整源代码
将 Javascript Fetch API 与 Hapi 一起使用
分离前端和后端 - 使用 Vue/Webpack/Hapi 进行持久身份验证
使用 Nodejs (Hapi.js) 和 Prisma 的 Docker 中的 ConnectionError