Skip to content
坑坑洞洞
Github

給自己看的 HTML 超基礎

程式導師計劃, coding 筆記6 min read

前言

緩慢看完 [NET101] 網路基礎概論(搭配 JS 實作練習) 後覺得不太扎實,果然一寫到作業就掛掉了。這幾篇會用 第四週作業 來整理 JavaScript 實際串接 API 時會用到的語法和觀念。

API 是什麼?

API 全名為 Application Programming Interface,中文翻譯為「應用程式介面」。簡單來說就是交換資料的管道。想知道更多可以看 從拉麵店的販賣機理解什麼是 API

直接來寫作業ㄅ

API 文件 Base URL: https://lidemy-book-store.herokuapp.com

說明Methodpath參數範例
獲取所有書籍GET/books&lt_limit:限制回傳資料數量/books?&lt_limit=5
獲取單一書籍GET/books/:id/books/10
新增書籍POST/booksname:書名
刪除書籍DELETE/books/:id
更改書籍資訊PATCH/books/:idname: 書名

hw1:來自秋秋鞋的任務

有一天,住你隔壁的鄰居秋秋鞋跑來按門鈴,說有事想要找你討論,他最近在做一個知識型的 YouTube 頻道,可是快要沒有靈感了。 這時,他想到一個好主意!他只要能夠看到書店提供的書籍相關資訊,就可以從中汲取靈感,之後就可以發想相關題材,頻道就不會一直不更新了。 身為秋秋鞋的好朋友,這個重責大任當然就交給你了! 請閱讀開頭給的 API 文件並串接,用 node.js 寫出一個程式,執行後會在 console 列出前十本書籍的 id 以及書名。 順帶一提,叫做秋秋鞋是因為他很喜歡秋天。

把東西抓下來:requst

資料來源: 官網 MDN

首先,我們要下載 request 的 npm:

npm install requst --save

request 的基本用法為:

request(input, init)

通常 input 為目標網址,例如官網上提供的範本為:

const request = require('request');
request('http://www.google.com', function (error, response, body) {
console.error('error:', error);
console.log('statusCode:', response && response.statusCode);
console.log('head:', response.headers);
console.log('body:', body);
});

初步整理資料:JSON

剛抓下來的資料會以 JSON 呈現。 JSON 全名 JavaScript Object Notation ,和 JS 中物件很像,只是不管是 key 還是 value 都要用雙引號 " 框起來,而整體是個字串。 JSON 轉物件 參考資料: MDN JSON.parse() 可以將 JSON 轉成物件,第一個參數放欲轉換的 JSON ,後面可以指示如何選擇結果。例如

const json = {
name: 'jason',
age: '23',
phone: '0922',
};
// 排除 age
const obj = JSON.parse(json, (key, value) => {
if (key === 'age') return undefined;
return value;
});
//{name: "jason", phone: "0922"}

物件轉 JSON 參考資料: MDN 與此相對的, JSON.stringify() 可將物件轉換成 JSON 格式。第一個參數一樣放物件,後面則是結果的轉換標準。

const obj = {
name: 'jason',
age: '23',
phone: '0922',
};
// 排除 age
const json = JSON.stringify(obj, (key, value) => {
if (key === 'age') return undefined;
return value;
});
//{"name": "jason", "phone": "0922"} <= 這是字串

try...catch

參考資料: MDN try...catch 可用於程式中可能出錯處,主動捕捉錯誤,並防止整個程式因錯誤而停擺。用法如下:

try {
// 預期可能會發生錯誤的程式碼
} catch (e) {
// try 區塊有拋出錯誤時,則執行這裡的程式碼
} finally {
// finally 區塊的程式碼一定會在最後被執行
// 可以省略 finally 區塊
}

回頭看第一題

因為實在太菜了,直接看答案怎麼寫好了:

const request = require('request');
const API_ENDPOINT = 'https://lidemy-book-store.herokuapp.com';
request(`${API_ENDPOINT}/books?_limit=10`, (err, res, body) => {
if (err) {
return console.log('抓取失敗', err);
}
let data;
try {
data = JSON.parse(body);
} catch (err) {
console.log(err);
return;
}
for (let i = 0; i < data.length; i += 1) {
console.log(`${data[i].id} ${data[i].name}`);
}
});

筆記:

  1. 目標網址抓出來變成變數,之後要改目標位置就只要改該變數就好。方便。
  2. 先查看是否抓取成功 => 轉成物件後再檢查一次 => 依次列出前十個

7/24 實際跑過筆記

  1. url 後方加上 ? 可以加參數,如上方 _limit=10 就是限制只抓取十筆。但似乎是照 id 抓而非出現順序?
  2. try 的框框中用 const 定義的新變數無法在最後使用,所以外面才會先定義一個 data。

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

process.argv

參考資料 使用 process 可以取得指令的參數。 process.argv 可以得到啟動 Node.js 時 command line 的參數。 例如若 hw1.js 中有 console.log(process.argv) ,再於 command line 輸入 node hw1.js 123 ,會得到一個陣列,分別指向 node 、 hw1 和 123 。

開始寫之前,整體架構是

找到第二三個參數

const request = require('request');
const apiUrl = 'https://lidemy-book-store.herokuapp.com';
const action = process.argv[2];
const param = process.argv[3];

用 switch 區分功能

switch (action) {
case 'list':
listBooks();
break;
case 'read':
readBooks(param);
break;
case 'delete':
deleteBooks(param);
break;
case 'create':
createBooks(param);
break;
case 'update':
updateBooks(param, process.argv[4]);
break;
default:
console.log('Available commands: list, read, delete, create and update');
}

list 功能 這個上一題練習過了:

function listBooks() {
request(`${apiUrl}/books?_limit=20`, (err, res, body) => {
if (err) return console.log('抓取失敗', err);
let data;
try {
data = JSON.parse(body);
} catch (e) {
return console.log(e);
}
for (let i = 0; i < data.length; i += 1) {
console.log(data[i].id, data[i].name);
}
});
}

read 功能 從上面的函式修改:

function readBooks(id) {
request(`${apiUrl}/books/${id}`, (err, res, body) => {
if (err) return console.log('抓取失敗', err);
const data = JSON.parse(body);
return console.log(data);
});
}

delete, post 和 patch

參考資料 request.delete() 可以刪除資料,例如:

request.delete(
'https://reqres.in/api/users/2',
function (error, response, body) {
console.log(response.statusCode);
}
);

上方因為資料已經被刪掉了,因此會印出 204 。 這題中,刪除的語法是這樣:

function deleteBooks(id) {
request.delete(`${apiUrl}/books/${id}`, (err) => {
if (err) return console.log('刪除失敗');
return console.log('刪除成功');
});
}

刪除完後, err 照理來說會變成 null (false) 。

request.post() 可以增加資料,最常見的形式為:

request.post(
{ url, form: { key: 'value' } },
function (err, httpResponse, body) {
/* ... */
}
);

這題中,新增的語法如下:

function createBooks(name) {
request.post({ url: `${apiUrl}/books`, form: { name } }, (err) => {
if (err) return console.log('新增失敗', err);
return console.log('新增成功');
});
}

request.patch() 則可以修改資料,使用形式為:

request.patch({
url,
form: {
//欲修改內容
},
}, function)

這題中寫法如下:

function updateBooks(id, newName) {
request.patch({ url: `${apiUrl}/books/${id}`, form: { newName } }, (err) => {
if (err) return console.log('更新失敗', err);
return console.log('更新成功');
});
}

hw3:周遊列國

你的好麻吉小立是一個很愛到處旅遊的人,在前一陣子才靠著便宜的 bug 機票以及特價的商務艙玩遍了許多地方。不過小立一直有個困擾,那就是他希望了解更多跟國家有關的知識,因此他來請你幫忙寫一個搜尋國家資訊的小程式。 這個程式很簡單,只要輸入國家的英文名字,就能夠查詢符合的國家的資訊,會輸出以下幾項:

  1. 國家名稱
  2. 首都
  3. 使用的貨幣名稱
  4. 電話國碼

