实战项目案例:编写任务管理系统后端API
下面编写一个任务管理系统的后端 API。任务管理系统的界面如图22-3所示。它拥有添加任务、查看任务、设置任务为完成状态以及删除任务的功能。

编写的后端 API 将供下一章将要介绍的前端界面使用。在正式编写之前,先在项目目录下执行以下安装命令,安装 Express
库及其声明文件,以及 cors
库及其声明文件(cors
库是 Express
的扩展中间件,用于支持跨域访问)。
$ npm install express cors $ npm install @types/express @types/cors -D
bash
项目结构如下所示,粗体字标出的文件表示相对于上一节新增或修改的文件。
D:\TSProject\server-side │ package.json │ tsconfig.json │ ├─node_modules │ ... │ ├─dist │ ... │ └─src index.ts type.d.ts TaskAccess.ts
bash
编写任务类型声明并实现任务数据访问功能
src/type.d.ts
文件的内容如下。
interface Task { id: number, name: string, description: string, isDone:boolean }
typescript
该文件定义了表示任务的 Task
接口,用于供其他 TypeScript 文件引用,它包含 id
、name
(名称)、description
(描述)、isDone
(是否完成)等字段。
src/TaskAccess.ts
文件的内容如下。
class TaskAccessor { tasks: Task[] = [{ id: 1, name: "完成报告", description: "完成上个月的工作报告", isDone: false }]; taskIdIndex = 1; addTask(task: Task): Task { let newTask = { id: ++this.taskIdIndex, name: task.name, description: task.description, isDone: false }; this.tasks.push(newTask); return newTask; } deleteTask(taskId: number): boolean { let index = this.tasks.findIndex(p => p.id == taskId) if (index < 0) { return false; } this.tasks.splice(index, 1); return true; } setTaskDone(taskId: number): boolean { let index = this.tasks.findIndex(p => p.id == taskId) if (index < 0) { return false; } this.tasks[index].isDone = true; return true; } } export const taskAccessor = new TaskAccessor();
typescript
该文件提供 Task
数据访问功能。其中,声明了 TaskAccessor
类,在代码最后实例化了该类并将其值赋给变量 taskAccessor
,然后以模块的形式导出。
下面分别介绍 TaskAccess
类中的各个成员。
-
tasks
属性:用于存放Task
数组,并在其中初始化一个名为 “完成报告” 的Task
。 -
taskIdIndex
属性:用于存放当前最大的Task id
,用于实现新建Task
的id
自增。 -
addTask()
方法:要求传入新增的Task
对象,传入的Task
对象中需要包含name
属性和description
属性。id
属性根据taskIdIndex
自增,而isDone
属性默认为false
。新的Task
对象将放到tasks
数组中,返回值为当前新增的Task
对象。 -
deleteTask()
方法:要求传入待删除的Task id
,返回值表示是否成功删除。如果没有找到匹配传入的id
的Task
,则表示删除失败,返回false
;如果找到,则执行删除操作并返回true
。 -
setTaskDone()
方法:要求传入已完成的Task id
,返回值表示是否成功将Task
设置为已完成。如果没有找到匹配传入id
的Task
,则表示设置失败,返回false
;如果找到,则将Task
的isDone
属性设置为true
并返回true
。
编写任务管理后端服务API
src/index.ts
文件的内容如下。
import express from 'express'; import cors from 'cors' import { taskAccessor } from './TaskAccess' const app = express(); const port = 8000; //由于各个路由的请求中涉及Json对象转换,因此需要引入json中间件 app.use(express.json()); //下一章中的前端会调用下面的API,涉及跨域访问,需引入cors中间件 app.use(cors()); app.get('/tasks', (req, res) => { res.send(taskAccessor.tasks); }); app.post('/task', (req, res) => { const { name, description } = req.body; if (!name?.trim() || !description?.trim()) { return res.status(400).send('Name or description is null.'); } let newTask = taskAccessor.addTask(req.body); res.status(200).send(newTask); }); app.delete('/task/:id', (req, res) => { let deleteSuccess = taskAccessor.deleteTask(Number(req.params.id)) if (!deleteSuccess) { return res.status(400).send('Task does not exist.'); } res.status(200).send(deleteSuccess); }); app.put('/task/:id', (req, res) => { let setSuccess = taskAccessor.setTaskDone(Number(req.params.id)) if (!setSuccess) { return res.status(400).send('Task does not exist.'); } res.status(200).send(setSuccess); }); app.listen(port, () => { return console.log(`Express is listening at http://localhost:${port}`); });
typescript
该文件用于提供后端服务,引用 TaskAccess
模块来查询或修改 Task
数据,并将通过不同路由发布不同的数据操作 API。
接下来,分别介绍 index.ts
文件中各方法的作用。
-
app.use(…)
:引入中间件。这里引入了两个中间件,分别为json
和cors
。json
中间件用于处理各个路由的请求中涉及的Json
对象转换,cors
中间件用于支持下一章中将要编写的前端界面以跨域形式去调用各个 API。 -
app.get('/tasks'…)
:获取全部的Task
数据的 API。 -
app.post('/task'…)
:创建Task
的 API。如果传入的name
属性和description
属性为空值,将返回HTTP
状态码 400;如果传入的Task
内容正确,则调用taskAccessor
的addTask()
方法新增Task
,然后返回新增的Task
,且HTTP
状态码为 200。 -
app.delete('/task/:id'…)
:删除Task
的 API,将调用taskAccessor
的deleteTask()
方法。如果删除失败,则返回 HTTP 状态码 400;如果成功,则返回true
,且 HTTP 状态码为 200。 -
app.put('/task/:id'…)
:设置Task
状态为已完成的 API,将调用taskAccessor
的setTaskDone()
方法。如果设置失败,则返回 HTTP 状态码 400;如果成功,则返回true
,且 HTTP 状态码为 200。
之后,你就可以使用如 Postman
等 API 工具访问这些 API。首先,执行 npm start
命令启动后端服务。然后,通过 Postman
调用 /task POST API,新增一个任务,如图22-4所示。接着,调用 /task/:id PUT API 设置任务处于完成状态,如图22-5所示。


最后,调用 /tasks GET API 获取当前的全部任务,如图22-6所示。
