很多人都在关注Deno,我也不例外,毕竟是nodejs之父的又一大作。这篇文章将使用Deno写一个简单的TodoList的RestApi,尝尝鲜。

Deno是什么?

Deno是一个用Rust写的基于 V8 引擎的一个Javascript / Typescript 运行环境。

Deno Features

  • Use TypeScript or JavaScript
  • ES Modules
  • Secure by Default
  • Top Level / First Class Await
  • De-centralized Packages
  • Built In Testing
  • Standard Library
  • Browser Compatible API
  • Modern JS

项目编写

目录结构

  • controller
    • tasks.ts 定义控制器
  • router.ts 定义项目路由
  • server.ts 项目主入口,创建http服务器
  • tasks.http 测试api
  • types.ts 定义接口

由于只是尝尝鲜,数据采用的是静态的,没有连接数据库,就没有写service了。

主要逻辑

Server.ts

1
2
3
4
5
6
7
8
9
10
11
12
import { Application } from 'https://deno.land/x/oak/mod.ts'
import router from './router.ts'
const port = 5000

const app = new Application()

app.use(router.routes())
app.use(router.allowedMethods())

console.log(`Server running on port ${port}`)

await app.listen({ port })

router.ts

1
2
3
4
5
6
7
8
9
10
11
12
import { Router } from 'https://deno.land/x/oak/mod.ts'
import { getTasks, getTask, updateTask, deleteTask, addTask } from './controller/tasks.ts'
const router = new Router()


router.get('/api/v1/tasks', getTasks)
.get('/api/v1/tasks/:id', getTask)
.post('/api/v1/tasks', addTask)
.put('/api/v1/tasks/:id', updateTask)
.delete('/api/v1/tasks/:id', deleteTask)

export default router

/contraller/tasks.ts

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
import { v4 } from 'https://deno.land/std/uuid/mod.ts'
import { Task } from '../types.ts'

let tasks: Task[] = [
{
id: "1",
name: "学习Deno",
description: "使用Deno写个小案例",
completed: false
},
{
id: "2",
name: "学习Nodejs",
description: "使用Nodejs写个小案例",
completed: false
},
{
id: "3",
name: "学习Vue",
description: "使用Vue写个小案例",
completed: false
},
{
id: "4",
name: "学习React",
description: "使用React写个小案例",
completed: false
},
{
id: "5",
name: "学习Angular",
description: "使用Angular写个小案例",
completed: false
}
]

/** @desc 获取所有的待办事项
* @route GET /api/v1/tasks
*/
const getTasks = ({ response }: { response: any }) => {
response.body = {
success: true,
data: tasks
}
}

/** @desc 通过id获取代办事项
* @route GET /api/v1/tasks/:id
*/
const getTask = ({ params, response }: { params: {id: string} ,response: any }) => {
const task: Task | undefined = tasks.find(t => t.id === params.id)
if(task) {
response.status = 200
response.body = {
success: true,
data: task
}
} else {
response.status = 404
response.body = {
success: false,
message: 'No task found'
}
}
}

/** @desc 增加待办事项
* @route POST /api/v1/tasks
*/
const addTask = async ({ request, response }: { request: any,response: any }) => {
const body = await request.body()
if(!request.hasBody){
response.status = 400
response.body = {
success: false,
message: 'No data'
}
} else {
const task: Task = body.value
task.id = v4.generate()
tasks.push(task)
response.status = 201
response.body = {
success: true,
data: task
}
}
}

/** @desc 更新待办事项
* @route PUT /api/v1/tasks/:id
*/
const updateTask = async ({ params, request, response }: { request: any, params: {id: string}, response: any }) => {
const index: number = tasks.findIndex(t => t.id === params.id)
if(index !== -1) {
const body = await request.body()

const updateData: {name?: string, description?: string, completed?: boolean } = body.value
tasks[index] = {...tasks[index], ...updateData}

response.status = 200
response.body = {
success: true,
data: tasks[index]
}
} else {
response.status = 404
response.body = {
success: false,
message: 'No task found'
}
}
}

/** @desc 通过id删除待办事项
* @route DELETE /api/v1/tasks/:id
*/
const deleteTask = ({ params, response }: { params: {id: string},response: any }) => {
const index: number = tasks.findIndex(t => t.id === params.id)
if(index !== -1) {
tasks.splice(index,1)
response.status = 200
response.body = {
success: true,
message: 'Task Removed'
}
} else {
response.status = 404
response.body = {
success: false,
message: 'No task found'
}
}
}

export { getTasks, getTask, addTask, updateTask, deleteTask }

可以看到较express、koa的写法差别都不是特别大。

API测试

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
@host = http://localhost:5000/api/v1
### 获取所有代办事项
GET {{host}}/tasks HTTP/1.1
### 通过id获取代办事项
GET {{host}}/tasks/1 HTTP/1.1
### 增加代办事项
POST {{host}}/tasks HTTP/1.1
Content-Type: application/json

{
"name": "学习Electron",
"description": "使用Electron写个小案例",
"completed": false
}
### 更新代办事项
PUT {{host}}/tasks/1 HTTP/1.1
Content-Type: application/json

{
"name": "测试",
"description": "测试更新接口",
"completed": true
}
### 删除代办事项
DELETE {{host}}/tasks/1 HTTP/1.1

总结

我们不断优化Deno的http服务器的性能。对于’hello world’的例子,DenoHTTP服务器每秒处理约25,000个请求,最大延迟1.3ms。Node服务器每秒处理34,000个请求,最大延迟介于2~300ms之间。

这段话摘自Deno官网。按照官网的说法deno的http性能会比node好很多,不过就目前来说还是很难取代node的。node的生态太丰富了。就我个人的看法来说,我比较喜欢deno的地方在于:

  • 内置了TypeScript编译器,写起来很爽啊~~
  • 取消掉了package.json管理依赖的模式,不再依靠npm。(npm最让我头痛的一点在于包的下载时不时就会出错,每写一个项目就有一个node_modules)
  • 有官方的标准库,可以根据官方的标准库进行开发自己的东西。标准库始终跟着版本走,不会出现第三方库用爱发电,发着发着就不更新了的情况,这点我觉得很好。而且第三方开发的库,始终有些隐患。
  • http服务器性能高!!!

总之可以期待一下Deno,后面生态丰富了可以尝试去转Deno。

欢迎来一起交流👏。