Now.js Framework Documentation
ApiService - บริการ HTTP ระดับสูง
ApiService - บริการ HTTP ระดับสูง
เอกสารสำหรับ ApiService ซึ่งเป็นบริการ HTTP ระดับสูงของ Now.js Framework ที่รวมฟีเจอร์มากมายไว้ในจุดเดียว
📋 สารบัญ
- ภาพรวม
- การติดตั้งและนำเข้า
- การเริ่มต้นใช้งาน
- การกำหนดค่า
- เมธอด HTTP
- ระบบแคช
- การยืนยันตัวตน
- การป้องกันคำขอซ้ำซ้อน
- กลไกการลองใหม่
- การจัดการแคช
- ฟีเจอร์ขั้นสูง
- ตัวอย่างการใช้งาน
- เอกสารอ้างอิง API
- แนวทางปฏิบัติที่ดี
ภาพรวม
ApiService เป็น High-level HTTP Service ที่สร้างมาเพื่อจัดการ HTTP requests ในระดับที่ซับซ้อน มีฟีเจอร์ขั้นสูงที่ช่วยเพิ่มประสิทธิภาพและความปลอดภัย
ฟีเจอร์หลัก
- ✅ การแคชในหน่วยความจำ: แคชข้อมูลใน memory พร้อมอายุการใช้งาน
- ✅ การป้องกันคำขอซ้ำ: ป้องกันการเรียก API ซ้ำในเวลาเดียวกัน
- ✅ กลไกการลองใหม่: ลองใหม่อัตโนมัติเมื่อเกิด network errors
- ✅ การจัดการการยืนยันตัวตน: รองรับ Bearer, Basic, OAuth, Hybrid
- ✅ การป้องกัน CSRF: ป้องกัน CSRF attacks อัตโนมัติ
- ✅ การรีเฟรช JWT อัตโนมัติ: Refresh token ก่อนหมดอายุ
- ✅ การติดตามคำขอ: ติดตามประสิทธิภาพและข้อผิดพลาด
- ✅ การยกเลิกคำขอ: ยกเลิก requests ที่กำลังทำงาน
- ✅ การดึงข้อมูลแบบช่วงเวลา: Poll endpoints อัตโนมัติ
- ✅ คำขอตามลำดับ: ทำ requests ตามลำดับที่กำหนด
เมื่อไหร่ควรใช้ ApiService
✅ ใช้ ApiService เมื่อ:
- ต้องการ caching สำหรับข้อมูลที่ไม่เปลี่ยนแปลงบ่อย
- ต้องการ retry logic สำหรับ network errors
- ต้องการ authentication management
- ต้องการป้องกันการเรียก API ซ้ำ
- ต้องการ request tracking และ analytics
❌ ไม่ควรใช้ ApiService เมื่อ:
- ต้องการความเรียบง่าย (ใช้
simpleFetchหรือhttpแทน) - ทำงานกับ real-time data (ไม่ควร cache)
- ไม่ต้องการฟีเจอร์ขั้นสูง
การติดตั้งและนำเข้า
ApiService โหลดมาพร้อมกับ Now.js Framework และพร้อมใช้งานทันทีผ่าน window object:
// ไม่ต้อง import - พร้อมใช้งานทันที
console.log(window.ApiService); // อ็อบเจ็กต์ ApiService บน windowการเริ่มต้นใช้งาน
การเริ่มต้นแบบพื้นฐาน
// เริ่มต้นด้วยการตั้งค่าเริ่มต้น
await ApiService.init();
// ตอนนี้คุณสามารถเรียก request ได้
const response = await ApiService.get('/api/users');
console.log(response.data);การเริ่มต้นพร้อมการกำหนดค่า
await ApiService.init({
baseURL: 'https://api.example.com',
debug: true,
cache: {
enabled: true,
expiry: {
get: 300000, // แคชคำขอ GET เป็นเวลา 5 นาที
post: 0, // ไม่แคช POST
put: 0,
delete: 0
}
},
security: {
csrfProtection: true,
bearerAuth: true,
bearerTokenKey: 'auth_token'
},
connection: {
timeout: 30000,
retryOnNetworkError: true,
maxNetworkRetries: 3
}
});การกำหนดค่า
ApiService มี configuration หลายส่วนที่สามารถกำหนดได้
1. การตั้งค่าทั่วไป
{
baseURL: '', // Base URL สำหรับทุกคำขอ
debug: false, // เปิดใช้งาน debug logging
retryCount: 3, // จำนวนครั้งในการลองใหม่
retryDelay: 1000, // ระยะเวลาหน่วงระหว่างการลองใหม่ (มิลลิวินาที)
deduplicate: true // เปิดใช้งานการป้องกันคำขอซ้ำซ้อน
}2. การตั้งค่าความปลอดภัย
{
security: {
// การป้องกัน CSRF
csrfProtection: true,
csrfHeaderName: 'X-CSRF-Token',
csrfCookieName: 'XSRF-TOKEN',
csrfTokenSelector: 'meta[name="csrf-token"]',
csrfIncludeSafeMethods: true,
// การยืนยันตัวตนด้วย Bearer Token
bearerAuth: false,
bearerTokenKey: 'auth_token',
bearerPrefix: 'Bearer ',
// การยืนยันตัวตนแบบ Basic
basicAuth: false,
basicUsername: '',
basicPassword: '',
// OAuth (โฟลว์การยืนยันตัวตนแบบ OAuth)
oauth: false,
oauthTokenKey: 'oauth_token',
// การรีเฟรช JWT อัตโนมัติ
jwtRefresh: false,
jwtRefreshEndpoint: 'api/auth/refresh',
jwtExpireKey: 'exp',
jwtRefreshBeforeExpirySec: 300,
// กลยุทธ์การยืนยันตัวตน
authStrategy: 'hybrid', // 'hybrid', 'cookie', 'storage' (โหมดผสม, คุกกี้, ที่เก็บข้อมูล)
sendCredentials: true // ส่ง cookies พร้อมกับ requests
}
}3. การตั้งค่าการเชื่อมต่อ
{
connection: {
timeout: 30000, // เวลารอคำขอ (มิลลิวินาที)
retryOnNetworkError: true, // ลองใหม่เมื่อเกิด network errors
maxNetworkRetries: 3, // จำนวนครั้งสูงสุดในการลองใหม่
backoffFactor: 1.5, // ตัวคูณ backoff
retryStatusCodes: [408, 429, 500, 502, 503, 504],
exponentialBackoff: true // ใช้ exponential backoff
}
}4. การตั้งค่าแคช
{
cache: {
enabled: true,
storageType: 'memory', // 'memory', 'session', 'local'
maxSize: 100, // จำนวนรายการแคชสูงสุด
expiry: {
default: 60000, // 1 นาที
get: 60000, // แคช GET นาน 1 นาที
post: 0, // ไม่แคช POST
put: 0, // ไม่แคช PUT
delete: 0 // ไม่แคช DELETE
},
keyGeneratorFn: null, // ฟังก์ชันสร้าง cache key แบบกำหนดเอง
responsePredicate: null // ฟังก์ชันตัดสินใจว่าจะแคชหรือไม่
}
}5. การตั้งค่าการติดตาม
{
tracking: {
enabled: false,
errorTracking: true,
performanceTracking: false,
analyticsCallback: null, // ฟังก์ชันรับข้อมูล analytics
excludePaths: [] // เส้นทางที่ไม่ต้องการติดตาม
}
}6. การตั้งค่าการบันทึกล็อก
{
logging: {
enabled: false,
logLevel: 'error', // 'debug', 'info', 'warn', 'error'
includeRequest: true,
includeResponse: true,
logToConsole: true,
customLogger: null // ฟังก์ชันบันทึกล็อกแบบกำหนดเอง
}
}เมธอด HTTP
ApiService มี HTTP methods หลักๆ ที่ใช้งานได้
คำขอ GET
// GET แบบง่าย
const response = await ApiService.get('/api/users');
console.log(response.data);
// GET พร้อมพารามิเตอร์
const response = await ApiService.get('/api/users', {
page: 1,
limit: 10,
sort: 'name'
});
// GET พร้อมตัวเลือก
const response = await ApiService.get('/api/users', {}, {
cache: { enabled: false }, // ปิดการแคชสำหรับคำขอนี้
timeout: 5000 // กำหนดเวลารอแบบกำหนดเอง
});คำขอ POST
// POST แบบง่าย
const response = await ApiService.post('/api/users', {
name: 'John Doe',
email: 'john@example.com'
});
// POST พร้อมตัวเลือก
const response = await ApiService.post('/api/users', userData, {
headers: {
'X-Custom-Header': 'value'
}
});คำขอ PUT
// อัปเดตข้อมูล
const response = await ApiService.put('/api/users/1', {
name: 'Jane Doe',
email: 'jane@example.com'
});คำขอ DELETE
// ลบข้อมูล
const response = await ApiService.delete('/api/users/1');
// DELETE พร้อมตัวเลือก
const response = await ApiService.delete('/api/users/1', {
headers: {
'X-Reason': 'Account closed'
}
});วัตถุ Response
ทุก method คืนค่า response object ที่มีโครงสร้างเหมือนกับ HttpClient:
{
ok: boolean, // true ถ้าสถานะ 200-299
status: number, // รหัสสถานะ HTTP
statusText: string, // ข้อความสถานะ HTTP
data: any, // ข้อมูล response ที่แปลงแล้ว
headers: object, // เฮดเดอร์ของ response
url: string, // URL ของคำขอ
fromCache: boolean, // true ถ้ามาจาก cache (GET เท่านั้น)
timestamp: number, // เวลาสแตมป์ (ถ้ามี)
requestId: string|null // ID ของคำขอ (ถ้ามี)
}ระบบแคช
ApiService มีระบบ caching ที่ทรงพลังและยืดหยุ่น
การแคชอัตโนมัติ
await ApiService.init({
cache: {
enabled: true,
expiry: {
get: 300000 // แคชคำขอ GET นาน 5 นาที
}
}
});
// การเรียกครั้งแรก - จะเรียก API
const response1 = await ApiService.get('/api/categories');
console.log(response1.fromCache); // false (โหลดจาก API จริง)
// การเรียกครั้งที่สองภายใน 5 นาที - จะได้จาก cache
const response2 = await ApiService.get('/api/categories');
console.log(response2.fromCache); // true (ดึงจากแคช)แคชตามประเภทที่เก็บข้อมูล
Memory Cache (ค่าเริ่มต้น)
await ApiService.init({
cache: {
enabled: true,
storageType: 'memory' // ค่าเริ่มต้น - เก็บใน memory
}
});ข้อดี:
- ✅ เร็วที่สุด
- ✅ ไม่มีขนาดจำกัด (ขึ้นกับ memory)
ข้อเสีย:
- ❌ หายเมื่อ refresh หน้า
Session Storage Cache
await ApiService.init({
cache: {
enabled: true,
storageType: 'session' // เก็บใน sessionStorage
}
});ข้อดี:
- ✅ คงอยู่ตลอด session
- ✅ เร็ว
ข้อเสีย:
- ❌ หายเมื่อปิด tab
- ❌ จำกัดขนาด (~5-10MB)
Local Storage Cache
await ApiService.init({
cache: {
enabled: true,
storageType: 'local' // เก็บใน localStorage
}
});ข้อดี:
- ✅ คงอยู่แม้ปิดเบราว์เซอร์
- ✅ แชร์ระหว่าง tabs
ข้อเสีย:
- ❌ จำกัดขนาด (~5-10MB)
- ❌ ช้ากว่า memory
Cache Key แบบกำหนดเอง
await ApiService.init({
cache: {
enabled: true,
keyGeneratorFn: (url, params, method) => {
// ตรรกะ cache key แบบกำหนดเอง
const userId = localStorage.getItem('user_id');
return `${userId}:${method}:${url}:${JSON.stringify(params)}`;
}
}
});การแคชแบบมีเงื่อนไข
await ApiService.init({
cache: {
enabled: true,
responsePredicate: (response) => {
// แคชเฉพาะ response ที่สำเร็จ
return response.ok && response.status === 200;
}
}
});ระยะเวลาแคชตามเมธอด
await ApiService.init({
cache: {
enabled: true,
expiry: {
get: 600000, // แคช GET นาน 10 นาที
post: 0, // ไม่แคช POST
put: 0, // ไม่แคช PUT
delete: 0 // ไม่แคช DELETE
}
}
});การยืนยันตัวตน
ApiService รองรับ authentication หลายแบบ
1. การยืนยันตัวตนด้วย Bearer Token
กลยุทธ์ Storage (เก่า)
await ApiService.init({
security: {
bearerAuth: true,
bearerTokenKey: 'auth_token',
authStrategy: 'storage' // ใช้ localStorage
}
});
// ตั้งค่า token ใน localStorage
localStorage.setItem('auth_token', 'your-token-here');
// Requests จะรวม: Authorization: Bearer your-token อัตโนมัติ
const response = await ApiService.get('/api/user/profile');กลยุทธ์ Hybrid (แนะนำ)
await ApiService.init({
security: {
bearerAuth: true,
authStrategy: 'hybrid' // HttpOnly cookie + in-memory token (โหมดผสม)
}
});
// ตั้งค่า access token (จาก login response)
ApiService.setAccessToken('short-lived-access-token');
// Requests จะรวม: Authorization: Bearer short-lived-access-token
const response = await ApiService.get('/api/user/profile');
// ลบ token เมื่อ logout
ApiService.clearAccessToken();กลยุทธ์ Cookie
await ApiService.init({
security: {
authStrategy: 'cookie', // เซิร์ฟเวอร์จัดการ auth ผ่าน cookie
sendCredentials: true
}
});
// ไม่มี Authorization header - เซิร์ฟเวอร์ใช้ HttpOnly cookie
const response = await ApiService.get('/api/user/profile');2. การยืนยันตัวตนแบบ Basic
await ApiService.init({
security: {
basicAuth: true,
basicUsername: 'admin',
basicPassword: 'secret123'
}
});
// Requests จะรวม: Authorization: Basic YWRtaW46c2VjcmV0MTIz
const response = await ApiService.get('/api/admin/stats');3. การรีเฟรช JWT อัตโนมัติ
await ApiService.init({
security: {
bearerAuth: true,
authStrategy: 'hybrid',
jwtRefresh: true,
jwtRefreshEndpoint: '/api/auth/refresh',
jwtExpireKey: 'exp',
jwtRefreshBeforeExpirySec: 300 // รีเฟรช 5 นาทีก่อนหมดอายุ
}
});
// ApiService จะทำอัตโนมัติ:
// 1. แปลง JWT token เพื่อตรวจสอบการหมดอายุ
// 2. รีเฟรช token 5 นาทีก่อนหมดอายุ
// 3. อัปเดต access token ใน memory
// คุณไม่ต้องทำอะไร - ใช้ ApiService ตามปกติ
const response = await ApiService.get('/api/user/profile');4. การป้องกัน CSRF
await ApiService.init({
security: {
csrfProtection: true,
csrfHeaderName: 'X-CSRF-Token',
csrfCookieName: 'XSRF-TOKEN',
csrfTokenSelector: 'meta[name="csrf-token"]'
}
});
// CSRF token จะถูก:
// 1. ดึงมาจาก meta tag หรือ cookie อัตโนมัติ
// 2. แนบเข้ากับ POST/PUT/DELETE requestsHTML:
<meta name="csrf-token" content="your-csrf-token">การป้องกันคำขอซ้ำซ้อน
ApiService ป้องกันการเรียก API ซ้ำในเวลาเดียวกัน
วิธีการทำงาน
await ApiService.init({
deduplicate: true // ค่าเริ่มต้น
});
// ผู้ใช้คลิกปุ่มหลายครั้งอย่างรวดเร็ว
button.addEventListener('click', async () => {
const response = await ApiService.get('/api/data');
console.log(response.data);
});
// ApiService จะ:
// 1. ตรวจสอบว่า request กำลัง pending อยู่หรือไม่
// 2. ถ้าใช่ คืนค่า promise เดียวกัน
// 3. ถ้าไม่ใช่ ทำ request ใหม่
// ผลลัพธ์: มีเพียง 1 การเรียก API จริง ทุกการคลิกใช้ response เดียวกันปิดการป้องกันคำขอซ้ำ
await ApiService.init({
deduplicate: false // อนุญาตให้มี duplicate requests
});Cache Key แบบกำหนดเอง
การป้องกันคำขอซ้ำใช้ cache key เพื่อระบุ requests:
// cache key เหมือนกัน = ถูกป้องกันคำขอซ้ำ
await ApiService.get('/api/users', { page: 1 });
await ApiService.get('/api/users', { page: 1 }); // ใช้ request แรก
// cache key ต่างกัน = requests แยก
await ApiService.get('/api/users', { page: 1 });
await ApiService.get('/api/users', { page: 2 }); // ทำ request ที่สองกลไกการลองใหม่
ApiService ลองใหม่อัตโนมัติเมื่อเกิดข้อผิดพลาด
การลองใหม่พื้นฐาน
await ApiService.init({
retryCount: 3,
retryDelay: 1000,
connection: {
retryOnNetworkError: true,
maxNetworkRetries: 3
}
});
// การลองใหม่จะเกิดขึ้นเมื่อ:
// 1. เครือข่ายขัดข้อง
// 2. หมดเวลา
// 3. ข้อผิดพลาดของเซิร์ฟเวอร์ (500, 502, 503, 504)การถอยกลับแบบเอ็กซ์โปเนนเชียล
await ApiService.init({
retryDelay: 1000,
connection: {
retryOnNetworkError: true,
maxNetworkRetries: 3,
backoffFactor: 1.5,
exponentialBackoff: true
}
});
// ลองใหม่อีกครั้ง:
// ครั้งที่ 1: 1000ms
// ครั้งที่ 2: 1500ms (1000 * 1.5)
// ครั้งที่ 3: 2250ms (1500 * 1.5)สถานะที่ลองใหม่ได้
await ApiService.init({
connection: {
retryStatusCodes: [408, 429, 500, 502, 503, 504],
maxNetworkRetries: 3
}
});
// จะลองใหม่สำหรับรหัสสถานะต่อไปนี้:
// 408 - หมดเวลา
// 429 - ติดต่อมากเกินไป
// 500 - ข้อผิดพลาดของเซิร์ฟเวอร์
// 502 - เกตเวย์ไม่ถูกต้อง
// 503 - ไม่พร้อมให้บริการ
// 504 - หมดเวลาเกตเวย์การจัดการแคช
ApiService มี methods สำหรับจัดการ cache
ล้างแคชทั้งหมด
// Clear all cache entries
ApiService.clearCache();การลบแคชแบบกำหนดเอง
// Invalidate by URL and params
ApiService.invalidateCache('/api/users', { page: 1 });
// Invalidate by URL (all params)
ApiService.invalidateCacheByUrl('/api/users');การลบแคชอัตโนมัติ
// POST/PUT/DELETE จะลบแคชที่เกี่ยวข้องอัตโนมัติ
await ApiService.post('/api/users', userData);
// ^ จะลบแคชสำหรับ '/api/users'
await ApiService.put('/api/users/1', userData);
// ^ จะลบแคชสำหรับ '/api/users/1'
await ApiService.delete('/api/users/1');
// ^ จะลบแคชสำหรับ '/api/users/1'ตรวจสอบสถานะแคช
const response = await ApiService.get('/api/users');
if (response.fromCache) {
console.log('ข้อมูลจากแคช');
} else {
console.log('ข้อมูลจาก API');
}ฟีเจอร์ขั้นสูง
1. ยกเลิกคำขอ
// เริ่ม request
const requestPromise = ApiService.get('/api/large-data');
// ยกเลิกหลังจาก 5 วินาที
setTimeout(() => {
ApiService.abort('/api/large-data');
}, 5000);
try {
const response = await requestPromise;
} catch (error) {
console.log('Request ถูกยกเลิก');
}2. การดึงข้อมูลเป็นช่วง
// Poll ทุก 5 วินาที
const stopPolling = ApiService.poll(
'/api/status',
{},
5000,
(response, error, count) => {
if (error) {
console.error('Poll error:', error);
return;
}
console.log('Poll #' + count, response.data);
},
{
maxPolls: 10, // หยุดหลัง 10 polls
condition: (response) => {
// หยุดเมื่อสถานะเป็น 'completed'
return response.data.status === 'completed';
}
}
);
// หยุด polling ด้วยตนเอง
// stopPolling();3. คำขอตามลำดับ
const requests = [
{ url: '/api/users', params: { page: 1 } },
{ url: '/api/posts', params: { page: 1 } },
{ url: '/api/comments', params: { page: 1 } }
];
const results = await ApiService.sequence(requests, (response) => {
// ประมวลผล response แต่ละตัว
return response.data;
});
console.log('ผลลัพธ์ทั้งหมด:', results);4. คำขอแบบขนาน
const responses = await ApiService.all([
ApiService.get('/api/users'),
ApiService.get('/api/posts'),
ApiService.get('/api/comments')
]);
console.log('Users:', responses[0].data);
console.log('Posts:', responses[1].data);
console.log('Comments:', responses[2].data);5. การบันทึกล็อกแบบกำหนดเอง
await ApiService.init({
logging: {
enabled: true,
logLevel: 'debug',
customLogger: (level, message, data) => {
// ส่งไปยังบริการบันทึกล็อกภายนอก
console.log(`[${level.toUpperCase()}] ${message}`, data);
// ตัวอย่าง: ส่งไป Sentry
if (level === 'error') {
// Sentry.captureException(data);
}
}
}
});6. การติดตามประสิทธิภาพ
await ApiService.init({
tracking: {
enabled: true,
performanceTracking: true,
analyticsCallback: (data) => {
if (data.type === 'performance') {
console.log(`${data.method} ${data.url} ใช้เวลา ${data.duration}ms`);
// ส่งไปยังบริการ analytics
// analytics.track('api_request', data);
}
}
}
});ตัวอย่างการใช้งาน
1. การเรียก API แบบง่ายพร้อมแคช
await ApiService.init({
baseURL: 'https://api.example.com',
cache: {
enabled: true,
expiry: { get: 300000 } // 5 นาที
}
});
// การเรียกครั้งแรก
const categories = await ApiService.get('/api/categories');
console.log(categories.fromCache); // false
// การเรียกครั้งที่สอง (ภายใน 5 นาที)
const categoriesCached = await ApiService.get('/api/categories');
console.log(categoriesCached.fromCache); // true2. การยืนยันตัวตนด้วย Bearer Token
await ApiService.init({
baseURL: 'https://api.example.com',
security: {
bearerAuth: true,
authStrategy: 'hybrid'
}
});
// เข้าสู่ระบบ
const loginResponse = await ApiService.post('/api/auth/login', {
email: 'user@example.com',
password: 'password123'
});
// ตั้งค่า access token
ApiService.setAccessToken(loginResponse.data.accessToken);
// ทำ requests ที่ผ่านการยืนยันตัวตน
const profile = await ApiService.get('/api/user/profile');
console.log(profile.data);
// ออกจากระบบ
await ApiService.post('/api/auth/logout');
ApiService.clearAccessToken();3. การส่งฟอร์มพร้อม CSRF
await ApiService.init({
security: {
csrfProtection: true
}
});
// CSRF token จะถูกแนบอัตโนมัติ
const response = await ApiService.post('/api/contact', {
name: 'John Doe',
email: 'john@example.com',
message: 'Hello!'
});4. การลองใหม่เมื่อเกิด Network Error
await ApiService.init({
connection: {
retryOnNetworkError: true,
maxNetworkRetries: 3,
backoffFactor: 1.5,
exponentialBackoff: true
}
});
// จะลองใหม่ 3 ครั้งเมื่อเกิด network error
try {
const response = await ApiService.get('/api/data');
console.log(response.data);
} catch (error) {
console.error('ล้มเหลวหลังจากลองใหม่ 3 ครั้ง:', error);
}5. การ Poll สำหรับอัปเดตสถานะ
await ApiService.init({
baseURL: 'https://api.example.com'
});
// เริ่มงานที่ใช้เวลานาน
const task = await ApiService.post('/api/tasks', {
type: 'export',
format: 'pdf'
});
// Poll สถานะ
const stopPolling = ApiService.poll(
`/api/tasks/${task.data.id}`,
{},
2000, // Poll ทุก 2 วินาที
(response, error, count) => {
if (error) {
console.error('Poll error:', error);
return;
}
const status = response.data.status;
console.log(`Poll #${count}: ${status}`);
if (status === 'completed') {
console.log('งานเสร็จสมบูรณ์!', response.data.result);
}
},
{
maxPolls: 30, // สูงสุด 1 นาที (30 * 2 วินาที)
condition: (response) => {
// หยุดเมื่อเสร็จสมบูรณ์หรือล้มเหลว
return ['completed', 'failed'].includes(response.data.status);
}
}
);6. การแบ่งหน้าพร้อมแคช
await ApiService.init({
baseURL: 'https://api.example.com',
cache: {
enabled: true,
expiry: { get: 60000 } // 1 นาที
}
});
async function loadPage(page) {
const response = await ApiService.get('/api/products', {
page: page,
limit: 20
});
console.log(`หน้า ${page} (cached: ${response.fromCache})`);
return response.data;
}
// โหลดหน้า 1-3
const page1 = await loadPage(1); // เรียก API
const page2 = await loadPage(2); // เรียก API
const page3 = await loadPage(3); // เรียก API
// โหลดหน้า 1 อีกครั้ง (ภายใน 1 นาที)
const page1Again = await loadPage(1); // จาก cache7. การอัปโหลดไฟล์
const fileInput = document.querySelector('#file');
const file = fileInput.files[0];
const formData = new FormData();
formData.append('file', file);
formData.append('title', 'My Document');
formData.append('category', 'reports');
const response = await ApiService.post('/api/upload', formData);
if (response.ok) {
console.log('อัปโหลดสำเร็จ:', response.data.url);
}8. การค้นหาพร้อม Debouncing
let searchTimeout;
function handleSearch(query) {
// ล้าง timeout ก่อนหน้า
clearTimeout(searchTimeout);
// ยกเลิก request ก่อนหน้า
ApiService.abort('/api/search', { q: lastQuery });
// ตั้ง timeout ใหม่
searchTimeout = setTimeout(async () => {
const response = await ApiService.get('/api/search', {
q: query,
limit: 10
});
displayResults(response.data);
}, 300); // รอ 300ms หลังจากผู้ใช้หยุดพิมพ์
}
searchInput.addEventListener('input', (e) => {
handleSearch(e.target.value);
});9. การแคชแบบมีเงื่อนไข
await ApiService.init({
cache: {
enabled: true,
expiry: { get: 300000 },
responsePredicate: (response) => {
// แคชเฉพาะ response ที่สำเร็จและมีข้อมูล
return response.ok &&
response.status === 200 &&
response.data &&
Object.keys(response.data).length > 0;
}
}
});
const response = await ApiService.get('/api/data');
// จะถูกแคชเฉพาะเมื่อ response สำเร็จและมีข้อมูล10. การจัดการข้อผิดพลาด
try {
const response = await ApiService.get('/api/users');
if (response.ok) {
console.log('สำเร็จ:', response.data);
} else {
// จัดการ HTTP errors
switch (response.status) {
case 401:
// เปลี่ยนไปหน้า login
window.location.href = '/login';
break;
case 403:
alert('ไม่มีสิทธิ์เข้าถึง');
break;
case 404:
console.error('ไม่พบข้อมูล');
break;
case 500:
alert('เกิดข้อผิดพลาดจากเซิร์ฟเวอร์ กรุณาลองใหม่อีกครั้ง');
break;
default:
console.error('ข้อผิดพลาด:', response.statusText);
}
}
} catch (error) {
// จัดการ network errors
console.error('ข้อผิดพลาดเครือข่าย:', error);
alert('ไม่สามารถเชื่อมต่อกับเซิร์ฟเวอร์ กรุณาตรวจสอบการเชื่อมต่ออินเทอร์เน็ตของคุณ');
}เอกสารอ้างอิง API
การเริ่มต้น
ApiService.init(options?: ConfigOptions): Promise<ApiService>เมธอด HTTP
get(url: string, params?: object, options?: RequestOptions): Promise<Response>
post(url: string, data: any, options?: RequestOptions): Promise<Response>
put(url: string, data: any, options?: RequestOptions): Promise<Response>
delete(url: string, options?: RequestOptions): Promise<Response>การยืนยันตัวตน
setAccessToken(token: string): void
clearAccessToken(): voidการจัดการแคช
clearCache(): void
invalidateCache(url: string, params?: object): boolean
invalidateCacheByUrl(url: string): number
createCacheKey(url: string, params?: object, method?: string): stringการควบคุมคำขอ
abort(url: string, params?: object): booleanเมธอดขั้นสูง
all(requests: Promise[]): Promise<any[]>
poll(url: string, params?: object, interval?: number, callback: Function, options?: PollOptions): Function
sequence(requests: RequestConfig[], processor?: Function): Promise<any[]>เมธอดยูทิลิตี้
buildUrlWithParams(url: string, params?: object): stringแนวทางปฏิบัติที่ดี
1. ✅ เริ่มต้นครั้งเดียว
// ❌ ไม่ดี: Initialize ทุกครั้ง
async function fetchData() {
await ApiService.init({ /* config */ });
return await ApiService.get('/api/data');
}
// ✅ ดี: Initialize ครั้งเดียว
await ApiService.init({ /* config */ });
async function fetchData() {
return await ApiService.get('/api/data');
}2. ✅ ใช้การหมดอายุแคชที่เหมาะสม
// ❌ ไม่ดี: Cache ทุกอย่างเหมือนกัน
await ApiService.init({
cache: {
enabled: true,
expiry: { get: 300000 } // 5 นาทีสำหรับทุกอย่าง
}
});
// ✅ ดี: Cache ตามประเภทข้อมูล
await ApiService.init({
cache: {
enabled: true,
expiry: {
get: 300000, // 5 นาทีสำหรับข้อมูลปกติ
post: 0, // ไม่แคช POST
put: 0,
delete: 0
}
}
});
// ✅ ดีกว่า: ปิดแคชสำหรับแต่ละคำขอ
const realtimeData = await ApiService.get('/api/live-stats', {}, {
cache: { enabled: false }
});3. ✅ ใช้ Hybrid Auth Strategy
// ❌ ไม่ดี: Storage strategy (ไม่ปลอดภัย)
await ApiService.init({
security: {
bearerAuth: true,
authStrategy: 'storage' // Token อยู่ใน localStorage
}
});
// ✅ ดี: Hybrid strategy (ปลอดภัยกว่า)
await ApiService.init({
security: {
bearerAuth: true,
authStrategy: 'hybrid', // Token in memory + HttpOnly cookie
jwtRefresh: true
}
});4. ✅ จัดการข้อผิดพลาดอย่างเหมาะสม
// ❌ ไม่ดี: ไม่จัดการ error
const response = await ApiService.get('/api/data');
console.log(response.data); // May be undefined
// ✅ ดี: ตรวจสอบ response.ok
const response = await ApiService.get('/api/data');
if (response.ok) {
console.log(response.data);
} else {
console.error('Error:', response.statusText);
}
// ✅ ดีกว่า: ใช้ try-catch
try {
const response = await ApiService.get('/api/data');
if (response.ok) {
console.log(response.data);
}
} catch (error) {
console.error('Network error:', error);
}5. ✅ เปิดใช้งาน CSRF Protection
// ✅ ดี: เปิดใช้งาน CSRF protection
await ApiService.init({
security: {
csrfProtection: true
}
});6. ✅ ใช้กลไก Retry
// ✅ ดี: เปิดใช้งาน retry
await ApiService.init({
connection: {
retryOnNetworkError: true,
maxNetworkRetries: 3,
exponentialBackoff: true
}
});7. ✅ ทำความสะอาด Polling เมื่อไม่ต้องการแล้ว
// ❌ ไม่ดี: ไม่ cleanup
ApiService.poll('/api/status', {}, 5000, callback);
// ✅ ดี: เก็บ stop function
const stopPolling = ApiService.poll('/api/status', {}, 5000, callback);
// Cleanup เมื่อไม่ต้องการแล้ว
window.addEventListener('beforeunload', () => {
stopPolling();
});8. ✅ ยกเลิกคำขอที่ไม่ต้องการ
// ✅ ดี: Abort requests ที่ไม่ต้องการแล้ว
const controller = new AbortController();
button.addEventListener('click', () => {
ApiService.get('/api/large-data', {}, {
signal: controller.signal
});
});
cancelButton.addEventListener('click', () => {
ApiService.abort('/api/large-data');
});9. ✅ ใช้การป้องกันการเรียกซ้ำ
// ✅ ดี: เปิดใช้งาน deduplication (default)
await ApiService.init({
deduplicate: true
});
// ป้องกันการคลิกซ้ำๆ
button.addEventListener('click', async () => {
const response = await ApiService.get('/api/data');
// ถ้าคลิกหลายครั้ง จะใช้ request เดียวกัน
});10. ✅ ลบแคชเมื่อข้อมูลเปลี่ยนแปลง
// ❌ ไม่ดี: ไม่ clear cache เลย
await ApiService.post('/api/users', userData);
// Cache เก่ายังคงอยู่
// ✅ ดี: ApiService clear cache อัตโนมัติ
await ApiService.post('/api/users', userData);
// Cache สำหรับ '/api/users' ถูกลบอัตโนมัติ
// ✅ ดีกว่า: Clear cache manually เมื่อจำเป็น
await ApiService.post('/api/settings', settings);
ApiService.invalidateCacheByUrl('/api'); // Clear all /api cacheสรุป
เมื่อไหร่ควรใช้ ApiService
| กรณีการใช้งาน | ใช้ ApiService? |
|---|---|
| ข้อมูลที่ไม่เปลี่ยนแปลงบ่อย (categories, config) | ✅ ใช่ - เปิด caching |
| ข้อมูล real-time (stock prices, live stats) | ❌ ไม่ - ใช้ http หรือ disable cache |
| ต้องการ authentication | ✅ ใช่ - มี auth management |
| ต้องการ retry logic | ✅ ใช่ - มี retry mechanism |
| ป้องกันการคลิกซ้ำ | ✅ ใช่ - มี deduplication |
| Simple API call | ❌ ไม่จำเป็น - ใช้ simpleFetch หรือ http |
| File download/upload | ✅ ใช้ได้ - รองรับ FormData |
| Polling | ✅ ใช่ - มี built-in polling |
| Performance tracking | ✅ ใช่ - มี tracking system |
ฟีเจอร์หลัก
| คุณสมบัติ | พร้อมใช้งาน | หมายเหตุ |
|---|---|---|
| Caching | ✅ | Memory, Session, Local storage |
| Deduplication | ✅ | ป้องกันคำขอซ้ำซ้อน |
| Retry | ✅ | พร้อม exponential backoff |
| Authentication | ✅ | Bearer, Basic, OAuth, Hybrid |
| CSRF Protection | ✅ | อัตโนมัติ |
| JWT Refresh | ✅ | รีเฟรชอัตโนมัติก่อนหมดอายุ |
| Polling | ✅ | พร้อมเงื่อนไข |
| Abort | ✅ | ยกเลิกคำขอที่กำลังรอ |
| Tracking | ✅ | ประสิทธิภาพและข้อผิดพลาด |
| Logging | ✅ | หลายระดับ |