[ 筆記 ] - API 基礎、JSON、curl 指令


Posted by krebikshaw on 2020-07-03

API 是什麼?

API 就是一段網址,只要照著對方要求的規格來輸入正確的網址,就能取得對方提供的資料。配合 HTTP 協定的規範,就可以達成更多資料交換的功能。

Server 要求的規格是什麼?

依據 Server 功能的不同,會要求的規格也會不同。
拿 Twitch 這個遊戲直播平台來舉例,他們有提供其中一項 熱門遊戲查詢 的功能。
只要輸入這段網址 https://api.twitch.tv/kraken/games/top 他就會依照熱門程度來提供遊戲資料給你。

除了這段規定的網址以外,Server 還說你可以加上條件來決定要你想列出前幾熱門的遊戲,只要在網址後面加上 limit=<你想列出的數量> ,所以如果我希望列出前十熱門的遊戲,網址就會變成這樣 https://api.twitch.tv/kraken/games/top?limit=10

其他像是訂房網站啦,可能就會讓你輸入指定網址來取得訂房資訊,加上條件或許能列出某某地區,某某時間或其他條件下查詢的結果。這些功能都是依據 Server 所提供給我們的,它提供哪些功能,我們就只能使用這些功能,因為總不可能連會員帳密、會員資料、手機號碼等等都公開出來。所以才會說,你只能取得對方願意讓你取得的資料。

Server 可以自由決定要讓使用者獲取哪些資訊,並且要提供使用者一份明確的 API 文件,使用者才會曉得如何透過 API 來取得 Server 提供的資料。

Server 提供的資料是什麼?

Server 會提供的就是它們資料庫有的資料,以遊戲直播平台來說,提供的就是與遊戲直播相關的訊息,熱門遊戲、熱門主播、遊戲頻道資訊、遊戲討論資訊...。若是訂房網站,提供的就會是與房間相關的資訊,價格、地點、房型、交通...等等。

你會發現!這些其實跟你實際去這些網站上會查到的資料差不多啊。因為不論是從它們網站上查詢,還是用 API 去取得 Server 的資料,都是存取相同的資料庫,所以網站上面顯示的資料內容,跟 API 提供的資料,才會大同小異。

API 簡介

  • Application Programming Interface 應用程式介面
    依據使用環境的不同有所區別:
    • 軟硬體廠商的 API
    • 有作業系統用的 API ,用於傳輸、寫入、讀取資料…等等電腦上一切的操作
    • 自己團隊內部用的 API
    • 對於網頁來說就是 Web API,是基於 http 協定下運作的 API

一個好的 API 應該要有下列條件

  • 完整的 API 文件說明與規範
  • 有範例程式,解釋如何運用於應用程式中
  • 有教學指引,一步一步帶領開發者學習使用 API
  • 合理的命名規則
  • 適當的防呆措施、必須預防開發者在錯誤使用時,也不會造成嚴重的傷害
  • 一開始就要有清楚的規劃、使用情境,因為一但更新或改動,客戶端都要做相對的審視與修改。

Web API 實際上最常應用的場景

  • 會員登入
  • 社群嵌入
    • 分享、按讚按鈕、嵌入貼文、留言板、影音
    • 例如:Facebook Graphic
  • 資料嵌入
    • 例如:Yahoo 氣象、Google 地圖

以網站來說,最常用的應該是登入系統,現在不管哪個網站,在會員登入頁,大部分都會有 Facebook 跟 Google 登入按鈕,這麼做對開發者、用戶、甚至是供應商,都是有利的狀況:

  • 開發者: 取自大神的登入功能,安全又省力
  • 用戶: 幾乎每個人都有帳號,無須花時間填寫會員資料
  • API 供應者:
    • 免費的廣告
    • 獲取使用者操作與使用習慣的資料,再進行分析,以方便投放更精準的廣告

參考資料:
什么是API,接口?
API設計和應用程式設計的不同?

RESTful API

RESTful API 是一種 API 的設計風格

在 「非」RESTful 的設計底下我們可能看到:

  • GET + /Get_allArticle: 獲取 所有文章
  • GET + /Get_Article/5: 獲取 id 為 5 的文章
  • POST + /Create_Article: 新增 文章
  • POST + /Delete_Article/5: 刪除 id 為 5 的文章

這些方式是將 http method 「動詞」寫在 URL 前面

