# SAM API 페이지네이션 정책 **작성일**: 2025-12-09 **수정일**: 2025-12-30 **적용 범위**: 모든 목록 조회 API --- ## 1. 응답 구조 ### 1.1 표준 페이지네이션 응답 (Laravel 기본) ```json { "success": true, "message": "조회되었습니다.", "data": { "current_page": 1, "data": [ { "id": 1, "name": "항목1" }, { "id": 2, "name": "항목2" } ], "first_page_url": "http://sam.kr/api/v1/items?page=1", "from": 1, "last_page": 5, "last_page_url": "http://sam.kr/api/v1/items?page=5", "links": [ { "url": null, "label": "« Previous", "active": false }, { "url": "http://sam.kr/api/v1/items?page=1", "label": "1", "active": true }, { "url": "http://sam.kr/api/v1/items?page=2", "label": "Next »", "active": false } ], "next_page_url": "http://sam.kr/api/v1/items?page=2", "path": "http://sam.kr/api/v1/items", "per_page": 20, "prev_page_url": null, "to": 20, "total": 100 } } ``` ### 1.2 응답 구조 설명 | 키 | 타입 | 설명 | |----|------|------| | `success` | boolean | 요청 성공 여부 | | `message` | string | 응답 메시지 (i18n 키) | | `data` | object | **페이지네이션 객체** (Laravel 기본) | ### 1.3 data 객체 필드 | 필드 | 타입 | 설명 | |------|------|------| | `current_page` | int | 현재 페이지 번호 (1부터 시작) | | `data` | array | **실제 데이터 배열** | | `per_page` | int | 페이지당 항목 수 | | `total` | int | 전체 항목 수 | | `last_page` | int | 마지막 페이지 번호 | | `from` | int\|null | 현재 페이지 첫 번째 항목 번호 | | `to` | int\|null | 현재 페이지 마지막 항목 번호 | | `first_page_url` | string | 첫 페이지 URL | | `last_page_url` | string | 마지막 페이지 URL | | `next_page_url` | string\|null | 다음 페이지 URL | | `prev_page_url` | string\|null | 이전 페이지 URL | | `path` | string | 기본 경로 | | `links` | array | 페이지 링크 배열 | --- ## 2. 요청 파라미터 ### 2.1 표준 파라미터 | 파라미터 | 타입 | 기본값 | 설명 | |----------|------|--------|------| | `page` | int | 1 | 페이지 번호 | | `size` | int | 20 | 페이지당 항목 수 (max: 100) | ### 2.2 요청 예시 ```http GET /api/v1/items?page=1&size=20 GET /api/v1/items?page=2&size=50&search=스크린 ``` --- ## 3. 구현 가이드 ### 3.1 Controller 구현 ```php public function index(IndexRequest $request) { $items = $this->service->getItems($request->validated()); return ApiResponse::success($items, __('message.fetched')); } ``` ### 3.2 Service 구현 ```php public function getItems(array $params): LengthAwarePaginator { $size = min($params['size'] ?? 20, 100); // 최대 100개 return Model::query() ->when($params['search'] ?? null, fn($q, $s) => $q->where('name', 'like', "%{$s}%")) ->orderByDesc('created_at') ->paginate($size); } ``` ### 3.3 최대 페이지 크기 제한 ```php $size = min($params['size'] ?? 20, 100); // 최대 100개 ``` - 기본값: 20 - 최대값: 100 - 서버 부하 방지 및 응답 시간 최적화 --- ## 4. 프론트엔드 사용 가이드 ### 4.1 TypeScript 타입 정의 ```typescript interface PaginatedResponse { success: boolean; message: string; data: { current_page: number; data: T[]; first_page_url: string; from: number | null; last_page: number; last_page_url: string; links: Array<{ url: string | null; label: string; active: boolean; }>; next_page_url: string | null; path: string; per_page: number; prev_page_url: string | null; to: number | null; total: number; }; } ``` ### 4.2 React 사용 예시 ```typescript const fetchItems = async (page: number, size: number) => { const response = await api.get>('/items', { params: { page, size } }); // 데이터 접근 const items = response.data.data.data; // 페이지네이션 정보 const { current_page, total, last_page } = response.data.data; return { items, pagination: response.data.data }; }; ``` ### 4.3 간편 접근 패턴 ```typescript // 구조 분해로 간결하게 사용 const { data: pagination } = response.data; const items = pagination.data; const { current_page, total, last_page, per_page } = pagination; ``` --- ## 5. 설계 원칙 ### 5.1 Laravel 기본 형식 유지 - 프레임워크 기본 동작 활용 - 추가 변환 로직 불필요 - 생태계 호환성 유지 ### 5.2 일관성 우선 - 기존 API와 동일한 형식 유지 - 프론트엔드 코드 재사용 - 학습 비용 최소화 ### 5.3 최대 페이지 크기 제한 - 서버 부하 방지 - 응답 시간 최적화 - DoS 공격 방어 --- ## 6. 관련 문서 - [API 개발 규칙](./api-rules.md)