偷看答案

const request = require('request');
const args = process.argv;
const API_ENDPOINT = 'https://restcountries.eu/rest/v2';
const name = args[2];
if (!name) {
return console.log('請輸入國家名稱');
}
request(`${API_ENDPOINT}/name/${name}`, (err, res, body) => {
if (err) {
return console.log('抓取失敗', err);
}
const data = JSON.parse(body);
if (data.status === 404) {
return console.log('找不到國家資訊');
}
for (let i = 0; i < data.length; i++) {
console.log('============');
console.log('國家:' + data[i].name);
console.log('首都:' + data[i].capital);
console.log('貨幣:' + data[i].currencies[0].code);
console.log('國碼:' + data[i].callingCodes[0]);
}
});

分析思路

  1. 如果沒有輸入名稱 ( args[2] 是空的) ,回傳「請輸入國家名稱」。 (用 return 連後面也不會跑嗎?)
  2. 先看 err 是否存在,有的話就回傳「抓取失敗」。
  3. data.status 可回傳 HTTP 的狀態碼。(因為 API 中有個 key 就叫 status )。
  4. 把結果印下來。

出錯ㄌ

const data 只會在 request 函式中作用,因此要將最後印下來的作業於其中完成,否則會無法找到 data 。

hw4:探索新世界

參考資料: 【第十五天】突發任務:Twitch API

之前幫秋秋鞋做完那個小程式以後,你會寫程式的消息似乎就傳開了,有一位 Twitch 平台實況主果凍跑來聯繫你,想請你幫忙做個東西。 事情是這樣的,他原本是 LOL 的玩家,但因為某些原因帳號被 ban 掉了,為了維持實況的熱度,需要去找其他遊戲來玩,可是他又不知道哪些遊戲比較熱門,會有比較多人觀看。 因此,他寫請你寫一個小程式,能夠去撈取 Twitch 上面受歡迎的遊戲,他就能夠參考這個列表來決定要實況哪個遊戲。 由於你偶爾也會看他的實況,所以你欣然接受了這個挑戰,準備來串串看真實世界的 API。 請參考 Twitch API v5 的文件,寫一隻程式去呼叫 Twitch API,並拿到「最受歡迎的遊戲列表(Get Top Games)」,並依序印出目前觀看人數跟遊戲名稱。 在這個作業中,你必須自己看懂 Twitch API 的文件,知道怎麼去申請一個 Application 拿到 ClientID,並且在 API 文件當中找到對的那一個 API(Get Top Games),而且務必記得要在 request header 中帶上 ClientID 跟另一個參數 Accept,值是:application/vnd.twitchtv.v5+json。 還有一件事情要提醒大家,Twitch API 有兩個版本,一個是最新版(New Twitch API,代號 Helix),一個是舊版的(Twitch API v5,代號 kraken),我們這次要串接的是舊版的,不要搞錯版本囉。

得到 ClientID

可參考文章:【第十五天】突發任務:Twitch API

如何加入 request header

request({
method: 'GET',
url: <url>,
headers: {
'參數':,
}
}, function(error,response,body){
// 其他內容
})

試著得到 body ,及其後

request(
{
method: 'GET',
url: apiUrl,
headers: {
'Client-ID': clientID,
Accept: 'application/vnd.twitchtv.v5+json',
},
},
(err, res, body) => {
console.log(body);
}
);

整理得到的 JSON 後得到: 此時要做的事情:

  1. 確認沒有 err
  2. 依序印出遊戲人次和名稱

for...of

參考資料:MDN for...of 可將陣列的值依序取出:

for (variable of iterable) {
//statements
}

結果 ESlint 不建議 for...of ,哈哈哈哈哈。 還是想用可參考: javascript - ESLint 提示“無限制的語法迭代器/生成器需要 regenerator-runtime”

最終結果

