Isomorphic JavaScript with MEVN stack,第二部分------Express搭建后端

Building a RESTful Backend API with Node.js and Express.js

01 Create Server with Express.js

npm install express --save

  • 根目录下增加dev-server, prod-server
  • 创建dev-server/index.js, 参考express的helloword代码
const express = require("express");
const app = express();
const port = 3000;

app.get("/", (req, res) => res.send("Hello World!"));

app.listen(port, () => console.log(`EXAMPLE app listening on port ${port}!`));

npm install nodemon -g

运行:

nodemon dev-server/index.js

  • 启动测试服务: http://localhost:3000

nodemon 运行过程中输入rs手动重启服务

参考: https://babeljs.io/docs/en/usage

npm install --save-dev @babel/core @babel/cli @babel/preset-env

npm install --save @babel/polyfill

  • 新建dev-server/.babelrc
{
    "presets": ["@babel/preset-env"]
}

package.json下script增加:

"dev": "babel dev-server --out-dir prod-server --watch",

修改dev-server/index.js

// const express = require("express");
import express from "express";

运行

nodemon prod-server

测试开发服务是否正常运行。

npm install concurrently --save-dev

  • package.json 下的script参考:
  "scripts": {
    "serve": "vue-cli-service serve",
    "vuebuild": "vue-cli-service build",
    "dev": "babel dev-server --out-dir prod-server --watch",
    "build": "babel dev-server --out-dir prod-server && vue-cli-service build",
    "concurrently": "concurrently \"babel dev-server --out-dir prod-server --watch\" \"nodemon prod-server/index.js\" \"npm run serve\" ",
    "lint": "vue-cli-service lint",
    "lintfix": "eslint ./dev-server --fix && vue-cli-service lint"
  },

02 Learn to Use Express.js Router

  • 创建dev-server/api/task/tasks-routes.js
import express from "express";
const router = express.Router();

router.post("/task", (req, res) => {
  res.send("post.task - create a task");
});

router.get("/task", (req, res) => {
  res.send("get.task - get all tasks");
});

router.get("/task/:id", (req, res) => {
  res.send("get.task/:id - get task by id");
});

router.put("/task/", (req, res) => {
  res.send("put.task - update a task");
});

router.delete("/task/", (req, res) => {
  res.send("delete.task - update a task");
});

export default router;
  • 创建dev-server/routes.js
import taskRoutes from "./api/task/tasks-routes";

export function registerRoutes(app) {
  app.use("/api", taskRoutes);
}
  • 修改dev-server/index.js
// const express = require("express");
import express from "express";
const app = express();
const port = 3000;
//===========注册路由==========
import { registerRoutes } from "./routes";
registerRoutes(app);

app.get("/", (req, res) => res.send("Hello World!"));

app.listen(port, () => console.log(`EXAMPLE app listening on port ${port}!`));
  • 使用postman测试

postman测试/api/task/

postman测试/api/task/:id

postman测试post /api/task

  • 增加dev-server/api/auth/auth-routes.js
import express from "express";
const router = express.Router();
const apiName = "auth";

router.post(`/${apiName}`, (req, res) => {
  res.send(`post.${apiName} - login`);
});

export default router;
  • 增加dev-server/api/register/register-routes.js
import express from "express";
const router = express.Router();
const apiName = "register";

router.post(`/${apiName}`, (req, res) => {
  res.send(`post.${apiName} - register a user`);
});

export default router;
  • 增加dev-server/api/user/user-routes.js
import express from "express";
const router = express.Router();
const apiName = "user";

router.get(`/${apiName}`, (req, res) => {
  res.send(`get.${apiName} - get all user`);
});

export default router;
  • 修改dev-server/routes.js
import taskRoutes from "./api/task/tasks-routes";
import regRoutes from "./api/register/register-routes";
import userRoutes from "./api/user/user-routes";
import authRoutes from "./api/auth/auth-routes";

export function registerRoutes(app) {
  app.use("/api", taskRoutes);
  app.use("/api", regRoutes);
  app.use("/api", userRoutes);
  app.use("/api", authRoutes);
}

03 Use Express.js Middleware and CORS Configuration

npm install cors morgan --save-dev

