API & AJAX

API

Application Programming Interface

目的

  • 降低耦合性 (單一原則)
  • 跨系統串接 (不同作業系統,不同程式語言)
  • 簡化使用方式 (封裝)

URL

組成

https://www.google.com/?s=hello

https 通訊協定

www.google.com 網址

?s=hello 參數

請求方式

  • GET
  • POST
  • PUT (有定義未實作)
  • DELETE (有定義未實作)

對應 CRUD

類型CRUD
全名CreateReadUpdateDelete
HTTPPOST/PUTGETPOST/PUTDELETE
SQLINSERTSELECTUPDATEDELETE

Web API

每次都請求都是一個 API 的發起與完成

flowchart LR
    A[Browser]
    B[Google]
    C[Backend]

    A-->| Request Method With URL | B
    B-->| Run Process | C
    C-->| Return | B
    B-->| Response | A

Browser 這個視覺化的角色拿掉,發起 Request 就是大眾所謂的 API

通常 Response 會使用 JSON 格式回傳

初體驗

觀察兩個網址回應差別

https://book.niceinfos.com/frontend/api/

https://book.niceinfos.com/frontend/api/?action=demo

Ajax

Asnychronous JavaScript And XML

同步與非同步

flowchart LR
    A[Browser]
    B[Google]
    C[Backend]

    A-->| Request Method With URL | B
    B-->| Run Process | C
    C-->| Return after 10s | B
    B-->| Response | A

在等待的時候,還可以點畫面其他的互動嗎?

非同步請求

html

<button id="btn">AJAX</button>
<div id="response"></div>

js

let btn = document.querySelector('#btn')
let response = document.querySelector('#response')

btn.addEventListener('click', doAjax)

function doAjax() {
    let request = new XMLHttpRequest()
    request.addEventListener('load', () => {
        response.innerHTML = request.responseText
    })

    request.open('GET', 'https://book.niceinfos.com/frontend/api/?action=demo')
    request.send()
}

demo

透過此方法,就算請求需要時間,也不會影響主畫面的操作 (背景作業)

模擬主機端睡眠

  1. 使用上面的範例,將 url 改為 https://book.niceinfos.com/frontend/api/?action=sleep
  2. 觀察 開發者工具 > 網路

demo

fetch

原本的 XMLHttpRequest 使用上不夠直覺,ES6 之後推出包裝過後的 fetch 方便使用

js

function doAjax() {
    let api = 'https://book.niceinfos.com/frontend/api/?action=demo';

    fetch(api)
        .then((response) => {
            return response.text()
            // return response.json()
        })
        .then((data) => {
            console.log(data)
        })
}

response.text() 將回傳資料解析為純文字

response.json() 將回傳資料解析為 json

demo

POST 發送

js

function doAjax() {
    let api = 'https://book.niceinfos.com/frontend/api/'

    let params = {
        action: 'demo',
        data: { a: 1, b: 2 },
    }

    let options = {
        method: 'POST',
        body: JSON.stringify(params),
    }

    fetch(api, options)
        .then((response) => {
            return response.text()
            // return response.json()
        })
        .then((data) => {
            response.innerHTML = data
            console.log(data)
        })
}

params 傳送資料

options 設定選項 - method 請求方式,預設 GET - body 請求主體,GET 不可以使用此屬性,透過序列化將資料打為 json 格式發送

demo

關於 then

fetch 本身的包裝是希望讓開發者透過類同步的開發方式寫程式,所以使用 then 來等待非同步

底層使用的是 Promise 物件來處理

檔案上傳

html

<input type="file" id="file" />
<button id="btn">Upload</button>
<div id="response"></div>

js

let btn = document.querySelector('#btn')
let response = document.querySelector('#response')

btn.addEventListener('click', doAjax)

function doAjax() {
    let domFile = document.querySelector('#file')
    let file = domFile.files[0]
    if (!file) {
        return
    }

    let api = 'https://book.niceinfos.com/frontend/api/'

    let form = new FormData()
    form.append('action', 'upload')
    form.append('file', file)

    let options = {
        method: 'POST',
        body: form,
    }

    fetch(api, options)
        .then((response) => {
            return response.text()
            // return response.json()
        })
        .then((data) => {
            response.innerHTML = data
            console.log(data)
        })
}

使用 FormData 物件傳送檔案,因為檔案是二進制格式,不可序列化為文字

demo

練習

雲端儲存版 Todo List

將先前開發好的本地儲存版 Todo List 近一步改良

  1. 新增雲端儲存功能
  2. 新增雲端載入功能

tip

  1. 儲存功能對應請求方式為 POST,請求 APIhttps://book.niceinfos.com/frontend/api/
  2. 載入功能對應請求方式為 GET 請求 APIhttps://book.niceinfos.com/frontend/api/?action=todo&uid=your_uid