const request = require('request');
const apiUrl = 'https://api.twitch.tv/kraken/games/top';
const clientID = 不給你複製我的ID;
request(
{
method: 'GET',
url: apiUrl,
headers: {
'Client-ID': clientID,
Accept: 'application/vnd.twitchtv.v5+json',
},
},
(err, res, body) => {
if (err) return console.log('抓取失敗');
const data = JSON.parse(body).top;
for (const i of data) {
console.log(i.viewers, i.game.name);
}
return true;
}
);

沒什麼關聯但記錄一下:curl 的用法

hw5:簡答題

參考資料: zoeaeen13 同學的作業 API 到底是什麼? 用白話文帶你認識 HTTP 狀態碼

請以自己的話解釋 API 是什麼?

API 全名為 Application Programming Interface,中文翻譯為「應用程式介面」。簡單來說就是交換資料的管道。

舉例來說好了,今天你進到一家拉麵店,要如何和廚房說你要什麼品項?因為你已經來過很多次了,所以走到拉麵販賣機前點餐,而 這個販賣機就是 API 。你和廚房可以透過販賣機溝通(使用 API),你開店的時候別人也可以從販賣機點餐(提供 API)。

讓我們整理一下:

  • 店面 = 網站或 APP
  • 販賣機 = API
  • 你 = 使用者
  • 廚房 = 資料庫
  • 拉麵 = 資料

請找出三個課程沒教的 HTTP status code 並簡單介紹

status code 表示一個 HTTP 要求是否已經被完成,代表 API 層的執行狀態。 status code 大約分成幾種:

  • 1xx = Informational(資訊)
  • 2xx = Success(成功)
  • 3xx = Redirect(重定向)
  • 4xx = User error(客戶端錯誤)
  • 5xx = Server error(伺服器端錯誤)

以下列出課程沒提到的 HTTP status code: 201 Created:請求成功且新的資源成功被創建,通常用於 POST 或一些 PUT 請求後的回應。 400 Bad Request:此回應意味伺服器因為收到無效語法,而無法理解請求。 403 Forbidden:用戶端並無訪問權限,例如未被授權,所以伺服器拒絕給予應有的回應。不同於 401,伺服端知道用戶端的身份。

假設你現在是個餐廳平台,需要提供 API 給別人串接並提供基本的 CRUD 功能,包括:回傳所有餐廳資料、回傳單一餐廳資料、刪除餐廳、新增餐廳、更改餐廳,你的 API 會長什麼樣子?請提供一份 API 文件。

參考資料: [Week4] JS 實作串接 API(一) [Week4] JS 實作串接 API(二)

Base URL: https://v61265.com

說明Methodpath參數範例
獲取所有餐廳資料GET/restaurants_limit:限制回傳資料數量/restaurants?_limit=5
獲取單一餐廳資料GET/restaurants/:id/restaurant/10
新增餐廳POST/restaurantsname: 店名
刪除餐廳DELETE/reataurants/:id
更改餐廳資訊PATCH/restaurants/:idname: 店名

回傳所有餐廳資料

const request = require('request');
request('https://v61265.com/reataurants', (err, res, body) => {
// 這裡是你要的內容
});

回傳單一餐廳資料

const request = require('request');
request(`https://v61265.com/restaurants/${id}`, (err, res, body) => {
//這裡是你要的內容
});

增新餐廳

const request = require('request');
request.post(
{
url: 'https://v61265.com/restaurants',
form: {
name, //新餐廳名稱
},
},
(err, res, body) => {
//這裡是你想要的內容
}
);

刪除餐廳

const request = require('request');
request.delete(`https://v61265.com/restaurants/${id}`, (err, res, body) => {
//這裡可以加其他東西
});

更改餐廳資訊

const request = require('request');
request.patch(
{
url: `https://v61265.com/restaurants/${id}`,
form: { name },
},
(err, res, body) => {
//可以加其他東西
}
);

最後附上有時間可以回頭看的: [原來後端要知道] 如何寫 API 文件? #Apiary #API Blueprint # Markdown

資料來源: API 基礎 [第六週] API 基礎- 實際串接 API、資料格式: JSON、API Method 風格: RESTful