---
# System prepended metadata

title: "\U0001F3C5 Day 16 - Express 應用程式產生器（Express generater）、在 routes 設計路由"
tags: [Node.js 直播班 - 2024 春季班]

---

# 🏅 Day 16 - Express 應用程式產生器（Express generater）、在 routes 設計路由
express 應用程式產生器可以快速產生一個應用程式架構

安裝步驟
- 先開好一個新專案
- 執行 `npm install express-generator -g`
- 接著切換到專案路徑下，執行 `express --no-view`
可參考[文件](https://expressjs.com/zh-tw/starter/generator.html)查看指令選項
注意：這裡需要選擇 `no view`，因最終作業最後設計出的 API 只需要回傳 JSON 資料，不會使用到 view 模板引擎
:::spoiler 指令選項
```
$ express -h

  Usage: express [options][dir]

  Options:

    -h, --help          output usage information
        --version       output the version number
    -e, --ejs           add ejs engine support
        --hbs           add handlebars engine support
        --pug           add pug engine support
    -H, --hogan         add hogan.js engine support
        --no-view       generate without view engine
    -v, --view &lt;engine&gt; add view &lt;engine&gt; support (ejs|hbs|hjs|jade|pug|twig|vash) (defaults to jade)
    -c, --css &lt;engine&gt;  add stylesheet &lt;engine&gt; support (less|stylus|compass|sass) (defaults to plain css)
        --git           add .gitignore
    -f, --force         force on non-empty directory
```
:::

執行成功後應該會出現以下結構
:::spoiler 資料夾結構
```
├── app.js
├── bin
│   └── www
├── package.json
├── public
│   ├── images
│   ├── javascripts
│   ├── stylesheets
│   │   └── style.css
│   └── index.html
└── routes
    ├── index.js
    └── users.js
```
:::


此結構已將 routes 的部分拆成獨立模組，並在 app.js 引入
在 routes 的 index.js 或 users.js，會使用 `const router = express.Router()` 
並使用 `router` 來設定路由

app.js 引入
```javascript=
const usersRouter = require('./routes/users');
app.use('/users', usersRouter);
```

./routes/users.js
```javascript=
const express = require('express');
const router = express.Router();

router.get('/', function(req, res, next) {
  res.send('respond with a resource');
});

module.export = router;
```
> 需注意在 app.js 引入使用時，就會自動帶入 `/users`，因此 users.js 中 path 可直接從 `/users` 之後開始（ 第 4 行：`router.get('/', ...)` 就會是 `/users`)

第一次啟用伺服器時需執行 `npm install` 安裝相關套件，並執行 `npm start`
若想使用 nodemon 運行也可自行在 package.json 加上指令，並使用 `npm run start:dev` 運行
```json
"scripts": {
  "start": "node ./bin/www",
  "start:dev": "nodemon ./bin/www"
}
```

### 參考資源

