我计划使用node后端+vue前端的方式构建一个模仿卡片日记UI的PWA应用,并在博客中记录一下。
2000年 HTTP 规范的主要编写者之一Roy Fielding
, 在他的博士论文中提出了 RESTful 的概念。
REST(Representational State Transfer),中文名叫表述性状态转移。它有以下的几种特征:
资源是一个具体的信息,可以使用一个URI去定位它。
资源不规定形式,同一个资源可以请求到它的HTML、XML、JSON等等不同格式。
URI中不包括动词,只包括名词。
动词由四个标准的HTTP方法: GET
(获取资源)、POST
(创建资源)、PUT
(更新资源)、DELETE
(删除资源)提供。
虽然是HTTP的标准方法,但是一些老的浏览器可能并不都支持。
npm i restify -S
创建一个server.js
的文件。
导入restify。
var restify = require("restify");
创建server。
const server = restify.createServer({
name: "restify-app", version: "1.0.0" });
使用组件。
server.use(restify.plugins.acceptParser(server.acceptable));
server.use(restify.plugins.queryParser());
server.use(restify.plugins.bodyParser());
创建一个post请求的handler。
server.post("/api/users", function (req, res, next) {
console.log(`username: ${
req.body.username}`);
console.log(`password: ${
req.body.password}`);
res.send(200, {
msg: "注册成功" });
return next();
});
监听端口。
server.listen(8080, "127.0.0.1", function () {
console.log("%s listening at %s", server.name, server.url);
});
运行node server.js
命令启动服务器。
按照图上的参数配置一下,然后点击 send 。
我们可能会希望我们的命令行中也能输出一些信息。
安装 restify-logger。
npm i restify-logger -S
导入restify-logger。
var logger = require("restify-logger");
注册到restify的响应处理链中。
logger.format("request-format", ":method :url :status");
server.use(logger("request-format"));
再次执行server.js和postman。
这次我们看到我们的命令行中多了一些信息。(这里发了三次POST请求)
restify-app listening at http://127.0.0.1:8080
POST /api/users 200
POST /api/users 200
POST /api/users 200
我们肯定还希望能把数据保存下来,所以要使用数据库。
关于使用关系型数据库还是非关系型数据库,在这样的小项目下,还是建议使用非关系型的数据库,主要是为了简化一些前期的设计工作,后期更改数据库也很容易。这里选择MongoDB。
进入mongo shell,创建一个名为restify的数据库。
use restify
非关系型数据库虽然方便,但是如果使用的过程中不注意,可能会让数据库的字段变得非常混乱。
使用 mongoose 可以有效防止这种情况的发生。 mongoose可以有效约束mongodb的类型和提供安全可靠的数据库操作接口。
安装 mongoose。
var mongoose = require("mongoose");
连接数据库。
var uri = `mongodb://localhost:27017/restify`;
var options = {
useCreateIndex: true,
useNewUrlParser: true,
useUnifiedTopology: true,
};
var db = mongoose.connect(uri, options);
创建 models/UserModel.js
文件。
schema是一种类型的约束,可以防止mongodb因混乱的类型管理失去控制。我在注释里解释了部分约束的意思。
model对应了mongodb的一个集合(collection)。值得一提的是,mongoose会把你定义的model名转换成小写,然后加上一个s,比如你定义了一个User的model,在mongodb的数据库里,它会变成users集合。
var mongoose = require("mongoose");
var UserSchema = mongoose.Schema({
username: {
type: String, //类型为String
index: true, //该字段作为index
unique: true, //值必须是唯一的
lowercase: true, //自动全部转换成小写字母
trim: true, //自动去除两边的空格
},
password: String,
userType: {
type: String,
enum: ["user", "vip"], //值只能在两者之间选择一个
default: "user", //默认值(无需声明就会自动添加)
},
avatarPath: String,
});
module.exports = mongoose.model("User", UserSchema);
重写server.js中POST请求的内容。
新建一个model实例,其实就是新建了一个mongodb的文档(document)。
使用model实例的save方法,可以保存一条记录。
server.post("/api/users", function (req, res, next) {
db.then(
() => {
var UserModel = require("./models/UserModel");
var newUser = new UserModel({
username: req.body.username,
password: req.body.password,
});
newUser.save().then(
() => {
res.send(201, {
msg: "注册成功" });
console.log(`新用户注册: ${
req.body.username}`);
},
(err) => {
console.error(err.toString());
res.send(409, {
msg: "注册失败" });
console.log(`用户 ${
req.body.username} 注册失败`);
}
);
},
(err) => {
console.error(err.toString());
res.send(500, {
msg: "数据库连接错误" });
}
);
return next();
});
重新运行server.js和postman。
restify-app listening at http://127.0.0.1:8080
新用户注册: root
POST /api/users 201
MongoError: E11000 duplicate key error collection: carddaily.users index: username_1 dup key: { username: "root" }
用户 root 注册失败
POST /api/users 409
可以看到第一次注册的时候,数据库中还没数据,所以可以注册成功,而第二次注册因为被用户已经被注册过了,所以注册失败了。
tree -L 2
.
├── server.js
├── models
│ └── UserModel.js
├── node_modules
└── //此处省略
├── package-lock.json
├── package.json
{
"name": "restify-demo",
"version": "1.0.0",
"description": "",
"main": "server.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "Jaycee Chow",
"license": "MIT",
"dependencies": {
"mongoose": "^5.9.15",
"restify": "^8.5.1",
"restify-logger": "^2.0.1"
}
}
var mongoose = require("mongoose");
var restify = require("restify");
var logger = require("restify-logger");
//创建一个 restify server
const server = restify.createServer({
name: "restify-app", version: "1.0.0" });
//使用组件
server.use(restify.plugins.acceptParser(server.acceptable));
server.use(restify.plugins.queryParser());
server.use(restify.plugins.bodyParser());
logger.format("request-format", ":method :url :status");
server.use(logger("request-format"));
//连接 mongodb 数据库
var uri = `mongodb://localhost:27017/restify`;
var options = {
useCreateIndex: true,
useNewUrlParser: true,
useUnifiedTopology: true,
};
var db = mongoose.connect(uri, options);
//用户注册
server.post("/api/users", function (req, res, next) {
db.then(
() => {
var UserModel = require("./models/UserModel");
var newUser = new UserModel({
username: req.body.username,
password: req.body.password,
});
newUser.save().then(
() => {
res.send(201, {
msg: "注册成功" });
console.log(`新用户注册: ${
req.body.username}`);
},
(err) => {
console.error(err.toString());
res.send(409, {
msg: "注册失败" });
console.log(`用户 ${
req.body.username} 注册失败`);
}
);
},
(err) => {
console.error(err.toString());
res.send(500, {
msg: "数据库连接错误" });
}
);
return next();
});
server.listen(8080, "127.0.0.1", function () {
console.log("%s listening at %s", server.name, server.url);
});
var mongoose = require("mongoose");
var UserSchema = mongoose.Schema({
username: {
type: String,
index: true,
unique: true,
lowercase: true,
trim: true,
},
password: String,
userType: {
type: String,
enum: ["user", "vip"],
default: "user",
},
avatarPath: String,
});
module.exports = mongoose.model("User", UserSchema);
网站 | 地址 |
---|---|
restify官方文档 | http://restify.com/docs/home/ |
IBM restify教程 | https://www.ibm.com/developerworks/cn/web/wa-lo-use-restify-develop-rest-api/index.html |
mongoose中文网 | http://mongoosejs.net/docs/guide.html |