Lab: Type-safe API Response Handlers
Lab: Type-safe API Response Handlers
Section titled “Lab: Type-safe API Response Handlers”ในแบบฝึกหัดนี้ คุณจะสร้างระบบ API response handling ที่ type-safe โดยใช้ Generics, Utility Types และ Type Guards
สร้าง type-safe API layer ที่:
- รองรับ success และ error responses ด้วย generic types
- มี type guards สำหรับตรวจสอบ response
- ใช้ utility types สำหรับ CRUD operations
- จัดการ pagination ได้
-
สร้าง Generic API Response types
สร้าง
ApiSuccess<T>และApiErrorแล้วรวมเป็นApiResponse<T> -
สร้าง Type Guards
เขียน custom type guard
isSuccess()และisError() -
สร้าง CRUD Types ด้วย Utility Types
ใช้
Omit,Partial,Pickสร้าง CreateInput, UpdateInput, ListItem -
สร้าง Generic Fetch Function
เขียน
fetchApi<T>()ที่ returnApiResponse<T> -
รวมทุกอย่างเข้าด้วยกัน
สร้าง UserService ที่ใช้ทุก type ที่สร้างมา
Show Solution
// 1. Generic API Response typesinterface ApiSuccess<T> { ok: true; data: T; status: number;}
interface ApiError { ok: false; error: string; status: number; details?: Record<string, string[]>;}
type ApiResponse<T> = ApiSuccess<T> | ApiError;
// Paginated versioninterface Paginated<T> { items: T[]; total: number; page: number; perPage: number; hasNext: boolean;}
// 2. Type Guardsfunction isSuccess<T>(response: ApiResponse<T>): response is ApiSuccess<T> { return response.ok === true;}
function isError<T>(response: ApiResponse<T>): response is ApiError { return response.ok === false;}
// 3. CRUD Types ด้วย Utility Typesinterface User { id: number; name: string; email: string; role: "admin" | "user"; createdAt: Date; updatedAt: Date;}
type CreateUserInput = Omit<User, "id" | "createdAt" | "updatedAt">;type UpdateUserInput = Partial<Omit<User, "id" | "createdAt" | "updatedAt">>;type UserListItem = Pick<User, "id" | "name" | "email" | "role">;
// 4. Generic Fetch Functionasync function fetchApi<T>(url: string): Promise<ApiResponse<T>> { try { const res = await fetch(url); const data = await res.json(); if (!res.ok) { return { ok: false, error: data.message, status: res.status }; } return { ok: true, data: data as T, status: res.status }; } catch (err) { return { ok: false, error: "Network error", status: 0 }; }}
// 5. UserServiceasync function getUsers(): Promise<UserListItem[]> { const response = await fetchApi<Paginated<UserListItem>>("/api/users"); if (isError(response)) { throw new Error(response.error); } return response.data.items;}
async function getUser(id: number): Promise<User> { const response = await fetchApi<User>(`/api/users/${id}`); if (!isSuccess(response)) { throw new Error(response.error); } return response.data;}