- [Express 應用程式產生器](https://expressjs.com/zh-tw/starter/generator.html)
- [Express - API](http://expressjs.com/zh-tw/api.html#express.router)
- 課程影音「Express - Node.js Web 應用程式架構」

題目
---
請嘗試建立一個 express 專案使用 express generater 產生結構，並完成以下需求

1. 在 app.js 載入 mongoose 並連接至 database（database 名稱可自行設定）
2. 建立 Post Model 連接 Post collection 與 postSchema（拆分至 `./models/posts.js` ）
3. 將 postsRouter 拆分至 ./routes/posts.js 內設計取得所有貼文與新增貼文的路由
  - 取得所有貼文 GET，200 成功回傳 `status: 'success'` 與貼文資料（運用到 mongoose 查詢資料）
  - 新增貼文 POST，200 成功回傳 `status: 'success'` 與 `message: '新增成功'`（運用到 mongoose 新增資料）
4. 在 app.js 引入 postsRouter

app.js
```javascript=
var express = require('express');
var path = require('path');
var cookieParser = require('cookie-parser');
var logger = require('morgan');

/* 載入 mongoose 並連接至 database（database 名稱可自行設定） */
...

var indexRouter = require('./routes/index');
var usersRouter = require('./routes/users');

/* 引入 postsRouter */
...

var app = express();

app.use(logger('dev'));
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));

app.use('/', indexRouter);
app.use('/users', usersRouter);

/* 使用 postsRouter */
...

module.exports = app;
```

./models/posts.js
```javascript=
/* 建立 Post Model 連接 Post collection 與 postSchema */
...
```
> :::spoiler 可直接使用此簡易 schema 範例（或是自行依照作業設計稿設計）
> ```
> const postSchema = new mongoose.Schema({
>   content: {
>     type: String,
>     required: [true, '貼文內容未填寫']
>   },
>   image: {
>     type: String,
>     default: ''
>   },
>   createdAt: {
>     type: Date,
>     default: Date.now,
>     select: false
>   },
>   likes: {
>     type: Number,
>     default: ''
>   }
> }, { versionKey: false });
> ```
> :::
<br>

./routes/posts.js
```javascript=
/* 設計取得所有貼文、新增貼文的路由 */
...
```


## 回報流程

將答案寫在 CodePen 並複製 CodePen 連結貼至底下回報就算完成了喔! 
解答位置請參考下圖（需打開程式碼的部分觀看）

![](https://i.imgur.com/vftL5i0.png)

<!-- 解答：  

app.js 
```javascript=
/* 載入 mongoose 並連接至 database（database 名稱可自行設定） */
const mongoose = require('mongoose').
mongoose.connect('mongodb://localhost:27017/testPost');

/* 引入 postsRouter */
const postsRouter = require('./routes/posts.js')

/* 使用 postsRouter */
app.use('/posts', postsRouter);
```

＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊

./models/posts.js
```javascript=
const mongoose = require('mongoose');
const postSchema = new mongoose.Schema({
  content: {
    type: String,
    required: [true, '貼文內容未填寫']
  },
  image: {
    type: String,
    default: ''
  },
  createdAt: {
    type: Date,
    default: Date.now,
    select: false
  },
  likes: {
    type: Number,
    default: ''
  }
}, { versionKey: false });

const Post = mongoose.model('Post', postSchema);

module.exports = Post;
```

＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊

./routes/posts.js
```javascript=
const express = require('express');
const router = express.Router();

const Post = require('../models/posts');

// 取得所有貼文
router.get('/', async (req, res) => {
  const allPosts = await Post.find();
  res.status(200).json({
    status: 'success',
    data: allPosts
  })
});

// 新增貼文
router.post('/', async (req, res) => {
  const postData = req.body;
  const allPosts = await Post.create(postData);
  res.status(200).json({
    status: 'success',
    message: '新增成功'
  })
});

module.exports = router;
```

-->




回報區
---
<!-- 
將答案貼至下方表格內，格式：
| Discord 暱稱 | [CodePen](連結) |
-->

|    Discord    |   CodePen ／ 答案  |
|:-------------:|:-----------------:|
| xxx | [CodePen]() |
| 苡安 | [hackmd](https://hackmd.io/@L7K9-66lSeagS28AP0_GjQ/HkwnyVDZC) |
| Chia Pin | [CodePen](https://codepen.io/joker-cat/pen/VwNgVrq) |
| jenny7532 | [CodePen](https://codepen.io/wei-chen-wu/pen/qBwgQjK#_=_) |
| Lobinda | [HackMD](https://hackmd.io/@Lobinda/S1GwoYDZC) |
| wei | [HackMD](https://hackmd.io/ET0OOWI4T66UO_eTasYjhQ?view) |
| Aida | [CodePen](https://codepen.io/ada23410/pen/eYoxobX?editors=0010) |
| ej_chuang | [CodePen](https://codepen.io/EJChuang/pen/gOyEXoJ) |
| william_hsu | [CodePen](https://codepen.io/william8815/pen/xxeBPWW) |
| Tiya | [CodePen](https://codepen.io/Tiya_blank/pen/rNbQPbY) |
| Ciel | [CodePen](https://codepen.io/nycteachen/pen/NWmmRJa) |
| tung030374 | [CodePen](https://codepen.io/tung__u/pen/ExJJRej) |
| Henry | [HackMD](https://hackmd.io/htzJ8rbKTSmu71Nd7Wf7OQ) |
| Hank | [CodePen](https://codepen.io/tw1720/pen/dyLrzNx) |
| Fabio20 | [CodePen](https://codepen.io/fabio7621/pen/mdgYqJq) |
| william威良 | [CodePen](https://codepen.io/snowman12320/pen/ExJzbPP?editors=1010) |
| 2魚 | [CodePen](https://codepen.io/ijrekmsn-the-sans/pen/JjVQPvP) |
| 瑀君 |[HackMD](https://hackmd.io/@sh5ojkmt/rJ8u6WWMC)|
|Mei|[HackMd](https://hackmd.io/WNpQWt3JTY2hqacXHAAjjg?view)|
|Benson|[CodePen](https://codepen.io/nosneb83/pen/bGJyYjJ)|
| albertyang3576 | [CodePen](https://codepen.io/albertyang3576/pen/eYowXOx)|
| runweiting | [CodePen](https://codepen.io/weiting14/pen/ZEZgLpw)|
| zaoannihao | [CodePen](https://codepen.io/ckhwdvrx-the-solid/pen/OJYyKwW)|
|Theodore0602|[Codepen](https://codepen.io/GustavoFringgg/pen/WNBpYOo?editors=0010)