六角體驗營 # 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 會回傳錯誤代碼(下圖) ![](https://hackmd.io/_uploads/HyyqQTLMa.png) * #### 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格式 ![](https://hackmd.io/_uploads/SJ7hU6IzT.png) **格式錯誤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 執行必要欄位檢驗)| | -------- | | ![](https://hackmd.io/_uploads/HyuwsTLM6.png) | * 將錯誤代碼使用 if...else 寫在 try 區塊 ( 如 **step 11-3.** ) |修改後: 使用POST方法 (try區塊將必要屬性放在if執行內容,else 錯誤資訊回傳) | | -------- | | ![](https://hackmd.io/_uploads/ByO92T8f6.png) | <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)