iT邦幫忙

2019 iT 邦幫忙鐵人賽

DAY 9
5
Software Development

用js成為老闆心中的全端工程師系列 第 9

Day 9 - 一周目- 開始玩轉後端(二)

回顧

昨日建立我們的一個後端伺服器,今天來做第一隻API

目標

  1. 自己的第一隻API
  2. 使用 Chrome devTool 查看 requests
  3. POSTMAN 手動發出 requests

你的第一個api

我們曾在 Day 8 - 一周目- 開始玩轉後端(一) 提及基於 http(s)協定下的Web API (Application Programming Interface)。Web API 常用來:

  1. 系統間的介面:不同的系統間用 Web API 來串接,例如:現在很火的 chat bot (Line Messaging API) 的 webhook,由你的系統提供 Web API (即 webhook),當有訊息時,Line 的系統會送 request 給你。
  2. 前後端溝通介面:前後端架構中,後端會定義API,提供給前端網頁用非同步的request,查詢後端API。後端API會集中心力在處理商業邏輯和資料,而前端會集中心力在做畫面和使用者體驗。

API 怎麼帶資料傳送

我們不會涉及太深入的 http(s)協定,只需要基本的了解就可以了。
從瀏覽器的角度看,有兩個訊息會傳送和接收:Request Message 和 Response Message。
他們都有 header 和 body 區塊。header 會記錄一些 Metadata;而 body 是主要要傳送的資料。

  1. HTTP Request Message Format(From: The TCP/IP Guide)
    https://ithelp.ithome.com.tw/upload/images/20181009/20110371hMAchcLCWl.jpg
    1. 是發起查詢的人送出的訊息,像是瀏覽器
    2. 送出headers,內容包含: http(s)/API 的查詢方法(如GET/POST )、客戶端能了解的資料格式(如圖中 Accept: text/html, text/plain)
    3. 送出body:送給接收端(後端)的資料,通常會加入 content-type header,讓接收端了解資料的格式
  2. HTTP Response Message Format(From: The TCP/IP Guide)
    https://ithelp.ithome.com.tw/upload/images/20181009/20110371RpI71H78Da.jpg
    1. 是接收端收到 request message 後做出的回應,像是後端伺服器對API的查詢結果做出回應
    2. 訊息要包含狀態代碼(status code),表示API 的查詢狀態代碼,如:大名鼎鼎的 404,找不到網頁/資源。這狀態代碼後端想傳什麼都可以,但有些狀態代碼有被加入規範中,儘量不要重覆到,因為瀏覽器可能會依照代碼給錯誤訊息。通常 200 是指 request 成功得到正常的 response
    3. 跟 request 一樣,通常會加入 content-type header,使送訊息者(前端)了解 body 的格式

以下是從 Chrome devtools 截下來的實例:
https://ithelp.ithome.com.tw/upload/images/20181009/20110371IFUVdXCPwf.png
https://ithelp.ithome.com.tw/upload/images/20181009/20110371wJsha4Qc5P.png
實際上,不單只有資料,雙方送出的 header 會更多,互動的行為才會更強健(robust)。

body 資料像什麼?

上面我們的知道了 content-type header,會用來告訢接收端資料的格式,方便接收端解讀資料。它可能的值見 Multipurpose Internet Mail Extensions (MIME) type

我們的前後端架構中,希望後端只送「純」資料給前端,而前端自己才產生HTML,所以我們採用 JSON 格式,它是以易於閱讀的 文字 為基礎,來傳送資料。JSON 的官方定義 MIME 為 application/json。如下圖:
https://ithelp.ithome.com.tw/upload/images/20181009/20110371ysne9DikX2.png
除了MIME 外,還用 charset 指明文件的編碼。

很幸運地,javascript 由原始型別(Primitives),像是 string, number, null, boolean, Array, Object, 組成的 object,剛好符合JSON格式。如:

const person = {
  id: '001',
  name: 'Billy',
  married: false,
  friendIds: ['002', '003'],
  accessories: [{
    name: '眼鏡',
    brand: null,
    price: undefined, // 這裡偷放了 `price: undefined`,序列化會自動過濾。
  }],
};

因為object中都是用原始型別組成的 ,所以它們可以正常轉成文串,也就是JSON 可序列化(JSON serializable)

console.log(JSON.stringify(person)); // {"id":"001","name":"Billy","married":false,"friendIds":["002","003"],"accessories":[{"name":"眼鏡","brand":null}]}

來吧!建立第一個API

  1. 打開昨天建的hello-express
  2. ./router/index.js檔案
    https://ithelp.ithome.com.tw/upload/images/20181009/20110371cxrWrzJv9p.png
  3. 建立第一隻 GET API
    var express = require('express');
    var router = express.Router();
    
    /* GET home page. */
    router.get('/', function(req, res, next) {
      res.render('index', { title: 'Express' });
    });
    
    router.get('/api/sayHi', function(req, res, next) {
      res.send('hi');
    });
    
    module.exports = router;
    
    router.get 表示接受來自 GET 的 request,其它的以些類推 (ex: router.post, router.delete...)
  4. 執行伺服器 npm run start 或用 debug 模式執行 ./bin/www 都可以
  5. 開啟瀏覽器,進入 http://localhost:3000/api/sayHi,就會出現下圖
    https://ithelp.ithome.com.tw/upload/images/20181009/20110371t9SU3Wwc0F.png

瀏覽器其實是發出一個 GET request,接下來我們驗証看看。

從Chrome 瀏覽器看 request

  1. 開啟瀏覽器,進入 http://localhost:3000/api/sayHi,就會出現下圖
  2. 開 devTools 後,選 Network 頁籤
    在空白處右建
    https://ithelp.ithome.com.tw/upload/images/20181009/20110371uFOECOkSIZ.png
    或按鍵盤F12,就可以開啟
    https://ithelp.ithome.com.tw/upload/images/20181009/20110371jwc7nrItrw.png
  3. 是空的! 別怕只要刷新再開一次就好,因為開啟 devTools 後才會記錄
    https://ithelp.ithome.com.tw/upload/images/20181009/20110371WO5lLJG7cW.png
    出現一堆 request,哪個才是我們的呢?

    你的可能會會跟我不一樣,有些 Chrome 的插件(extension)在開新頁面時也會發出 request

  4. 過濾 request:在上面有個小框框,輸入 api 就可以過濾
    https://ithelp.ithome.com.tw/upload/images/20181009/20110371AbsvXt9Ky3.png
  5. 點擊 sayHi 的 request,可以看到 request 的訊息,像是requst/response/header/body....等。
    https://ithelp.ithome.com.tw/upload/images/20181009/20110371Zjlaec4Wog.png

所以我們發現一件事:用瀏覽器開一個網址其實就是打一個 GET request 到伺服器

如果我們想要發出 POST request 怎麼辨?

如何手動發出 requests?

發出 requests 的工具很多,像是 Advanced REST client, POSTMAN…等,上 google 很容易找到一堆。

我們要使用的是 POSTMAN,他早期也是 google extension 上的一個 app,之後變成一個獨立的程式了,也出現訂閱服務。
https://ithelp.ithome.com.tw/upload/images/20181009/20110371qAm4YjS3kK.png

但我覺得免費版就夠用了,免費可以

  1. 模擬一個 request,設定 header, body…等
  2. 儲存每個 request,也可以命名、加 Markdown 描述,甚至是存下回應後的結果
  3. 有送出 request 的歷史清單
  4. request 打包成 collection(可想成是一個資料夾放一群 request)
    https://ithelp.ithome.com.tw/upload/images/20181009/20110371O2o0uJliRN.png
  5. 匯入/出collection
  6. 環境變數
    https://ithelp.ithome.com.tw/upload/images/20181009/20110371BBQMkBPzTi.png
    {{host}} 是環境變數,可以在 POSTMAN 中任意切換套用環境組態
  7. 同步request資料在連結的 Google 帳號中