npm install body-parser --save

  • 新建dev-server/config/env.js
import express from "express";
import morgan from "morgan";
import cors from "cors";
import bodyParser from "body-parser";

export function setEnvironment(app) {
  if (process.env.NODE_ENV !== "production") {
    setDevEnv(app);
  } else {
    setProdEnv(app);
  }
}

function setDevEnv(app) {
  //   console.log("setting development environment");
  process.env.NODE_ENV = "development";
  app.use(bodyParser.json());
  app.use(morgan("dev"));
  app.use(cors());
}

function setProdEnv(app) {
  app.use(bodyParser.json());
  app.use(express.static(__dirname + "/../dist"));
  console.log("setting production environment");
}
  • 修改dev-server/index,引入setEnvironment middleware
// const express = require('express')
import express from "express";
const port = 3000;
const app = express();
import { registerRoutes } from "./routes";
import { setEnvironment } from "./config/env";

setEnvironment(app);
registerRoutes(app);

// app.get('/', (req, res) => res.send('Hello World!'))

app.get("/", (req, res) => {
  if (process.env.NODE_ENV !== "production") {
    return res.send("Running server in devlopment mode.");
  } else {
    return res.sendFile("index.html"), { root: __dirname + "/../dist" };
  }
});

app.listen(port, () => {
  const msg = `MEVN app listening on port ${port} and run in ${process.env.NODE_ENV} mode!`;
  console.log(msg);
});
  • package.json的script增加
    "build": "set NODE_ENV=production && babel dev-server --out-dir prod-server && vue-cli-service build",
    "concurrently": "concurrently \"set NODE_ENV=development\" \"babel dev-server --out-dir prod-server --watch\" \"nodemon prod-server/index.js\" \"npm run serve\" ",

注意linux环境应该是export NODE_ENV=production

04 RESTful Endpoints with HTTP Controllers

  • 新建dev-server/api/user/user-controller.js
export function index(req, res) {
  return res.json({ message: "Hello World" });
}
  • 更改dev-server/api/user/user-routes.js
import express from "express";
const router = express.Router();
const apiName = "user";

import * as controller from "./user-controller";

/* router.get(`/${apiName}`, (req, res) => {
     res.send(`get.${apiName} - get all user`);
   }); */
router.get(`/${apiName}`, controller.index);

export default router;
  • 修改Home.vue增加beforeCreate
<template>
  <div id="custom-home">
    <Main />
  </div>
</template>

<script>
import Main from "@/components/Main.vue";

export default {
  name: "home",
  components: {
    Main,
  },
  beforeCreate: function () {
    fetch(this.$store.state.apiUrl + "/user", {
      method: "GET",
    })
      .then((res) => res.json())
      .then((res) => console.log(res));
  },
};
</script>
  • 浏览器端,测试验证

  • 增加utilities/string-util.js
//babel编译抛错
/*
export class StringUtil {
  static isEmpty(value) {
    return !value || !value.trim();
  }

  static capitalize(word) {
    return word.charAt(0).toUpperCase();
  }
}
*/
export const isEmpty = (value) => {
  return !value || !value.trim();
};

export const capitalize = (word) => {
  return word.charAt(0).toUpperCase();
};
  • 增加dev-server/register/register-controller.js
//import { StringUtil } from "../../utilities/string-util";
import * as StringUtil from "../../utilities/string-util";

export function index(req, res) {
  const validation = validateIndex(req.body);
  if (!validation.isValid) {
    return res.json({ message: validation.message });
  }

  const user = {
    username: req.body.username.toLowercase(),
    password: req.body.password,
  };
  console.log(user);
  return res.json();
}

function validateIndex(body) {
  let errors = "";
  if (StringUtil.isEmpty(body.username)) {
    errors += "Username is required. ";
  }
  if (StringUtil.isEmpty(body.password)) {
    errors += "Password is required. ";
  }

  return {
    isValid: StringUtil.isEmpty(errors),
    message: errors,
  };
}
  • 修改dev-server/register/register-routes.js, 引入controller
import express from 'express';
const router = express.Router();
import * as controller from './register-controller';

router.post('/register', controller.index);

export default router;
  • 新建dev-server/api/task/tasks-controller.js
