昨日建立我們的一個後端伺服器,今天來做第一隻API
我們曾在 Day 8 - 一周目- 開始玩轉後端(一) 提及基於 http(s)協定下的Web API (Application Programming Interface)。Web API 常用來:
我們不會涉及太深入的 http(s)協定,只需要基本的了解就可以了。
從瀏覽器的角度看,有兩個訊息會傳送和接收:Request Message 和 Response Message。
他們都有 header 和 body 區塊。header 會記錄一些 Metadata;而 body 是主要要傳送的資料。
Accept: text/html, text/plain
)content-type
header,讓接收端了解資料的格式content-type
header,使送訊息者(前端)了解 body 的格式以下是從 Chrome devtools 截下來的實例:
實際上,不單只有資料,雙方送出的 header 會更多,互動的行為才會更強健(robust)。
上面我們的知道了 content-type
header,會用來告訢接收端資料的格式,方便接收端解讀資料。它可能的值見 Multipurpose Internet Mail Extensions (MIME) type。
我們的前後端架構中,希望後端只送「純」資料給前端,而前端自己才產生HTML,所以我們採用 JSON 格式,它是以易於閱讀的 文字 為基礎,來傳送資料。JSON 的官方定義 MIME 為 application/json
。如下圖:
除了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}]}
./router/index.js
檔案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
...)npm run start
或用 debug 模式執行 ./bin/www
都可以http://localhost:3000/api/sayHi
,就會出現下圖瀏覽器其實是發出一個 GET request,接下來我們驗証看看。
http://localhost:3000/api/sayHi
,就會出現下圖Network
頁籤F12
,就可以開啟你的可能會會跟我不一樣,有些 Chrome 的插件(extension)在開新頁面時也會發出 request
api
就可以過濾sayHi
的 request,可以看到 request 的訊息,像是requst/response/header/body....等。所以我們發現一件事:用瀏覽器開一個網址其實就是打一個 GET request 到伺服器
如果我們想要發出 POST request 怎麼辨?
發出 requests 的工具很多,像是 Advanced REST client, POSTMAN…等,上 google 很容易找到一堆。
我們要使用的是 POSTMAN,他早期也是 google extension 上的一個 app,之後變成一個獨立的程式了,也出現訂閱服務。
但我覺得免費版就夠用了,免費可以
{{host}}
是環境變數,可以在 POSTMAN 中任意切換套用環境組態http://localhost:3000/api/sayHi
,按送出最後回答問題:怎麼發出 POST request呢? 就…換 request method
之前說,我們要傳遞資料的格式是 JSON ,後端要如何送出 JSON 呢? Express 提供方便的函數 res.json()
,幫我們送出 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
,你可以自行驗証看看。
我們利用 POSTMAN 送出 JSON 資料,在 Body 裡要設定使用 JSON 送出,這時 Headers 就會被設定
下圖是完整操作 (注意: object 的屬性要用 "
要包住,字串也是),送出後,伺服器會回應一樣訊息
你可以觀察到, request 和 response 都有設定 content-type: application/json
告之對方資料的格式,以便解讀。
怎麼看後端真的有解讀/了解 JSON 資料呢?
./bin/www
,修改 launch.json
"configurations": [
{
"type": "node",
"request": "launch",
"name": "Launch Program",
"program": "${workspaceFolder}/bin/www"
}
]
POST /api/echo
,後端就會執行 API 的動作,然後停在中斷點body
的型態真的是 Object
!其實,Express 可以解讀 JSON 文字轉成 javascript 的 Object,是因為有套用解讀 json
中間件(middleware)
express.json() 的原因:
你可以註解掉看看,body 就得不到 JSON object 了。中間件(middleware)
會在二周目介紹它,目前只要了解app.use()
會使所有 request 經過 middleware 處理。
今天我們大概說明 request/response 訊息的格式並建立了 APIs,還用 Chrome 監看網路行為(ex:查看 GET request),也用 POSTMAN 手動發出 request (ex: 送出 JSON 資料的 POST request)。