六角體驗營
# Todolist RESTful API : 開發新刪修查的API (實作3) - POST API 資料錯誤樣態
[**Todolist RESTful API : 開發新刪修查的API (實作2) - CRUD ( GET / POST API )**](https://hackmd.io/fjk5zVcFRwaVnQND2iUNfQ?view)
<br>
## 11. 新增 POST API 異常行為
> try catch 捕捉錯誤
> * [**個人筆記**](https://hackmd.io/c2KkZRulQ2-AdBIXNds43w?view#try-catch-%E6%8D%95%E6%8D%89%E9%8C%AF%E8%AA%A4%E7%95%B0%E5%B8%B8%E8%A1%8C%E7%82%BA)
> * [**mdn docs**](https://developer.mozilla.org/zh-TW/docs/Web/JavaScript/Reference/Statements/try...catch)
### 錯誤樣態 : 格式錯誤
**格式錯誤1. POST資料非JSON格式 -> JSON.parse 無法解析 )**
* #### STEP 11-1. 將 try...catch 在POST方法中執行
* try 區塊放正確應執行的內容(可能拋出錯誤)
* catch 區塊印出 error 錯誤資訊
```js=
const http = require('http');
const todos = [
// 清空,之後以POST方式新增
]
const requestListener = (request,response)=>{
const headers = {
'Access-Control-Allow-Headers': 'Content-Type, Authorization, Content-Length, X-Requested-With',
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Methods': 'PATCH, POST, GET,OPTIONS,DELETE',
'Content-Type': 'application/json'
};
let body ="";
request.on('data',(chunk)=>{
body += chunk;
})
if(request.url=='/todolist' && request.method == "GET"){
response.writeHead(200,headers);
response.write(JSON.stringify({
"status":"success",
data:todos,
}));
response.end();
//POST方法-------------------------------------------------------
}else if(request.url=='/todolist' && request.method == "POST"){
request.on('end',()=>{
//try...catch------------------
try{ // 這裡有可能拋出錯誤
const title = JSON.parse(body).title;
console.log(title);
const todo = {
"title":title,
"id":uuidv4()
}
todos.push(todo);
response.writeHead(200,headers);
response.write(JSON.stringify({
"status":"success",
data:todos,
}));
response.end(); //回傳結束
}catch(error){ // 處理錯誤
console.log(error,"程式錯誤") //error會印出錯誤資訊
response.end(); //回傳結束
}
})
//-----------------------------------------------------------------
}else if(request.method == "OPTIONS"){
response.writeHead(200,headers);
response.end();
}else{
response.writeHead(404,headers);
response.write(JSON.stringify({
"status":"fail",
"message":"查無此路由",
}));
response.end();
}
};
const server = http.createServer(requestListener);
server.listen(3005);
```
* postman POST 非JSON內容 ` { `
-> 執行catch區塊,erminal 會回傳錯誤代碼(下圖)

* #### STEP 11-2. 進一步修改 catch 區塊執行程式
```js=
//POST方法-------------------------------------------------------
}else if(request.url=='/todolist' && request.method == "POST"){
request.on('end',()=>{
//try...catch------------------
try{
const title = JSON.parse(body).title;
console.log(title);
const todo = {
"title":title,
"id":uuidv4()
}
todos.push(todo);
response.writeHead(200,headers);
response.write(JSON.stringify({
"status":"success",
data:todos,
}));
response.end(); //回傳結束
//修改為回傳錯誤資訊給使用者-----------------
}catch(error){
response.writeHead(400,headers); //400 bad request 錯誤請求 (格式錯誤)
response.write(JSON.stringify({
"status":"false",
"message":"欄位未填寫正確,或無此todo id"
}));
response.end();
}
})
//-----------------------------------------------------------------
```
* postman POST 非JSON格式

**格式錯誤2. JSON 中 key值 錯誤**
> 必要欄位沒有 POST -> undefined 狀態
* #### STEP 11-3. 修改 try 區塊 : 若沒有回傳todo{"title":title},印出錯誤資訊
```js=
//POST方法-------------------------------------------------------
}else if(request.url=='/todolist' && request.method == "POST"){
request.on('end',()=>{
//try...catch------------------
try{
const title = JSON.parse(body).title;
console.log(title); //沒有title屬性的話 會印出undefined
//1. POST物件中有title屬性------------------------------------------
if(title !== undefined){
const todo = {
"title":title,
"id":uuidv4()
}
todos.push(todo);
response.writeHead(200,headers);
response.write(JSON.stringify({
"status":"success",
data:todos,
}));
response.end(); //回傳結束
//2. POST物件中沒有title屬性資料 -> undefined---------------------
}else{
//執行與catch error一樣的錯誤訊息
response.writeHead(400,headers); //400 bad request 錯誤請求 (格式錯誤)
response.write(JSON.stringify({
"status":"false",
"message":"欄位未填寫正確,或無此todo id"
}));
response.end();
}
}catch(error){
response.writeHead(400,headers); //400 bad request 錯誤請求 (格式錯誤)
response.write(JSON.stringify({
"status":"false",
"message":"欄位未填寫正確,或無此todo id"
}));
response.end();
}
})
//-----------------------------------------------------------------
```
* postman 測試錯誤樣態2
* POST 物件中沒有"title"屬性資料,仍會是 200 ok 回傳成功 (下圖 postman 回傳成功)
| 修改前: 使用POST方法 (try區塊沒使用 if...else 執行必要欄位檢驗)|
| -------- |
|  |
* 將錯誤代碼使用 if...else 寫在 try 區塊 ( 如 **step 11-3.** )
|修改後: 使用POST方法 (try區塊將必要屬性放在if執行內容,else 錯誤資訊回傳) |
| -------- |
|  |
<br>
## 12. 重構程式碼
> 整理重複的程式碼,將程式碼"模組化"
* #### STEP 12-1. 新增 errorHandle.js 檔案,放執行錯誤模組
```js=
//此函式內容包含引用headers、response,因此需要引入相關變數或引數
function errorHandle(response){
const headers = {
'Access-Control-Allow-Headers': 'Content-Type, Authorization, Content-Length, X-Requested-With',
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Methods': 'PATCH, POST, GET,OPTIONS,DELETE',
'Content-Type': 'application/json'
};
response.writeHead(400,headers);
response.write(JSON.stringify({
"status":"false",
"message":"欄位未填寫正確,或無此todo id"
}))
response.end();
}
//匯出module
module.exports = errorHandle;
```
* #### STEP 12-2. 引用模組
```js=
const errorHandle = require('./errorHandle'); //錯誤樣態執行程式
//抽換程式碼--------------------------
//POST 新增資料
}else if(request.url=='/todolist' && request.method == "POST"){
request.on('end',()=>{
try{
const title = JSON.parse(body).title;
console.log(title);
if(title !== undefined){
const todo = {
"title":title,
"id":uuidv4()
}
todos.push(todo);
response.writeHead(200,headers);
response.write(JSON.stringify({
"status":"success",
data:todos,
}));
response.end();
//使用自訂模組--------------------------------------
}else{
errorHandle(response);
}
}catch(error){
errorHandle(response);
}
//------------------------------------------------
})
//----------------------------------------------------
```
<br>
> [**Todolist RESTful API : 開發新刪修查的API (實作4) - CRUD ( DELETE API )**](https://hackmd.io/6w2zSZFkRR6G7AUTwEJ4nQ?view)