API, HTTP & fetch

API = กลไกให้ซอฟต์แวร์สองส่วนสื่อสารกันด้วยชุดคำจำกัดความและโปรโตคอล ส่วน Web API สื่อสารผ่าน HTTP เป็นหลัก

API คืออะไร

Client  --- request: x=1, y=2 --->  Server
                                    API service: บวก x + y
Client  <-- response: 3 ----------  Server

HTTP 1.0 / 1.1 / 2.0

เวอร์ชันลักษณะการเชื่อมต่อ
HTTP/1.0เปิด–ปิด connection ทุกครั้งที่มี request/response
HTTP/1.1 persistentเปิด connection ครั้งเดียว ส่งได้หลาย request/response
HTTP/1.1 pipeliningส่งหลาย request ติด ๆ กันได้โดยไม่ต้องรอ response ก่อนหน้า
HTTP/2.0ส่งหลาย request ใน connection เดียว และ response ไม่ต้องเรียงลำดับตาม request
HTTP/1.0 — เปิดปิด connection ทุกรอบ req/res 1 (เปิด-ปิด) req/res 2 (เปิด-ปิดใหม่) HTTP/1.1 persistent — เปิดครั้งเดียว หลายรอบ 1 connection · req → res → req → res HTTP/1.1 pipelining — ส่ง req ติดกันไม่ต้องรอ res req req req → res res res (ต้องเรียงลำดับ) HTTP/2.0 — multiplex ไม่ต้องเรียงลำดับ res กลับมาก่อนหลังสลับกันได้

ยิ่งเวอร์ชันใหม่ ยิ่งลดจำนวนการเปิด-ปิด connection และลดการรอ

Header กับ Body

ส่วนเก็บอะไร
Headerข้อมูลกำกับ — HTTP version, method, Content-Type, Content-Length, Authorization
Bodyข้อมูลจริงที่ส่ง เช่น JSON, ไฟล์, HTML
เอกสาร HTML ที่ server ส่งกลับมาก็อยู่ใน body ของ HTTP response ส่วน method จะแปะอยู่ที่ header ของ request

HTTP Method

Methodใช้เมื่อ
GETขอข้อมูลจาก server โดยไม่แก้ข้อมูล
POSTส่งข้อมูลไป server เพื่อเพิ่มข้อมูล
PUTอัปเดตข้อมูลทั้งชิ้น (ถ้าไม่มีจะสร้างใหม่)
PATCHอัปเดตข้อมูลบางส่วน
DELETEลบข้อมูล
HEADเหมือน GET แต่เอาเฉพาะ header กลับมา
CONNECTสร้างการสื่อสารสองทาง (tunnel)
OPTIONSถามว่า server รองรับ method อะไรบ้าง
TRACEร้องขอแบบ loop back ใช้ debug
คำถามชวนคิดจากสไลด์: ใช้ POST ลบข้อมูลก็ได้ แล้วทำไมต้องมี DELETE?
คำตอบ: ทำได้ แต่ไม่เป็นมาตรฐาน ลดความน่าเชื่อถือของ API และคนอื่นอ่านโค้ดเราไม่เข้าใจ บาง API เช่น Firebase ถ้าใช้ method ผิดจะทำงานไม่ถูกต้องเลย

Status Code ที่ควรรู้

Codeความหมาย
200Success
400Bad Request — ข้อมูลที่ส่งมาผิด
401Unauthorized — ยังไม่ยืนยันตัวตน
403Forbidden — ไม่มีสิทธิ์
404Not Found
500Internal Server Error
504Gateway Timeout

fetch

ดีกว่า XMLHttpRequest ตรงที่รองรับ Promise และ async/await ได้เลย

// แบบ .then()
fetch('https://jsonplaceholder.typicode.com/users')
    .then(response => response.json())     // แปลงเป็น JSON
    .then(data => console.log(data))
    .catch(error => console.error('Error:', error));

