写在最前面
- 使用 node 完成一个
todolist app
的server
端,其中包括基本的 ts 配置方案和完成了 Models 和 Controler 层。 - 提示:需要对 Typescript 有一定了解,server 和 client 端均使用 Typescript
- 默认已经安装好
yarn
或者npm
您可以按照顺序阅读
- 全栈 Todolist-server 篇 Node(server) React(client) MongoDB(database) Typescript
- Todolist-database 篇(Cloud MongoDB)
- Todolist-client 篇(React Typescript)
NodeJS App(server 端)
1、初始化(源码参考)
- 新建文件夹
mkdir server
cd server
- 初始化
yarn init
- 构建文件目录
├── dist
├── node_modules
├── src
├── app.ts
├── controllers
| └── todos
| └── index.ts
├── models
| └── todo.ts
├── routes
| └── index.ts
└── types
└── todo.ts
├── nodemon.json
├── package.json
├── tsconfig.json
app.ts 就是我们项目的入口,dist 文件夹主要是负责 ts 编译输出文件,
nodemon.json
是数据库的配置项,后面会提到。
2、配置
- 我们来配置
ts.config
{
"compilerOptions": {
"target": "es6",
"module": "commonjs",
"outDir": "dist/js",
"rootDir": "src",
"strict": true,
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true
},
"include": ["src/**/*"],
"exclude": ["src/types/*.ts", "node_modules", ".vscode"]
}
outDir: 告诉编译器,把编译好的 js 文件输出到 dist/js 目录
rootDir: ts 需要编译的根目录
include: 告诉编译器具体需要编译的地址.
exclude: 排除不需要编译的文章
- 安装
typescript
yarn add typescript -g
- 安装
express
和MongoDB
依赖和他们的 @types
yarn add express cors mongoose
yarn add -D @types/node @types/express @types/mongoose @types/cors
- 安装用来编译 Typescript 的
concurrently
和nodemon
yarn add -D concurrently nodemon
- 最后我们添加 build 和 start 脚本
"scripts": {
"build": "tsc",
"start": "concurrently "tsc -w" "nodemon dist/js/app.js""
}
ps:这里
tsc
需要全局安装 ts 才能进行
concurrently
最主要的工作就是帮助我们编译 Typescript,进行热更新。
3、code(源码参考)
3.1 创建 todolist @types
- types/todo.ts
import { Document } from "mongoose"
export interface ITodo extends Document {
name: string
description: string
status: boolean
}
创建的新的 @types 是来自 mongoose 的 Document,也就是基础的文本格式。
3.2 创建 todolist Model
- models/todo.ts
import { ITodo } from "./../types/todo"
import { model, Schema } from "mongoose"
const todoSchema: Schema = new Schema(
{
name: {
type: String,
required: true,
},
description: {
type: String,
required: true,
},
status: {
type: Boolean,
required: true,
},
},
{ timestamps: true }
)
export default model("Todo", todoSchema)
创建一个类型库定义 dotolist 的数据类型。
3.3 API controllers
现在我们在 controller 中添加几个 todolist 相关的方法。
getTodos
- controllers/todos/index.ts
import { Response, Request } from "express"
import { ITodo } from "./../../types/todo"
import Todo from "../../models/todo"
const getTodos = async (req: Request, res: Response): Promise<void> => {
try {
const todos: ITodo[] = await Todo.find()
res.status(200).json({ todos })
} catch (error) {
throw error
}
}
需要引入 express 来明确的定义我们的 response 和 request 类型。具体的解析如上,我们使用 json 来定义我们的数据。这个函数来初始化我们的 todolist 的数据,页面加载会调用。
addTodo
- controllers/todos/index.ts
const addTodo = async (req: Request, res: Response): Promise<void> => {
try {
const body = req.body as Pick"name" | "description" | "status">
const todo: ITodo = new Todo({
name: body.name,
description: body.description,
status: body.status,
})
const newTodo: ITodo = await todo.save()
const allTodos: ITodo[] = await Todo.find()
res
.status(201)
.json({ message: "Todo added", todo: newTodo, todos: allTodos })
} catch (error) {
throw error
}
}
addTodo 函数用于添加新增一条的 list 和更新总的 lists。
updateTodo
- controllers/todos/index.ts
const updateTodo = async (req: Request, res: Response): Promise<void> => {
try {
const {
params: { id },
body,
} = req
const updateTodo: ITodo | null = await Todo.findByIdAndUpdate(
{ _id: id },
body
)
const allTodos: ITodo[] = await Todo.find()
res.status(200).json({
message: "Todo updated",
todo: updateTodo,
todos: allTodos,
})
} catch (error) {
throw error
}
}
更新一条 list,变成完成状态。我们需要传相关的 id 确定具体的 list。
deleteTodo
- controllers/todos/index.ts
const deleteTodo = async (req: Request, res: Response): Promise<void> => {
try {
const deletedTodo: ITodo | null = await Todo.findByIdAndRemove(
req.params.id
);
const allTodos: ITodo[] = await Todo.find();
res.status(200).json({
message: 'Todo deleted',
todo: deletedTodo,
todos: allTodos,
});
} catch (error) {
throw error;
}
};
删除一条信息
4、API routes
- routes/index.ts
import { Router } from "express"
import { getTodos, addTodo, updateTodo, deleteTodo } from "../controllers/todos"
const router: Router = Router()
router.get("/todos", getTodos)
router.post("/add-todo", addTodo)
router.put("/edit-todo/:id", updateTodo)
router.delete("/delete-todo/:id", deleteTodo)
export default router
好了现在基本的方法对应的路由就构建好了
5、MongoDB 数据库配置
- nodemon.json
{
"env": {
"MONGO_USER": "your-username",
"MONGO_PASSWORD": "your-password",
"MONGO_DB": "your-db-name"
}
}
具体怎么配置?可以看我的这篇 mongoDB clound 云数据库的配置文章。
- app.ts
import express, { Express } from 'express';
import mongoose from 'mongoose';
import cors from 'cors';
import todoRoutes from './routes';
import bodyParser from 'body-parser';
const app: Express = express();
// 这里默认 4000 端口,后续 client 端会用到,如果想自定义,保持一致即可
const PORT: string | number = 4000;
// const PORT: string | number = process.env.PORT || 4000;
console.log(process.env.PORT);
app.use(cors()); // 跨域处理
app.use(bodyParser.json()); // post 请求处理
app.use(bodyParser.urlencoded({ extended: false }));
app.use(todoRoutes); // 咋们的 api 路由处理
const uri: string = `mongodb srv://${process.env.MONGO_USER}:${process.env.MONGO_PASSWORD}@cluster0.4qpw4.mongodb.net/${process.env.MONGO_DB}?retryWrites=true&w=majority`;
const options = { useNewUrlParser: true, useUnifiedTopology: true };
mongoose.set('useFindAndModify', false);
mongoose
.connect(uri, options)
.then(() =>
app.listen(PORT, () =>
console.log(`Server running on http://localhost:${PORT}`)
)
)
.catch((error) => {
throw error;
});
复制代码
6、总结
- ok,现在我们的 server 端和 clound database就完成了,下篇来介绍 client 端的构建。
- 需要 gitignore的可以查看下面的 source code
7、源码
- 源码参考
- 大家可以按照 branch 分支的顺序查看
技术栈参考
- 如果对上面技术栈不太熟悉的同学可以优先参考以下文档
- react 官网
- typescript 官网
- node 官网
- mongoDB 官网
翻译来自
- freeCodeCamp