export function index(req, res) {
  // FIND ALL TASKS
  return res.json();
}

export function create(req, res) {
  return res.json();
}

export function update(req, res) {
  // UPDATE TASKS
  return res.json();
}

export function remove(req, res) {
  // DELETE A TASK
  return res.json();
}

export function show(req, res) {
  // GET TASK BY ID
  return res.json();
}
  • 更改dev-server/api/task/tasks-routes.js, 引入controller
import express from "express";
const router = express.Router();
import * as controller from "./tasks-controller";

router.post("/task", controller.create);
router.get("/task", controller.index);
router.get("/task/:id", controller.show);
router.put("/task", controller.update);
router.delete("/task", controller.remove);

export default router;
  • 增加dev-server/api/auth/auth-controller.js
//import { StringUtil } from "../../utilities/string-util";
import * as StringUtil from "../../utilities/string-util";

export function index(req, res) {
  const validation = validateIndex(req.body);
  if (!validation.isValid) {
    return res.json({ message: validation.message });
  }

  return res.json();
}

function validateIndex(body) {
  let errors = "";
  if (StringUtil.isEmpty(body.username)) {
    errors += "Username is required. ";
  }
  if (StringUtil.isEmpty(body.password)) {
    errors += "Password is required. ";
  }

  return {
    isValid: StringUtil.isEmpty(errors),
    message: errors,
  };
}
  • 修改dev-server/api/auth/auth-routes.js, 引入controller
import express from "express";
const router = express.Router();
const apiName = "auth";
import * as controller from "./auth-controller";

/* router.post(`/${apiName}`, (req, res) => {
     res.send(`post.${apiName} - login`);
   }); */

router.post(`/${apiName}`, controller.index);

export default router;

05 Check HTTP Status Codes

http的状态码的意义,参考:https://httpstatuses.com/

  • 修改dev-server\api\auth\auth-controller.js
import * as StringUtil from "../../utilities/string-util";

export function index(req, res) {
  const validation = validateIndex(req.body);
  if (!validation.isValid) {
    return res.status(400).json({ message: validation.message });
  }

  return res.status(201).json();
}

function validateIndex(body) {
  let errors = "";
  if (StringUtil.isEmpty(body.username)) {
    errors += "Username is required. ";
  }
  if (StringUtil.isEmpty(body.password)) {
    errors += "Password is required. ";
  }

  return {
    isValid: StringUtil.isEmpty(errors),
    message: errors,
  };
}
  • 修改dev-server\api\register\register-controller.js
// import { StringUtil } from "../../utilities/string-util";
import * as StringUtil from "../../utilities/string-util";

export function index(req, res) {
  const validation = validateIndex(req.body);
  if (!validation.isValid) {
    return res.status(400).json({ message: validation.message });
  }

  const user = {
    username: req.body.username.toLowercase(),
    password: req.body.password,
  };
  console.log(user);
  return res.status(201).json();
}

function validateIndex(body) {
  let errors = "";
  if (StringUtil.isEmpty(body.username)) {
    errors += "Username is required. ";
  }
  if (StringUtil.isEmpty(body.password)) {
    errors += "Password is required. ";
  }

  return {
    isValid: StringUtil.isEmpty(errors),
    message: errors,
  };
}
  • 修改dev-server\api\task\tasks-controller.js
export function index(req, res) {
  // FIND ALL TASKS
  return res.status(200).json();
}

export function create(req, res) {
  return res.status(201).json();
}

export function update(req, res) {
  // UPDATE TASKS
  return res.status(204).json();
}

export function remove(req, res) {
  // DELETE A TASK
  return res.status(204).json();
}

export function show(req, res) {
  // GET TASK BY ID
  return res.status(200).json();
}
  • 修改dev-server\api\user\user-controller.js
export function index(req, res) {
  return res.status(200).json({ message: "Hello World" });
}
  • 注释Home.vue中的beforeCreate方法中的一行,测试
  beforeCreate: function () {
    fetch(this.$store.state.apiUrl + "/user", {
      method: "GET",
    })
      // .then((res) => res.json())
      .then((res) => console.log(res));
  },

http status 200

http status 204

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值