// แบบ async/await
async function getText(file) {
    let x = await fetch(file);
    let y = await x.text();
    myDisplay(y);
}
รูปแบบข้อมูลที่แปลงได้: .text(), .json(), .blob(), .formData()
// ส่งแบบ POST พร้อม header และ body
fetch('https://jsonplaceholder.typicode.com/posts', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify(postData)
});

// ใช้ Request object แล้วระบุ method DELETE
const request = new Request('https://xxx.firebaseio.com/locations.json', { method: 'DELETE' });
const response = await fetch(request);
return await response.json();

fetch ดึงเอกสาร HTML มาแปลงเป็น DOM ก็ได้:

fetch('https://jsonplaceholder.typicode.com', {
    mode: 'cors',
    headers: { 'Access-Control-Allow-Origin': '*' }
})
    .then(response => response.text())
    .then(text => {
        var parser = new DOMParser();
        var html = parser.parseFromString(text, "text/html");
        console.log(html);
    });

axios

npm install axios

const axios = require('axios');
const response = await axios.get('https://jsonplaceholder.typicode.com/posts');
const data = response.data;      // ไม่ต้องเรียก .json() เอง
fetchaxios
ติดตั้งมีมาให้ในเบราว์เซอร์ต้องลงผ่าน npm
แปลง JSONต้องเรียก .json() เองได้ response.data เลย
กำหนด method/header/bodyต้องเขียนเองทั้งหมดมี axios.get/post/put/delete ให้

อัปโหลดไฟล์ & base64

function uploadFile() {
    const fileInput = document.getElementById('fileInput');
    const file = fileInput.files[0];
    if (!file) { console.error('No file selected'); return; }

    const formData = new FormData();
    formData.append('file', file);

    fetch('/upload/', { method: 'POST', body: formData })
        .then(response => response.json())
        .then(data => console.log('Success:', data))
        .catch(error => console.error('Error:', error));
}

ไฟล์ใหญ่แบ่งส่งเป็นส่วน ๆ ได้ด้วยการแปลงเป็น base64 string:

const reader = new FileReader();
reader.onload = function(event) {
    const base64String = event.target.result.split(',')[1];
    document.getElementById('result').textContent = base64String;
};
reader.readAsDataURL(file);
ข้อดีของการแบ่งส่ง: ทำแถบแสดงเปอร์เซ็นต์การอัปโหลดให้ผู้ใช้เห็นได้

SOAP / REST / GraphQL

SOAPRESTGraphQL
รูปแบบข้อมูลXMLปกติ JSON (ไม่บังคับ)JSON
โครงสร้างenvelope ตามมาตรฐานแยกเป็น endpoint / resourceendpoint เดียว client เลือก field ที่ต้องการ
ข้อดีเป็นมาตรฐานเข้มงวดง่าย ใช้กับ JS สะดวกได้ข้อมูลเท่าที่ขอ ไม่เกินไม่ขาด
ปัจจุบันไม่ค่อยนิยม เพราะ XML จัดการยากใน JSนิยมที่สุดนิยมในระบบที่ข้อมูลซับซ้อน

โครงของ GraphQL คือ schema ที่ประกอบด้วย Type และ Field:

const UserType = new GraphQLObjectType({
    name: 'User',
    fields: () => ({
        id:   { type: GraphQLString },
        name: { type: GraphQLString },
        age:  { type: GraphQLInt }
    })
});
โปรโตคอลที่ไม่ใช่ HTTP ที่ควรรู้จัก: WebSocket (สื่อสารสองทางแบบต่อเนื่อง) และ Webhook (server ยิงข้อมูลกลับมาหาเราเมื่อมีเหตุการณ์)

REST CRUD

การกระทำMethodตัวอย่าง URL
CreatePOSTPOST /users
ReadGETGET /users หรือ GET /users/1
UpdatePUT / PATCHPUT /users/1 (ทั้งชิ้น) / PATCH /users/1 (บางส่วน)
DeleteDELETEDELETE /users/1
ใส่เวอร์ชันใน URL ได้ เช่น GET /api/v1/users เพื่อให้เปลี่ยน API ในอนาคตโดยไม่พังของเดิม