使用 POSTMAN 發送 GET request

  1. 下載 POSTMAN
  2. 建立一個 request,按 + 號
    https://ithelp.ithome.com.tw/upload/images/20181009/201103712FfIfAPaHc.png
  3. 輸入 http://localhost:3000/api/sayHi,按送出
    https://ithelp.ithome.com.tw/upload/images/20181009/20110371xeN3tKmgT9.png
  4. 就得到和瀏覽器一樣的結果
    https://ithelp.ithome.com.tw/upload/images/20181009/20110371jtSOVkQtLd.png
    跟 Chrome 一樣可以看到 request/response 的資料

最後回答問題:怎麼發出 POST request呢? 就…換 request method
https://ithelp.ithome.com.tw/upload/images/20181009/20110371NSam0hmNa7.png

JSON 格式交互資料

之前說,我們要傳遞資料的格式是 JSON ,後端要如何送出 JSON 呢? Express 提供方便的函數 res.json(),幫我們送出 JSON資料的回應資料。

後端再加一個 POST API:回應 JSON 資料

./router/index.js檔案,加入下面 POST API

router.post('/api/echo', function(req, res, next) {
  const body = req.body;
  res.json(body);
});

這隻 API 做的事情很單純:把 request 的 body 資料,再以 JSON 格式回應回去。

res.json() 回應時,Express會自動在 response header 中加入 content-type: application/json,不同於res.send()送出content-type: text/html,你可以自行驗証看看。

前端打 POST API:送出帶有 JSON 資料

我們利用 POSTMAN 送出 JSON 資料,在 Body 裡要設定使用 JSON 送出,這時 Headers 就會被設定
https://ithelp.ithome.com.tw/upload/images/20181009/20110371EdpYv4altQ.png

下圖是完整操作 (注意: object 的屬性要用 " 要包住,字串也是),送出後,伺服器會回應一樣訊息
post request

你可以觀察到, request 和 response 都有設定 content-type: application/json 告之對方資料的格式,以便解讀。
https://ithelp.ithome.com.tw/upload/images/20181009/20110371l51wPt9Euv.png

用 debug 模式驗証伺服器真有收到 JSON 資料

怎麼看後端真的有解讀/了解 JSON 資料呢?

  1. 設定 VSCode debug 執行 ./bin/www,修改 launch.json
    "configurations": [
        {
          "type": "node",
          "request": "launch",
          "name": "Launch Program",
          "program": "${workspaceFolder}/bin/www"
        }
    ]
    
  2. 下中斷點,再用 POSTMAN 再送出一次 POST /api/echo,後端就會執行 API 的動作,然後停在中斷點
    https://ithelp.ithome.com.tw/upload/images/20181009/20110371P8jJD4EsEC.png
    body 的型態真的是 Object!

其實,Express 可以解讀 JSON 文字轉成 javascript 的 Object,是因為有套用解讀 json 中間件(middleware) express.json() 的原因:
https://ithelp.ithome.com.tw/upload/images/20181009/201103714X0j3sLQaz.png
你可以註解掉看看,body 就得不到 JSON object 了。中間件(middleware) 會在二周目介紹它,目前只要了解 app.use() 會使所有 request 經過 middleware 處理。

總結

今天我們大概說明 request/response 訊息的格式並建立了 APIs,還用 Chrome 監看網路行為(ex:查看 GET request),也用 POSTMAN 手動發出 request (ex: 送出 JSON 資料的 POST request)。


上一篇
Day 8 - 一周目- 開始玩轉後端(一)
下一篇
Day 10- 一周目- 開始玩轉前端(一)
系列文
用js成為老闆心中的全端工程師31
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

1 則留言

2
神Q超人
iT邦研究生 5 級 ‧ 2018-10-09 22:44:00

文章內容很豐富!
大大要繼續加油!帶來優質好文XD

我要留言

立即登入留言