在「有」RESTful 的設計底下我們可能看到:

  • GET + /articles: 獲取 所有文章
  • GET + /articles/5: 獲取 id 為 5 的文章
  • POST + /articles: 新增 文章
  • DELETE + /articles/5: 刪除 id 為 5 的文章
  • PATCH + /articles/5: 修改 id 為 5 的文章部分內容
  • PUT + /articles/5: 更新 id 為 5 的文章全部內容 ( 換句話說,就是覆蓋 )

request 要符合 「 語易化的動詞 Method 」 + 「 名詞 URL 」的格式

CRUD 原則
雖然只用 GET 跟 POST 也可以達到以上功能,但充份善用 HTTP Method 可以讓開發者更快速地了解如何使用此 API,也符合 CRUD 原則的、分別是
Create (Post):新增資料時用
Read (Get):取得資料時用
Update (Put / Patch):利用更新的方式於"指定位置"新增一項資料 / 在現有的資料欄位中,增加或部分更新一筆新的資料
Delete (Delete):刪除資料時用
我們就把這種風格稱為 RESTful API。

正確的動詞搭配明確的名詞,讓人清楚知道這個 request 的目的是什麼

參考資料:休息(REST)式架構? 寧靜式(RESTful)的Web API是現在的潮流?

串接 API 實作重點

因為取得的資料不一定保證正確,所以需要一些除錯手段來防止顯示出有誤的資料

  • 判斷一:responseStatusCode 要是 2xx 才執行,不是 2xx 開頭的要報錯
if (response.statusCode >= 200 && response.statusCode < 300) {
  //...
} else {
  //...
}
  • 判斷二:response 如果有 error 要報錯:
request.get(error, response, body)
  .then(response => {
    //...
  }).catch { error => {
    //...
  })
  • 要 POST 或者 PATCH 的時候,要告訴 server 你要帶的資料型態
    • 需要用一個參數叫 content-type
      1. 若是要帶表單格式: application/x-www-form-urlencoded
      2. 若是要夾帶檔案: multipart/form-data
      3. 若是要帶 JAON 格式:application/json
題目要求要使用 Node 執行程式的同時,可以達到各種參數的功能
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
  • 一般正常的寫法會是:
const request = require('request');

const argv = process.argv;
const inputMethod = argv[2];

if (!inputMethod) console.log('請輸入完整訊息!')
// 用 switch 來區別不同的 method 要做相應的處理
switch (inputMethod) {
  case 'list':
    doList();
    break;
  case 'read':
    deRead(argv);
    break;
  case 'delete':
    doDelete(argv);
    break;
  case 'create':
    doCreate(argv);
    break;
  case 'update':
    doUpdate(argv);
    break;
  default:
    console.log('輸入內容有誤喔!請再試一次。')
}
// 每個不同的 case 都要一個新的 function,程式會變得很長很雜
function doList() {
  request.get('https://lidemy-book-store.herokuapp.com/books?_limit=20')
    .then( response => {

    }).catch( error => {

    })
}

function doRead(argv) {

}

function doDelete(argv) {

}
   .
   .
   .
  • 學姐使用的方法是:
const request = require('request');
const process = require('process');
const rp = require('request-promise');

const baseUrl = 'https://lidemy-book-store.herokuapp.com/books';
const num = 20;
const method = process.argv[2];
const firstKey = process.argv[3];
const secondKey = process.argv[4];

// 先定義好取得 JSON 後如何處理資料
function getJson(body) {
  const json = JSON.parse(body);
  if (json.length > 1) {
    json.map(element => console.log(element.id, element.name));
  } else {
    console.log(json.id, json.name);
  }
}

// 用非常簡潔的方式寫出 5 情況需要做哪些事情,超整潔超乾淨!
if (method === 'list') {
  rp(`${baseUrl}?_limit=${num}`)
    .then(htmlString => getJson(htmlString));
}
if (method === 'read') {
  rp(`${baseUrl}/${firstKey}`)
    .then(htmlString => getJson(htmlString));
}
if (method === 'delete') request.delete(`${baseUrl}/${firstKey}`);
if (method === 'create') request.post(baseUrl).form({ name: firstKey });
if (method === 'update') request.patch(`${baseUrl}/${firstKey}`).form({ name: secondKey });

資料格式 XML & JSON

XML

  • Extensible Markup Language
  • 跟 HTML 有點像、都是標記語言 Markup Language,特色是「 內容用前後標籤包起來 」,因為此格式檔案較大、且不好閱讀,所以現代開發比較少人用 XML。

JSON

  • JavaScript Object Notation
  • 乍看跟 JavaScript 的物件很像,但 key 值必須要用雙引號 "key" 包起來
  • JSON 字串可以包含 陣列 ( 用中括號 [ ] ) 以及 物件 ( 用大括號 { } )
  • 小規定:
    • JSON 格式不能使用註解
    • Vaule 值沒有辦法放 function
  • JSON Editor online

