nodejs_restful_api_tutorial

Node.js RESTful API 實例教學: 簡單 To Do List

REST 全稱是 Representational State Transfer,中文翻譯為具象狀態傳輸,是一種 Web 應用程式架構風格,由於它的簡潔性,近年越來越多人採用。它的重點是,資料由 URI 指定,並通過 HTTP 提供的 POST , GET 等方法進行操作。符合REST設計風格的 Web API 稱為 RESTful API。Node.js 對 REST 是非常有善,也就是說使用 Node.js 來建立 RESTful API 是很容易的事情。

REST是設計風格而不是標準。REST通常基於使用HTTP,URI,和XML以及HTML這些現有的廣泛流行的協議和標準。

  • 資源是由URI來指定。
  • 對資源的操作包括獲取、創建、修改和刪除資源,這些操作正好對應HTTP協議提供的GET、POST、PUT和DELETE方法。
  • 通過操作資源的表現形式來操作資源。
  • 資源的表現形式則是XML或者HTML,取決於讀者是機器還是人,是消費web服務的客戶軟體還是web瀏覽器。當然也可以是任何其他的格式。

維基百科

在這個練習中,我們要實現一個簡單的 RESTful API 伺服器,提供待辦事項列表(To do List)的各種操作,包括:

  1. 建立一個待辦事項
    操作方式:POST;
    Endpoint:/todo;
  2. 讀取一個待辦事項
    操作方式:GET
    Endpoint:/todo/:id;
  3. 刪除一個待辦事項
    操作方式:DELETE
    Endpoint:/todo/:id;
  4. 讀取整個待辦事項列表
    操作方式:GET
    Endpoint:/todo,。
  5. 更新一個待辦事項
    操作方式:PUT,
    Endpoint:/todo/:id;

Endpoint 是指網址最後的部分,例如,POST的網址會是:localhost:3000/todo 。

目錄

  1. npm init:建立新專案
  2. 建立伺服器
  3. RESTful POST 新增一個待辦事項
  4. RESTful GET 讀取一個待辦事項
  5. RESTful DELETE 刪除一個待辦事項
  6. RESTful GET 讀取整個待辦事項列表
  7. RESTful PUT 更新一個待辦事項
  8. 總結
  9. 下載程式碼
  10. Change Log

1. npm init:建立新專案

首先,用 npm init  一個新的 project 。這個指令可以協助你建立一個 package.json 檔案,裡面包含這個 project 的配置資訊,之後要修改配置可以直接改這個檔案。作為練習,我們可以一直按 Enter,使用預設的配置。

npm_init_nodejs_restful

2. 建立伺服器

在這個練習中,我們會使用到 http 跟 router 兩個 modules,分別用來建立伺服器與處理路由。http 是 Node.js 內置的,但 router 則需要透過 npm 安裝,在 project 的目錄下跑一次以下指令:

等 router 安裝完成後,新增一個 server.js 檔案,加入以下程式。這段程式的功能是建立一個 server,監聽 port 3000,並用 router 對錯誤進行簡單的處理。

然後,回到 Command Line,執行:

會看到 server 成功運行。用瀏覽器打開:localhost:3000,會看到空白頁面,Command Line 沒有特別訊息,代表一切正常。 No news is good news。

3. RESTful POST 新增一個待辦事項

正常來講,待辦事項應該儲存在資料庫裡,但這裡我們只用一個 Array 在存放。以下程式都放在 server.js 裡面:

接著,我們要處理第一個路由: /todo,新增一個待辦事項:

首先,我們建立一個函式來處理 /todo 路由,這個函式就是這個路由的 handler。在函式裡,我們把計數器加 1 ,以追蹤待辦事項總數。接著,把項目 id 回應出去。最後一行,可以看到,我們要處理的是 POST 的請求(router.post),要針對的Endpoint 是 /todo ,使用的 handler 是剛剛建立的 createItem 函式。

由於這裡處理的是 POST 的請求,我們無法直接用瀏覽器查看效果,而要使 curl 或者一些瀏覽器的 REST 工具,像是:Advanced REST Client 等,這裡我們用 curl 。打開一個新的 Command Line (原本 Server 所在的 Command Line 不能關掉),輸入以下指令:

注意, X 是大寫,指令很簡單,就是向後面的網址執行 POST 請求。馬上你就會得到 Item 1 這個訊息作為回應,同時,server 所在的 Command Line 會得到訊息:Create Item 1。把這個指令多執行幾次,會看到 Item 數的累加。

3.1 Body Parser

剛剛新增的項目只有編號,並沒有俱體內容。我們希望能夠通過 RESTful API 把項目內容也傳過去,這意味著,伺服器(server.js)那邊要能夠解釋傳進來的資料。要完成這個任務,可以借助 body-parser 這個 module。

首先在 server.js 的開頭 require 這個 module:

接著在 server.listen() 之後用 router.use() 來執得解釋,目標是解釋成純文本:

接著,修改一下 createItem() 函式,把項目的內容記錄下來:

