Node.js是一个基于 Chrome V8 引擎的 JavaScript 运行环境。Node.js 使用了一个事件驱动、非阻塞式 I/O 的模型,使其轻量又高效。Express是一个保持最小规模的灵活的 Node.js Web应用程序开发框架,为Web和移动应用程序提供一组强大的功能。使用Node.js和Express可以快速的实现一个RESTful API服务。

什么是RESTful API

RESTful API是一种遵循 REST(Representational State Transfer,表现层状态转移)架构风格的网络 API 设计,它使用HTTP协议定义的请求方法(GET、POST、PUT、DELETE)来定义对资源的操作。
RESTful API是一种非常流行的API设计风格,它具有以下特点:

  1. 使用HTTP协议定义对资源的操作
  2. 使用HTTP协议定义的请求方法(GET、POST、PUT、DELETE)来定义对资源的操作
  3. 使用JSON作为数据交换格式
  4. 使用URL来定义资源
  5. 使用HTTP状态码来表示操作结果

如何使用nodejs和express实现一个RESTful API

在MySQL中创建一个数据库和表

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
CREATE DATABASE `app`;

CREATE TABLE if not exists user (
id BIGINT NOT NULL,
account varchar(100) DEFAULT '' NOT NULL,
password varchar(200) DEFAULT '' NOT NULL,
secret_key varchar(100) DEFAULT '' NOT NULL,
nick_name varchar(100) DEFAULT '' NOT NULL,
avatar varchar(300) DEFAULT '' NOT NULL,
email varchar(100) DEFAULT '' NOT NULL,
email_verified tinyint(1) DEFAULT 0 NOT NULL,
phone_number varchar(100) DEFAULT '' NOT NULL,
phone_numbert_verified tinyint(1) DEFAULT 0 NOT NULL,
creator_id BIGINT DEFAULT 0 NOT NULL,
creation_time timestamp DEFAULT CURRENT_TIMESTAMP NOT NULL,
last_modifier_id BIGINT DEFAULT 0 NOT NULL,
last_modification_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL,
CONSTRAINT pk_user PRIMARY KEY (id),
CONSTRAINT unique_user_email UNIQUE KEY (email),
CONSTRAINT unique_user_phone UNIQUE KEY (phone_number)
)
ENGINE=InnoDB
DEFAULT CHARSET=utf8mb4
COLLATE=utf8mb4_unicode_ci

从GitHub下载项目模板一个基于nodejs、TypeScript和express的web模板

创建User实体类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
class User {
public id!: bigint;
public account: string;
public password: string;
public secret_key: string
public nick_name: string;
public avatar: string;
public email: string;
public phone_number: string;
public creator_id: bigint;
public creation_time!: Date;
public last_modifier_id!: bigint;
public last_modification_time!: Date;

constructor(account: string, password: string, secret_key: string, nick_name: string, avatar: string, email: string,
phone_number: string, creator_id: bigint) {
this.account = account;
this.password = password;
this.secret_key = secret_key;
this.nick_name = nick_name;
this.avatar = avatar;
this.email = email;
this.phone_number = phone_number;
this.creator_id = creator_id;
}
}

export default User;

创建UserService类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
import User from "../models/User";
import { connection } from '../utils/db';
import PasswordSecurity from '../utils/password-security';
import { SnowflakeId } from "../utils/snowflakeid";

class UserService {

public async create(user: User): Promise<User> {
return new Promise<User>((resolve, reject) => {
try {
const passwordSecurity = new PasswordSecurity();
const secret_key = passwordSecurity.createSalt();
user.id = SnowflakeId.newId();
user.secret_key = secret_key;
user.password = passwordSecurity.createHash(user.password, secret_key);
user.creation_time = new Date();
user.last_modifier_id = user.creator_id;
user.last_modification_time = new Date();
connection.query('insert into user (id, account, password, secret_key, nick_name, avatar, email, phone_number, creator_id, creation_time, last_modifier_id, last_modification_time)'
+ 'values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)',
[user.id, user.account, user.password, user.secret_key, user.nick_name, user.avatar, user.email, user.phone_number, user.creator_id, user.creation_time, user.last_modifier_id, user.last_modification_time],
function (error: any, result: any) {
if (error) {
console.log('Error: ' + error.message);
reject(error);
} else {
resolve(user);
}
});
} catch (e) {
reject(e)
}
})
}

public async getByAccount(account: string): Promise<User> {
return new Promise<User>((resolve, reject) => {
try {
connection.query('select * from user where account = ?', [account], function (error: any, result: any) {
if (error) {
console.log('Error: ' + error.message);
reject(error);
} else {
resolve(result[0]);
}
});
} catch (e) {
reject(e)
}
})
}

public async getById(id: number): Promise<User> {
return new Promise<User>((resolve, reject) => {
try {
connection.query('select * from user where id = ?', [id], function (error: any, result: any) {
if (error) {
console.log('Error: ' + error.message);
reject(error);
} else {
resolve(result[0]);
}
})
} catch (e) {
reject(e)
}
});
}

public async getByEmail(email: string): Promise<User> {
return new Promise<User>((resolve, reject) => {
try {
connection.query('select * from user where email = ?', [email], function (error: any, result: any) {
if (error) {
console.log('Error: ' + error.message);
reject(error);
} else {
resolve(result[0]);
}
})
} catch (e) {
reject(e)
}
})
}

public async getByPhoneNumber(phone_number: string): Promise<User> {
return new Promise<User>((resolve, reject) => {
try {
connection.query('select * from user where phone_number = ?', [phone_number], function (error: any, result: any) {
if (error) {
console.log('Error: ' + error.message);
reject(error);
} else {
resolve(result[0]);
}
})
} catch (e) {
reject(e)
}
})
}

public async update(user: User): Promise<User> {
return new Promise((resolve, reject) => {
try {
connection.query('update user set account = ?, password = ?, secret_key = ?, name = ?, avatar = ?, email = ?, phone_number = ?, creator_id = ?, creation_time = ?, last_modifier_id = ?, last_modification_time = ? where id = ?',
[user.account, user.password, user.secret_key, user.nick_name, user.avatar, user.email, user.phone_number, user.last_modifier_id, user.last_modification_time, user.id], function (error, result) {
if (error) {
console.log('Error: ' + error.message);
reject(error)
} else {
resolve(user);
}
});
} catch (e) {
reject(e);
}
});
}

public async delete(id: number): Promise<void> {
return new Promise<void>((resolve, reject) => {
try {
connection.query('delete from user where id = ?', [id], function (error, result) {
if (error) {
console.log('Error: ' + error.message);
reject(error)
} else {
resolve();
}
});
} catch (e) {
reject(e);
}
})
}

}

export default new UserService();

创建UserController

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
import { Request, Response } from 'express';
import User from '../models/User';
import UserService from '../services/UserService';
import { success, error } from '../utils/json-result'
import { Get, Post, Put, Delete, Controller} from '../utils/routing-controllers'

@Controller('/api/user')
class UserController {

constructor() { }

@Post('/')
public async create(req: Request, res: Response): Promise<any> {
try {
var user = new User(
req.body.name,
req.body.password,
req.body.secret_key,
req.body.nick_name,
req.body.avatar == null || req.body.avatar == undefined ? '' : req.body.avatar,
req.body.email,
req.body.phone_number,
req.body.creator_id == null || req.body.creator_id == undefined ? 0 : req.body.creator_id);

if (user.account == null || user.account == '') {
error(res, "用户名不能为空");
return;
}
if (user.password == null || user.password == '') {
error(res, "密码不能为空");
return;
}
if (user.email == null || user.email == '') {
error(res, "邮箱不能为空");
return;
}
if (user.phone_number == null || user.phone_number == '') {
error(res, "手机号不能为空");
return;
}
var existingUser = await UserService.getByAccount(user.account);
if (existingUser != null) {
error(res, "用户已存在");
return
}
existingUser = await UserService.getByEmail(user.email);
if (existingUser != null) {
error(res, "邮箱已存在");
return;
}
existingUser = await UserService.getByPhoneNumber(user.phone_number);
if (existingUser != null) {
error(res, "手机号已存在");
return;
}
UserService.create(user).then(result => {
success(res, result);
});
} catch (err: any) {
console.error(err);
error(res, err.message);
}
}

@Get('/')
public get(req: Request, res: Response): any {
res.send('users');
}

@Put('/')
public update(req: Request, res: Response): any {
res.send('update user');
// 处理更新用户的请求
}

@Delete('/')
public delete(req: Request, res: Response): void {
res.send('delete user');
// 处理删除用户的请求
}
}

export default UserController;

启动服务

1
npm start

测试

1
curl -X POST -H "Content-Type: application/json" -d '{"account":"admin","password":"123456","secret_key":"123456","nick_name":"admin","email":"[email protected]","phone_number":"13888888888"}' http://localhost:3000/api/user

返回结果

1
{"account":"admin","password":"43ad945a38257858c962d7e703bf090db019e61efda2edd34a48480e8da51b4a12c1f1d04ed06feced130bfa30e76e41f08762ee7e04fe038b2ecd4b90d43c94","secret_key":"b4689647434328c65a18cb7707b74734","nick_name":"admin","avatar":"","email":"[email protected]","phone_number":"13888888888","creator_id":0,"id":"11087864288776192","creation_time":"2024-06-02T14:19:12.888Z","last_modifier_id":0,"last_modification_time":"2024-06-02T14:19:12.888Z"}