JSON 資料處理

JSON 字串解析成 JavaScript 物件

JSON.parse():可以將 JSON 字串解析成 JavaScript 物件

// 宣告字串須使用 '' 括起來,否則就會變成是 JavaScript object 了
// 如在不同行必須在每行結尾處加上 \,否則會產生 SyntaxError
var jsonString = '{ \
    "number": "1020501", \
    "name": "小明", \
    "age": 32, \
    "sex": "M", \
    "interest": [ \
        "網頁設計", \
        "撰寫文章" \
    ] \
}';

// 將 JSON 字串解析成 JavaScript 值,這樣就可使用 JavaScript 進行操作了
var member = JSON.parse(jsonString);

// 取得物件的指定值
console.log(
    member.name + ', ' +
    member.interest[0]
);

輸出: 
小明, 網頁設計

JSON.parse() 可傳入 第二個參數 來過濾要轉換的資料

  • 第一個參數:String 名稱
  • 第二個參數:
    • 可以傳入一個用來過濾資料的 function
var jsonString = '{ \
    "number": "1020501", \
    "name": "小明", \
    "age": 32, \
    "sex": "M", \
    "interest": [ \
        "網頁設計", \
        "撰寫文章" \
    ] \
}';

// 使用第二個參數 function 方式,排除 age 特性不被包括在物件
var member = JSON.parse(jsonString, function(key, value) {
    if (key === "age") return undefined;

    return value;
});

// 取得物件
console.log(member);

輸出:
Object {number: "1020501", name: "小明", sex: "M", interest: ["網頁設計", "撰寫文章"]}

物件序列化成 JSON 字串

JSON.stringify():可以將 JavaScript 物件序列化成 JSON 字串:

// JavaScript 物件
var member = {
    "number": "1020501",
    "name": "小明",
    "age": 32,
    "sex": "M",
    "interest": [
        "網頁設計",
        "撰寫文章"
    ]
};

console.log(
    JSON.stringify(member)  // 序列化成 JSON 字串
);

輸出:
 {"number":"1020501","name":"小明","age":32,"sex":"M","interest":["網頁設計","撰寫文章"]}

JSON.stringify() 可傳入 第二個參數 來過濾要轉換的資料

  • 第一個參數:Object 名稱
  • 第二個參數:
    • 可以傳入一個用來過濾資料的 function
  // JavaScript 物件
  var member = {
    "number": "1020501",
    "name": "小明",
    "age": 32,
    "sex": "M",
    "interest": [
        "網頁設計",
        "撰寫文章"
    ]
  };

// 使用第二個參數 function 方式,排除 age 特性不被序列為 JSON 字串
  console.log(
    JSON.stringify(member, function(key, value) {
        if (key === "age") return undefined;

        return value;
    })
);

輸出: 
{"number":"1020501","name":"小明","sex":"M","interest":["網頁設計","撰寫文章"]}
  • 或傳入 array 來指定要轉換哪些資料
// 使用第二個參數 array 方式,指定要被序列為 JSON 字串的特性
console.log(
    JSON.stringify(member, ["number", "name"])
);

輸出:
{"number":"1020501","name":"小明"}

參考資料:JSON 格式與 JavaScript 解析教學範例

curl 方法

隨便看一個 Web API 文件,一定都會看到上面用 curl 示範如何發出正確的 request,因為此做法最簡單、沒有任何門檻,只要在終端機 ( Terminal ) 輸入指令就可以發 request!
基本格式

curl [options] [URL...]

curl 參數

-I:只需要 response header (--header)

-o(小寫):下載 response 到新檔案 (--output)

-O(大寫):下載指定網址的檔案內容 (--remote-name)

-L:直接跟隨 Status Code 為 301 / 302 轉址後的網址

  • curl -L google.com

-X:使用 HTTP Method 來發出 request,後面要加上 GET/POST/PUT/DELETE/PATCH (--request)

-H:設定 request 要攜帶的 header

-S:靜音模式,不輸出任何東西 (--silent)

參考資料:
Linux Curl Command 指令與基本操作入門教學
linux指令 curl指令详解


#API







Related Posts

[12] 函式 Function

[12] 函式 Function

data attribute

data attribute

[ Day 07 ] 來用 Docker 運行 InstaPy 吧!

[ Day 07 ] 來用 Docker 運行 InstaPy 吧!


Comments