我們用 request.body 取得請求送過來的資料,將之存放在 item 裡面,也順便把 item 存到 todoList 裡面,以備後面的讀取使用。接著,我們會回應的時候,使用 Location 把網址轉向 /todo/:id,也就是這個項目的網址。最後,將 item 內容回應出去。

重新運行 server.js。

為了測試這部分,curl 指令要傳送資料,改為:

分解一下這個指令:

  • -X POST:指令用 POST 方式,預設是 GET;
  • –data ‘buy milk’:這就是我們要傳送的資料;
  • –header ‘Content-Type: text/plain’:在 header 說明一下,資料格式是純文本:text/plain。
  • http://localhost:3000/todo:這是我們要送達的目標地址。
  • -v:最後我加上了這個設定,要求 curl 顯示完整資訊:

    可以看到,在第二段,也就是回應(response)的部分,有一項 Location: /todo/1,這就是我們在 response.writeHead() 裡指定的。

執行這個指令之後,會得到 buy milk 的回應,也就是 response.end() 傳回來的 item。同時 server.js 那邊會得到:Create item  1 buy milk。意味著資料成功送到。

4. RESTful GET 讀取一個待辦事項

接下來,我們要通過 /item/:id 這個網址來讀取單一個待辦事項,在 server.js 最後加上以下程式:

可以看到,要取得請求網址裡的 id ,可以用 request.params.id ,接著利用這個 id 從 todoList 裡取出相對應的項目,再送到回應。要注意的是這裡的用的是 router.get() 而不是 POST,而 Endpoint 的寫法是: /todo/:id ,冒號後面的 id 就是 request.params.id 。

中間的 if 則是判斷 item 存不存在。不存在的話,直接回應一個 404 ,把程式結束掉。

接著要測試這段程式,使用的 curl 指令更簡單:

你在運行讀取之前,記得先用之前的新增指令,建立新的待辦事項,不然沒東西可讀。而我們目前的做法是沒有將資料存進資料庫,因此每次運行程式, todoList 都是空的。

5. RESTful DELETE 刪除一個待辦事項

刪除跟讀取是非常類似,同樣把以下程式加到 server.js 裡面:

我們直接把 todoList 裡對應 id 的項目設為 undefined ,使之無效,response 則是什麼也不用傳回。而 router 那邊則使用 .delete() 來處理。

同樣地,中間用了 if 來判斷 item 存不存在。

測試用的 curl 指令如下:

最後的 1 是 id ,記得先新增才有辦法刪除。

6. RESTful GET 讀取整個待辦事項列表

最後,我們要實現的是讀取整個待辦事項列表的功能。

這裡我們用了 itemList 來儲存有效的待辦事項。用 For…in 遍歷整個 todoList,並通過兩個判斷來找出所有有效的待辦事項,找到後 push 到 itemList 裡面:

  1. if ( !todoList.hasOwnProperty( id ) )  :判斷這個 id 是否存在,不存在就馬上換下一個 id;
  2. if ( typeof item !== 'string' )  :判斷這個 id 的項目是否有效,也就是有沒有被刪除,如果無效,馬上換一下個 id 。

接著就要把得到的列表送到 Console 以及 response。Console 方面,這裡用了一個 JSON.stringify() 函式將資料以 JSON 字串的形式顯示出來。Response 方面,我們用換行( ‘\n’ )將 Array 裡面的字串組合成一字串,並存放在 listString 裡面,最後把 listString 送出。

Router 方面用 .get() 來處理,Endpoint 是 /todo。

測試用的 Curl 指令如下:

沒什麼特別,直接用預設的 GET 方式打開 /list。執行這一句之前,記得先新增一些待辦事項,不然就沒東西可以列出。

7. 更新一個待辦事項

更新跟新增很像,只是在 Endpoint 已經把 id 給你,所以你不需要把 counter 加 1 ,反而要檢查這個 id 是不是存在於列表中,這就跟讀取的檢查一樣。另外,跟新增一樣,更新後,可以將 Endpoint 傳回,也就是把 Location 設為 /todo/:id。而最後 router 使用的是 PUT 操作。

測試用的 curl 指令:

跟新增差不多,只是操作方法改為了 PUT,URI 最後加上 id。

Node.js RESTful API Todo List

8. 總結

在這個例子中,我們練習了:

  1. 三個常用的 Node.js 模組:http, router, bady-parser。
  2. Router 的 GET, POST, DELETE 操作。
  3. 用 curl 來對 RESTful API 進行測試。
  4. 使用 body-parser 解釋 POST 傳送過來的資料。

這個例子還可以繼續加強地方有:

  1. 用戶認證。也就是要提供用戶帳號密碼才可以進行任何操作。
  2. 使用資料庫儲存待辦事項。
  3. 重構程式(Refactoring),例如,檢查項目是否存在的判斷重覆出現,可以把它寫成函式。

9. GitHub:下載程式碼

你可以到 GitHub 上下載程式碼。

GitHub 下載

若有任何問題或疑問的,歡迎在下面留言提出。

9. Change log

  • 03 Mar: 加入 Update 操作
  • 02 Mar: 更新 Endpoint 為: /todo

參考

分享到: