API, HTTP & fetch
API = กลไกให้ซอฟต์แวร์สองส่วนสื่อสารกันด้วยชุดคำจำกัดความและโปรโตคอล ส่วน Web API สื่อสารผ่าน HTTP เป็นหลัก
API คืออะไร
Client --- request: x=1, y=2 ---> Server
API service: บวก x + y
Client <-- response: 3 ---------- Server
- บริการ API ปกติอยู่ฝั่ง server (back-end development)
- Client เป็นผู้ร้องขอบริการ
- ต้องมี protocol มาตรฐานเป็นข้อตกลงร่วมกัน
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 |
ยิ่งเวอร์ชันใหม่ ยิ่งลดจำนวนการเปิด-ปิด 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 ผิดจะทำงานไม่ถูกต้องเลย
คำตอบ: ทำได้ แต่ไม่เป็นมาตรฐาน ลดความน่าเชื่อถือของ API และคนอื่นอ่านโค้ดเราไม่เข้าใจ บาง API เช่น Firebase ถ้าใช้ method ผิดจะทำงานไม่ถูกต้องเลย
Status Code ที่ควรรู้
| Code | ความหมาย |
|---|---|
| 200 | Success |
| 400 | Bad Request — ข้อมูลที่ส่งมาผิด |
| 401 | Unauthorized — ยังไม่ยืนยันตัวตน |
| 403 | Forbidden — ไม่มีสิทธิ์ |
| 404 | Not Found |
| 500 | Internal Server Error |
| 504 | Gateway 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() เอง
| fetch | axios | |
|---|---|---|
| ติดตั้ง | มีมาให้ในเบราว์เซอร์ | ต้องลงผ่าน 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
| SOAP | REST | GraphQL | |
|---|---|---|---|
| รูปแบบข้อมูล | XML | ปกติ JSON (ไม่บังคับ) | JSON |
| โครงสร้าง | envelope ตามมาตรฐาน | แยกเป็น endpoint / resource | endpoint เดียว 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 |
|---|---|---|
| Create | POST | POST /users |
| Read | GET | GET /users หรือ GET /users/1 |
| Update | PUT / PATCH | PUT /users/1 (ทั้งชิ้น) / PATCH /users/1 (บางส่วน) |
| Delete | DELETE | DELETE /users/1 |
ใส่เวอร์ชันใน URL ได้ เช่น
GET /api/v1/users เพื่อให้เปลี่ยน API ในอนาคตโดยไม่พังของเดิม