# 後端basic - Express
[Node.js Express 結構分析](https://ithelp.ithome.com.tw/articles/10222345)

開始使用Express in project: 在目標資料夾使用`npm init`並用`npm install express`安裝
* Tools:
Templating
URL Mapping/Routing
User Input Processing
[Installation guides for common application development tools](https://treehouse.github.io/installation-guides/) | [解決: 因為這個系統上已停用指令碼執行,所以無法載入...](https://israynotarray.com/other/20200510/1067127387/)
#### Server
A **program** runs on a remote computer, wait for **HTTP request** from client(使用者輸入網址), then bring action to putting together a **response**.
通常會先在local端建server測試app,測試完成後再把app [Deploy](https://teamtreehouse.com/library/deploy-a-node-application-to-heroku) 到remote server.
#### Route (end point)
對client端來說: Route是URLs
對server端來說: Route是**command**,會執行特定**function** which sends **response** back to client
## 開始使用express
[Express doc - API reference](https://expressjs.com/en/4x/api.html) | 若code有更改,server必須重開才會更新,此時可用[nodemon](https://www.npmjs.com/package/nodemon)來自動化此步驟
```
const express = require('express');
const app = express();
app.get('/', (request, response) => {...}); //參數1-PATH:'/'是root route, 參數2-callback
```
* `app.listen(port, callback)`method: 參數1 tell server which port to serve the app on
## Pug Templating
#### template (views)

templates are a special type of file that have their own syntax and language, **stored on server**, and act as some kind of **form letter** for your HTML.
The result is a **full HTML page** sent to the client.
* Rendering the template: provides the **basic HTML** for app and serves it to the users.
* vary output to provide customized **responses**.
* JS templatimg engine languages: **[Pug](https://pugjs.org/api/getting-started.html)**(formerly Jade), **[Handlebars](https://handlebarsjs.com/)**, **[EJS](https://ejs.co/)**

[pug加attrubutes](https://pugjs.org/language/attributes.html)
#### start to use pug
1. Downloading Pug with npm
2. Update code with `app.set()` method in app to use Pug
```
app.set('view engine', 'pug'); //參數2:要用哪個engine
```
3. Create templates and folder for templates
By default, Express會指向root裡面的'views'資料夾,我們會把Template檔案(e.g. `index.pug`)放在裡面。若要更改路徑參考[app.set()](https://expressjs.com/en/guide/using-template-engines.html)
4. Render templates with response.render()
```
res.render('index'); //Pug會自己抓資料夾裡面的檔案名來render
```

可用dev tool來查看template的內容,並整理排版
5. templates.pug檔案常用開頭:
```
doctype html
html(lang="en")
head
title Your Web Page
body
```
* [Using Logic in Pug](https://orandigo.github.io/blog/2020/12/27/20201227-pug-note/)
可做if...else判斷,loop等
#### interpolation (template literals of Pug)
```
h1 My name is #{name} //<h1>My name is Andrew</h1>
```
attributes(title, id, class...)不接受interpolation,所以要這樣寫:
```
h1(title='My name is '+ name) #{name} // <h1 title='My name is Andrew'>Andrew</h1>
```
#### [Template Inheritance](https://pugjs.org/language/inheritance.html)
可以寫一個layout.pug包含所有template會共用的部分,並讓child.pug繼承parent.pug來共用layout
* 方法1:block content
```
//parent template: layout.pug
block content
------
//child template
extends layout.pug //延伸的template路徑,parent.pug
block content //讓child.pug輸入內容到content block
section#content //這些內容會被放入parent.pug的content block
```
*方法2:[Include](https://pugjs.org/language/includes.html) 常用在header跟footer
```
//parent template: layout.pug
include includes/header.pug //views裡創建includes資料夾,並連結child檔案路徑
------
//child template
header //直接寫內容
h1 Assignment 2
```
#### [HTML to Pug](https://html2jade.org/)
## Request object & Response object in Pug
### Request object
Gives us access to data the client has sent to the server, such as values of fields from a form submission.
#### making a [POST](https://expressjs.com/en/4x/api.html#app.post.method) request using `form` tag: send data to the server
```
form(action='/url', method='post') //參數1:提供data到哪個path(空白會提供給當前頁面), 參數2:request method
label Please enter a Number:
input(type='number', name='inputValue') //給user的輸入欄位
button(type='submit') Submit //submit按鈕
```
#### [Request](https://expressjs.com/en/4x/api.html#req) Object in Pug
* `req.body`: 注意body property, this is where our ***form response* will end up**. By default, it is **undefined**
* **Middleware**: some **code fits in the middle** of a *request* or *response*, it dose something with the *incoming data*(HTTP request), and hands the result of to the app.
We use middleware **to put the form response into the body**. (e.g.`express.json()` or `express.urlencoded()`)
```
app.use(express.urlencoded({ extended: false})); //不要問為甚麼,之後user輸入的資料就會進到req.body了
```

* `express.urlencoded()`在做這件事:

* 三個獲取參數的method: `req.params` `req.body` `req.query`
### [Response](https://expressjs.com/en/4x/api.html#res) object
Packaging a response to be sent back to the client.
#### res.send()
```
res.send('<h1>Hello World!</h1>')
```
#### [res.render()](https://expressjs.com/en/4x/api.html#res.render) Method: Turn templates into HTML
```
res.render(view [, locals] [, callback]) //[]代表optional
```
參數1:view檔案名(不用加附檔名.pug)
參數2:Locals-{var:value} for view to have access to when being rendered.
### Locals
Locals是一個object(e.g.`{prompt: 'Who are you?'}`,`{num: request.body.num}`)
也可使用`res.locals`,以下兩段程式碼等效
```
res.render('card', {prompt:'Who is buried in Grant's tomg?}); //在.pug檔裡使用prompt會輸出值'Who is buried in Grant's tomg?
```

* 兩種把res.locals傳入template.pug的方法
```
h1= prompt //若var沒定義,則為undefined, h1值為空白
h1 The hint is #{name} //類似template literals的用法
```

#### GET POST cycle
express裡設定GET跟POST request(num的值由POST form裡的.inputValue定義)

Pug裡寫if num有被定義則GET,else則render POST(屬性name:inputValut)

#### res.json()
For client who don't want all the persentation of HTML CSS, they just want data. (e.g. build REST API)
```
res.json(req.body); //return {"username":"Andrew"}
```
## Modular Routes
### Cookies
Cookie store **state** data on the client.
(Further Resources for Storing State: keywords - Local Storage, SQL and Node.js with Sequelize, Mongo)
1. [`res.cookie()`](https://expressjs.com/en/4x/api.html#res.cookie): Send a cookie to the broswer after *submit the form*, then the browser will automatically send this cookie with *every request it makes*.
```
//res.cookie(name, value [, options])
res.cookie('username', req.body.username); //參數1:name, 參數2:從form取出的值
```
但此時server isn't reading回傳的cookie, to read the cookie from the request, 在request object裡需要有 cookie's property, 此時就需要cookie-parser這個Middleware.
2. [`cookie-parser`](https://github.com/expressjs/cookie-parser): 可以讓我們讀取form裡的data
* npm install cookie parser
* config and use cookieParser in your app
```
const cookieParser = require('body-parser');
app.use(cookieParser());
```
3. [`res.cookies()`](https://expressjs.com/en/4x/api.html#req.cookies): 讀取步驟1 form submit的值. When using *cookie-parser* middleware, this property is an **object** that contains *cookies sent by the request*. If the request contains no cookies, it defaults to `{}`.

### redirect
當Client端request一個 *受保護的*(需login) 或*輸入錯誤的*(Google買下的類似domain) 或*被移動的* URL, Server通常會回覆一個包含redirect URL的response, Client收到後會立刻make a 2nd request去這個new URL.
HTTP Redirects require a browser or client to make a second request and **don't require action from the user** to follow the new URL being redirected to.
* `res.redirect([status,] path)`
利用cookie state來redirect: 若cookie state裡有username,首頁會歡迎{[name](https://ui.dev/shorthand-properties)}; 若無,redirect到inputForm讓使用者輸入username

* `res.clearCookie()`
首頁清除cookie後redirect到inputForm


## [Middleware](https://expressjs.com/en/guide/writing-middleware.html)
讀取req跟res的需求,處理成回覆給使用者的res
* Basic form of Express middleware
```
(req, res, next) => {
// do something
next();
}
```
* express使用middleware
```
app.use((req, res, next) => {}); //for every request
app.use('/users', (req, res, next) => {}); //run for特定route
```
`.use`可以換成`.get`,單純處理get request
* Sequence: 會按順序由上往下執行,也可用`,`增加多個function
```
app.use((req, res, next) => { //func1
console.log('one');
next();
},
(req, res, next) => { //func2
console.log('two');
next();
});
app.use((req, res, next) => { //func3
console.log('three');
next();
});
//one two three
```
* pass info
```
app.use((req, res, next) => {
req.message = 'I made it!';
next();
});
app.use((req, res, next) => {
console.log(req.message);
next();
});
//I made it!
```
#### The `next` function
* `next()`;宣告一個middleware-function結束了,可以執行下一個
* 要結束一個middleware function,要馬`next()`,要馬完成一個response (e.g.`.render()`,`.send()`),不然app會一直loading
* third party middleware: these func are being called as Express sets up the server and returns middleware functions.([Closures的概念](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Closures))

### Handling Errors in an Express App
By Passing an object as a parameter to `next()`來抓app裡的錯誤
```
app.use((req, res, next)=>{
const err = new Error('Oh noes!'); //製作一個方便查找的簡短Error message
err.status = 500; //這裡的.status是普通的object property, 500代表general error
next(err);
});
```

This output comes from Express's built in error handler.紅線為錯誤發生位置
#### Error Handling Middleware
* Error Middleware
```
(err, req, res, next) => {} //Express會把Error object pass給第一個有4個parameter的Middleware(類似request.on("error", () =>{})的概念)
```
```
app.use((err, req, res, next)=>{
res.local.error = err; //把local.error property設成err
res.status(err.status); //抓取status code給browser
res.render('error', err); //參數1:error template, 參數2:error object
});
```
* `res.status()`method takes the number of the code.

#### Handling 404 Errors
A 404 signals the requested route dosen't exists. Express's native handler會傳送預設的404 plain text給client端
如何catch the request before他跑到最後,並傳送客製化404頁面

```
//做一個'error製造Middleware'放在Error Middleware之前,Express跑到這,會使用這個製造機
app.use((req, res, next)=>{
const err = new Error('Not Found');
err.status = 404;
next(err);
});
```
## Parameters, Query Strings, and Modularizing Routes
### Modular Routes

通常業界會把route依功能模組拆分成數個檔案,放在route資料夾

```
//index.js裡的config
const express = require('express');
const router = express.Router();
======
router.get('/'......);
router.post('/inputForm'......);
======
module.exports = router;
```
```
//cards.js裡的config
const express = require('express');
const router = express.Router();
======
router.get('/'......); //因為在app.js裡app.use('/cards', cardRoutes); 所以在cards.js裡的route都會多一個/cards
======
module.exports = router;
```
### Using Data and Route Parameters
以下程式碼使用{[ES6 Shorthand Properties](https://ui.dev/shorthand-properties)} + 解構賦值

* Route Parameters `/:`
```
// '/:'的':'後面的值會被當成param的name,以id示範
router.get('/:id',(req, res)=>{});
```
* [`req.params`](https://expressjs.com/en/api.html#req.params) object 網頁網址會變`/url/id`
* [`req.query`](https://expressjs.com/en/api.html#req.query) object 用query string的方法取值 網頁網址會變`/url?key1=value1&key2=value2`
### 隨機card的.pug

## Serving Static Assets
Static Assets: 靜態網頁內容(CSS, client-side JS),存放在web server資料夾內的完整檔案,會直接交由browser(Client端)執行.(Express無法讀取Client端的js)
#### Setup
1.先在project裡建立一個public(業界慣用)資料夾,裡面存放.css檔案
#### `express.static()` method
2.設一個route連到public資料夾
```
app.use('/static', express.static('public'));
```

3.若希望所有頁面都使用此stylesheet, 在layout.pug裡連結此檔案(css會放在`<head>`tag裡)

4.調整template