本篇會介紹如何用 request 這套 library 在 node.js上串接 API,實作的部份也是程式導師計畫第四週的內容及作業:
基礎知識
因為我們要使用 npm 上 request 這套 library,首先第一步是要確認有安裝 node.js ,並初始化 npm,npm 簡易教學可以參考這篇,之後就可以用 npm install request 來安裝這套 library 啦。
完成安裝後,我們先來查找 request 的文件來看看怎麼發最基本的 GET request
結果文件的第一行就寫得很清楚了 XDD
- 宣告一個變數來引入 request 之後
- request 的第一個參數是要串接 API 的 url,第二個參數是箭頭函式,可以取得 response, error, statusCode 和 body 等資料都放在這裡。
- 讓我們加入 try... catch 來處理成功和失敗的狀況吧,於是 test_api.js 這支程式碼會像這樣:
const request = require('request');
request.post(
'https://example.com,
(error, response, body) => {
let data;
try {
data = JSON.parse(body);
//如果成功就把 body 轉成 JSON 物件
} catch (err) {
console.log('API抓取錯誤', error);
return;
// 如果失敗就顯示 API 抓取錯誤並跳出
}
console.log(data);
// 印出接收到的 data
},
);
在使用終端機輸入 node test_api.js 執行程式,就可以得到回傳的 response data 了~
寫作業啦
有了初步的串接 API 的知識之後,我們來做做看程式導師計畫第四週的作業吧~
API 文件
Base URL: https://lidemy-book-store.herokuapp.com
說明 | Method | path | 參數 | 範例 |
---|---|---|---|---|
獲取所有書籍 | GET | /books | _limit:限制回傳資料數量 | /books?_limit=5 |
獲取單一書籍 | GET | /books/:id | 無 | /books/10 |
新增書籍 | POST | /books | name: 書名 | 無 |
刪除書籍 | DELETE | /books/:id | 無 | 無 |
更改書籍資訊 | PATCH | /books/:id | name: 書名 | 無 |
hw1:來自秋秋鞋的任務
有一天,住你隔壁的鄰居秋秋鞋跑來按門鈴,說有事想要找你討論,他最近在做一個知識型的 YouTube 頻道,可是快要沒有靈感了。
這時,他想到一個好主意!他只要能夠看到書店提供的書籍相關資訊,就可以從中汲取靈感,之後就可以發想相關題材,頻道就不會一直不更新了。
身為秋秋鞋的好朋友,這個重責大任當然就交給你了!
請閱讀開頭給的 API 文件並串接,用 node.js 寫出一個程式,執行後會在 console 列出前十本書籍的 id 以及書名。
範例:
node hw1.js1 克雷的橋
2 當我想你時,全世界都救不了我
3 我殺的人與殺我的人
....
所以要獲取所有書籍,可以參考 API 文件使用 GET 方法,對應的 path 就是 /books
我們就使用剛才學會的 request 來串串看吧
const request = require('request');
request.get(
'https://lidemy-book-store.herokuapp.com/books?_limit=10',
(error, response, body) => {
let data;
try {
data = JSON.parse(body);
} catch (err) {
console.log('API抓取錯誤', error);
return;
}
console.log(data)
}
},
);
拿到之後,直接 node hw1.js 把資料印出來看看有沒有成功,結果獲得一個陣列...
[
{ id: 1, name: '克雷的橋' },
{ id: 2, name: '當我想你時,全世界都救不了我' },
{ id: 3, name: '我殺的人與殺我的人' },
{ id: 4, name: '念念時光真味' },
{ id: 5, name: '蜂蜜花火【致年少時光‧限量插畫設計書衣典藏版】' },
{ id: 6, name: '苦雨之地' },
{ id: 7, name: '你已走遠,我還在練習道別' },
{ id: 8, name: '想把餘生的溫柔都給你' },
{ id: 9, name: '你是我最熟悉的陌生人' },
{ id: 10, name: '偷書賊(25萬本紀念版本)' }
]
現在要思考怎麼輸出成作業要求的格式,有 10 筆資料要輸出,哦哦,可以用迴圈印出每筆資料的 id 和書名
第 i 筆資料就是 data[i],它的 id 就是 data[i].id,而書名就是 data[i].name(如果不熟可以回去複習 JavaScript 物件和陣列的概念),所以我們就可以這樣寫:
const request = require('request');
request.get(
'https://lidemy-book-store.herokuapp.com/books?_limit=10',
(error, response, body) => {
let data;
try {
data = JSON.parse(body);
} catch (err) {
console.log('API抓取錯誤', error);
return;
}
for (let i = 0; i < data.length; i += 1) {
console.log(`${data[i].id} ${data[i].name}`);
}
},
);
就可以拿到結果啦
λ node test.js
1 克雷的橋
2 當我想你時,全世界都救不了我
3 我殺的人與殺我的人
4 念念時光真味
5 蜂蜜花火【致年少時光‧限量插畫設計書衣典藏版】
6 苦雨之地
7 你已走遠,我還在練習道別
8 想把餘生的溫柔都給你
9 你是我最熟悉的陌生人
10 偷書賊(25萬本紀念版本)
hw2:最後的考驗
原本以為上次就已經是最後一次幫忙,沒想到秋秋鞋還是又跑來找你了。他說他想要更多功能,他想把這整個書籍資料庫當作自己的來用,必須能夠顯示前 20 本書的資料、刪除、新增以及修改書本,這樣他就可以管理自己的書籍了。
(跟 hw1 不同,之前是 10 本,這次要顯示 20 本)
雖然你很想問他說為什麼不用 Excel 就好,但你問不出口,再加上你最近剛學程式需要練習的機會,於是你就答應了。
請閱讀開頭給的 API 文件並串接,用 node.js 寫出一個程式並接受參數,輸出相對應的結果,範例如下:
node hw2.js list // 印出前二十本書的 id 與書名
node hw2.js read 1 // 輸出 id 為 1 的書籍
node hw2.js delete 1 // 刪除 id 為 1 的書籍
node hw2.js create "I love coding" // 新增一本名為 I love coding 的書
node hw2.js update 1 "new name" // 更新 id 為 1 的書名為 new name
作業二的精華在於要怎麼在終端機輸入不同命令以呼叫不同的 API 功能,可以利用 process.argv 這個陣列拿到對應的參數:
把 process.argv 這個陣列利用 console.log 印出來之後有人驚人的發現
以 node test.js 這行終端機指令來說,process.argv[0] 就是 node,prcess.argv[1] 就是 test.js,所以也就是說,我們可以在自訂義之後的參數,然後利用 if 判斷式來判斷 prcess.argv[2] 是 list, read, delete, create 還是 update,來做不同的 path 串接,如此一來....
可以先把執行的這些參數的位置都宣告成變數
/* eslint-disable no-unused-vars */
const request = require('request');
const action = process.argv[2];
const parameter = process.argv[3];
const parameterTwo = process.argv[4];
const APIUrl = 'https://lidemy-book-store.herokuapp.com';
當執行參數是什麼,我們就執行對應的什麼函式以呼叫 API
switch (action) {
case 'list':
listBook();
break;
case 'read':
readBook(parameter);
break;
case 'delete':
deleteBook(parameter);
break;
case 'create':
createBook(parameter);
break;
case 'update':
updateBook(parameter, parameterTwo);
break;
case 'manual':
manual();
break;
default:
console.log('可執行的指令: list, read, delete, create, update, manual');
console.log('執行指令 node hw2.js manual 可查看各指令用法');
}
接下來就只是把不同的 call API 方法包在一個個函式裡面等待我們執行的時候去呼叫啦
function listBook() {
request.get(
`${APIUrl}/books?_limit=20`,
(error, response, body) => {
let data;
try {
data = JSON.parse(body);
} catch (err) {
console.log('API抓取錯誤', error);
return;
}
for (let i = 0; i < data.length; i += 1) {
console.log(`${data[i].id} ${data[i].name}`);
}
},
);
}
function readBook(id) {
request.get(
`${APIUrl}/books/${id}`,
(error, response, body) => {
let data;
try {
data = JSON.parse(body);
} catch (err) {
console.log('API抓取錯誤', error);
return;
}
console.log(`${data.id} ${data.name}`);
},
);
}
function deleteBook(id) {
request.delete(
`${APIUrl}/books/${id}`,
(error, response, body) => {
try {
console.log('刪掉啦');
} catch (err) {
console.log('沒刪到', error);
}
},
);
}
function createBook(name) {
request.post({
url: `${APIUrl}/books`,
form: {
name,
},
}, (error, response, body) => {
try {
console.log(`《${name}》新增成功`);
} catch (err) {
console.log('新增失敗', error);
}
});
}
function updateBook(id, name) {
request.patch({
url: `${APIUrl}/books/${id}`,
form: {
name,
},
}, (error, response, body) => {
try {
console.log(`${id} 已修改為 ${name}`);
} catch (err) {
console.log('修改失敗', error);
}
});
}
function manual() {
console.log('list (列出前 20 本書的 id 及書名)');
console.log('read x (輸出id為x的書)');
console.log('delete x (刪除 id 為 x 的書)');
console.log('create name (新增一本名為 name 的書)');
console.log('update x n(更新 id 為 x 的書為 n)');
}
雖然實作上有點麻煩,但只要掌握 process.argv 這個陣列的使用應該就比較容易了吧 ^__^