[译] 全栈 Todolist-server 篇 Node(server) React(client) MongoDB(database) Typescript

时间:2021-1-8 作者:admin

写在最前面

  • 这篇文章适用者,node 初学者的前端同学,或者对 react 有兴趣的后端同学。文章难度为入门,即使不太了解这些语言的同学稍微查阅资料也能看懂。
  • 提示:需要对 Typescript 有一定了解,server 和 client 端均使用 Typescript
  • 默认已经安装好 yarn或者npm

技术栈参考

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
  • 安装 expressMongoDB 依赖和他们的 @types
yarn add express cors mongoose

yarn add -D @types/node @types/express @types/mongoose @types/cors
  • 安装用来编译 Typescript 的concurrentlynodemon
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<ITodo>("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<ITodo, "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。

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;
    });

5、总结
  • ok,现在我们的 server 端和 clound database就完成了,下篇来介绍 client 端的构建。
  • 需要 gitignore的可以查看下面的 source code
6、源码

翻译来自

声明:本文内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎进行举报,并提供相关证据,工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。