---
# System prepended metadata

title: Todolist RESTful API

---

六角體驗營
# Todolist RESTful API : 開發新刪修查的API (實作2) - CRUD  ( GET / POST  API )
> [**node.js - Todolist RESTful API : 開發新刪修查的API (實作1) - 環境設置**](https://hackmd.io/CVSnuG_jQgiYvHta5lq7-w?view)

<br>

## 7. API 介紹
> RESTful API 功能列表(CRUD): 
> * GET 取得所有待辦事項
> * POST 新增單筆待辦事項
> * PATCH 編輯指定待辦事項
> * DELETE 刪除 ( 所有 / 指定 ) 代辦事項

* #### STEP 7-0. POSTMAN 管理 API 列表
  * 新增collection、request 請求 API
  ![](https://hackmd.io/_uploads/SkajB_p-T.png)


* #### STEP 7-1. GET API 取得所有代辦
    
    ```js=
    const http = require('http');

    //1. 新增陣列放資料(一般是資料庫中數據)------
    const todos = [
        {
            "title":"幫全家人買早餐"
        }
    ]
    //----------------------------------------

    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'
        };

        //2. 定義url路徑------------------------------------------
        if(request.url=='/todolist' && request.method == "GET"){
            response.writeHead(200,headers); 
            response.write(JSON.stringify({
                "status":"success",
                data:todos,   //3. 回傳數據改為陣列資料取代
            }));
            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);
    ```
    
    
* #### STEP 7-2. 安裝 uuid 的 npm
  安裝完檢查package.json有無新增 
  ``` terminal=
  npm install uuid --save
  ```

* #### STEP 7-3. 將 id 由 uuid 生成
  > [create uuid 文件](https://www.npmjs.com/package/uuid?activeTab=readme)
  
    ```js=
    //1. 使用 uuid 套件
    const { v4: uuidv4 } = require('uuid');
    //uuidv4();

    //2. 陣列物件中新增id資料
    const todos = [
        {
            "title":"幫全家人買早餐",
            "id": uuidv4(); //暫時測試使用
        },
        {
            "title":"百貨公司周年慶",
            "id": uuidv4(); //暫時測試使用
        }
    ]
    ```
* #### STEP 7-4. terminal 執行，postman get 測試 -> 成功回傳 data
  > * 若伺服器沒有關閉，且todos資料沒有修改，網頁重整不會影響 uuid 的數據 (暫存於記憶體)
  > * 若原始資料修改 或 重新開啟伺服器(node.js)，uuid 會重新生成
  
  ![](https://hackmd.io/_uploads/SkSRCvpb6.png)

<br>

## 8. POST API router 環境建立
* #### STEP 8-1. 新增 POST 方法的情況 在else if 函式

    ```js=
    const http = require('http');
    const todos = [
        {
            "title":"幫全家人買早餐"
        }
    ]

    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'
        };


        if(request.url=='/todolist' && request.method == "GET"){
            response.writeHead(200,headers); 
            response.write(JSON.stringify({
                "status":"success",
                data:todos,   //3. 回傳數據改為陣列資料取代
            }));
            response.end();

        //新增POST方法在else if情況中------------------------------------------------------ 
        }else if(request.url=='/todolist' && request.method == "POST"){
            response.writeHead(200,headers); 
            response.write(JSON.stringify({
                "status":"success",
                data:todos,   //3. 回傳數據改為陣列資料取代
            }));
            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);
    ```
* #### STEP 8-2. postman 測試 POST 方法
  ![](https://hackmd.io/_uploads/Byhbzdp-6.png)

<br>

## 9. TCP/IP Buffer 傳送 (接收chunk組成的body資料)
> [TCP/IP說明筆記](https://hackmd.io/Jgc4Q5YBRIaOjzr8oIX-Ig?view)
* #### STEP 9-1-1. 修改requestListener
  * 透過 **request.on('end',()={})** 可接收body資料 
  ```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'
        };
        
  //新增TCP傳輸函示-------------------------------------------------
        
        //定義body接資料
        let body ="";
        
        //若有data資料發出請求時觸發
        request.on('data',(chunk)=>{ //chunk取值
            console.log(chuck);  //觀察chunk > <Buffer 7b 0d 0a 20 20 20 20 22 74 69 74 6c 65 22 3a 22 e5 b9 ab e5 ae b6 e4 ba ba e8 b2 b7 e6 97 a9 e9 a4 90 22 0d 0a 7d> 
            body += chunk; //chunk組成要傳送的body
        })
        
        //body 資料全收到後時觸發 -> 將body中的資料印出觀察
        request.on('end',()=>{
            console.log(typeof body); //觀察資料格式 >string
            console.log(JSON.parse(body).title); //解析string為JSON -> 幫家人買早餐
        })
        
  //-----------------------------------------------------------------

        if(request.url=='/todolist' && request.method == "GET"){
            response.writeHead(200,headers); 
            response.write(JSON.stringify({
                "status":"success",
                data:todos,  
            }));
            response.end();

        }else if(request.url=='/todolist' && request.method == "POST"){
            response.writeHead(200,headers); 
            response.write(JSON.stringify({
                "status":"success",
                data:todos,   
            }));
            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);
  ```
 <br>
* #### STEP 9-1-2. postman 測試 
  * 使用 POST API
  * 選擇 BODY 
  * POST 資料格式改為 raw / JSON
  ![](https://hackmd.io/_uploads/rJ8xJqTbT.png =80%x)

<br>

## 10. 新增資料 POST API

* #### STEP 10-1-1. 將on('end')執行內容移到 POST 方法中
  ```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; 
        })
  //--------------------------------------------------------
        //將request.on('end',執行內容移到POST方法中)
  //-----------------------------------------------------------------

        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"){
            
            //資料接收到並組成body後執行
            request.on('end',()=>{
                
                //取得物件中title的資訊
                const title = JSON.parse(body).title; //解析string為JSON
                onsole.log(title); //送coffee去洗澡
                
                //回覆文字以JSON字串格式印到網頁上
                response.writeHead(200,headers); 
                response.write(JSON.stringify({
                    "status":"success",
                    data:todos,   
                }));
                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);
  ```
<br>

* #### STEP 10-1-2. postman 測試 
  * 使用 POST API
  * 選擇 BODY 
  * POST 資料格式改為 raw / JSON
    ![](https://hackmd.io/_uploads/H1UCfL8Mp.png)
    

* #### STEP 10-2. 傳送todo物件資料{}
  ```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"){
            
            //資料接收到並組成body後執行
            request.on('end',()=>{
                
                //取得物件中title的資訊
                const title = JSON.parse(body).title; //解析string為JSON
                onsole.log(title); //送coffee去洗澡
                
                //回覆文字以JSON字串格式印到網頁上
                response.writeHead(200,headers); 
                response.write(JSON.stringify({
                    "status":"success",
                    data:todos,   
                }));
                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);
  ```
  <br>
  
* #### STEP 10-3-1. 將POST的資料傳送進todos
  * 將POST的資料放入單筆todo資料{}中
  *  將todo{}資料push進todos陣列中
  
    ```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"){
            
            //資料接收到並組成body後執行
            request.on('end',()=>{
                
                //取得物件中title的資訊
                const title = JSON.parse(body).title; //解析string為JSON
                console.log(title); //送coffee去洗澡

                const todo = {
                    "title":title, //放POST的JSON資料
                    "id":uuidv4()
                }
                //將todo內容放入todos[]中
                todos.push(todo);
                
                //回覆文字以JSON字串格式印到網頁上
                response.writeHead(200,headers); 
                response.write(JSON.stringify({
                    "status":"success",
                    data:todos,  //回應會顯示todos陣列中資料(已經push進去的) 
                }));
                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);
    ```

<br>

* #### STEP 10-3-2. postman傳送(POST)
  * 接收到todos中的資料，回傳到data中
  ![](https://hackmd.io/_uploads/HyQiFDLza.png =80%x)
  
 <br>

> 接續 : 
> [**Todolist RESTful API : 開發新刪修查的API (實作3) - POST API 資料錯誤樣態**](https://hackmd.io/6c02HxuUR5CLhX5K5vgVBg?view)