Files
sam-docs/standards/pagination-policy.md
hskwon 26a821adca docs: 페이지네이션 정책 문서 추가
- SAM API 페이지네이션 표준 응답 구조 정의
- data 배열 + pagination 객체 분리 구조
- 구현 가이드 및 TypeScript 타입 정의 포함
2025-12-09 20:28:58 +09:00

6.1 KiB

SAM API 페이지네이션 정책

작성일: 2025-12-09 적용 범위: 모든 목록 조회 API


1. 응답 구조

1.1 표준 페이지네이션 응답

{
  "success": true,
  "message": "조회되었습니다.",
  "data": [
    { "id": 1, "name": "항목1", ... },
    { "id": 2, "name": "항목2", ... }
  ],
  "pagination": {
    "current_page": 1,
    "per_page": 20,
    "total": 100,
    "last_page": 5,
    "from": 1,
    "to": 20
  }
}

1.2 응답 구조 설명

타입 설명
success boolean 요청 성공 여부
message string 응답 메시지 (i18n 키)
data array 데이터 배열 (바로 접근 가능)
pagination object 페이지네이션 정보

1.3 pagination 객체 필드

필드 타입 설명
current_page int 현재 페이지 번호 (1부터 시작)
per_page int 페이지당 항목 수
total int 전체 항목 수
last_page int 마지막 페이지 번호
from int|null 현재 페이지 첫 번째 항목 번호
to int|null 현재 페이지 마지막 항목 번호

2. 요청 파라미터

2.1 표준 파라미터

파라미터 타입 기본값 설명
page int 1 페이지 번호
size int 20 페이지당 항목 수 (max: 100)

2.2 요청 예시

GET /api/v1/items?page=1&size=20
GET /api/v1/items?page=2&size=50&search=스크린

3. 구현 가이드

3.1 Controller 구현

public function index(Request $request)
{
    $items = $this->service->getItems($request->all());

    return ApiResponse::success([
        'data' => $items->items(),
        'pagination' => [
            'current_page' => $items->currentPage(),
            'per_page' => $items->perPage(),
            'total' => $items->total(),
            'last_page' => $items->lastPage(),
            'from' => $items->firstItem(),
            'to' => $items->lastItem(),
        ],
    ], __('message.fetched'));
}

3.2 Service 구현

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 Helper 함수 (권장)

ApiResponse 클래스에 페이지네이션 헬퍼 추가:

// app/Responses/ApiResponse.php

public static function paginated(LengthAwarePaginator $paginator, string $message = null): JsonResponse
{
    return self::success([
        'data' => $paginator->items(),
        'pagination' => [
            'current_page' => $paginator->currentPage(),
            'per_page' => $paginator->perPage(),
            'total' => $paginator->total(),
            'last_page' => $paginator->lastPage(),
            'from' => $paginator->firstItem(),
            'to' => $paginator->lastItem(),
        ],
    ], $message ?? __('message.fetched'));
}

사용 예시:

public function index(Request $request)
{
    $items = $this->service->getItems($request->all());
    return ApiResponse::paginated($items);
}

4. 설계 원칙

4.1 data는 항상 배열

// ✅ 올바른 형식 - data가 바로 배열
{
  "data": [...]
}

// ❌ 잘못된 형식 - data.data 중첩
{
  "data": {
    "data": [...]
  }
}

4.2 pagination 분리

  • 페이지네이션 정보는 pagination 객체로 명확히 분리
  • Laravel 기본 형식(first_page_url, links 등) 대신 필수 정보만 포함
  • 응답 경량화 및 프론트엔드 접근 편의성 확보

4.3 최대 페이지 크기 제한

$size = min($params['size'] ?? 20, 100);  // 최대 100개
  • 기본값: 20
  • 최대값: 100
  • 서버 부하 방지 및 응답 시간 최적화

5. 프론트엔드 사용 가이드

5.1 TypeScript 타입 정의

interface PaginatedResponse<T> {
  success: boolean;
  message: string;
  data: T[];
  pagination: {
    current_page: number;
    per_page: number;
    total: number;
    last_page: number;
    from: number | null;
    to: number | null;
  };
}

5.2 React 사용 예시

const fetchItems = async (page: number, size: number) => {
  const response = await api.get<PaginatedResponse<Item>>('/items', {
    params: { page, size }
  });

  // 데이터 직접 접근
  const items = response.data.data;

  // 페이지네이션 정보
  const { current_page, total, last_page } = response.data.pagination;

  return { items, pagination: response.data.pagination };
};

6. 기존 API 마이그레이션

6.1 변경 전 (Laravel 기본)

{
  "success": true,
  "data": {
    "current_page": 1,
    "data": [...],
    "first_page_url": "http://...",
    "from": 1,
    "last_page": 5,
    "links": [...],
    "next_page_url": "http://...",
    "path": "http://...",
    "per_page": 20,
    "prev_page_url": null,
    "to": 20,
    "total": 100
  }
}

6.2 변경 후 (SAM 표준)

{
  "success": true,
  "message": "조회되었습니다.",
  "data": [...],
  "pagination": {
    "current_page": 1,
    "per_page": 20,
    "total": 100,
    "last_page": 5,
    "from": 1,
    "to": 20
  }
}

6.3 Breaking Changes

항목 변경 전 변경 후
데이터 접근 response.data.data response.data
페이지 정보 response.data.current_page response.pagination.current_page
URL 정보 포함 (first_page_url 등) 제거
links 배열 포함 제거

7. 적용 API 목록

API 상태 비고
GET /api/v1/items 🔧 예정 Items API 통합 작업 시 적용
GET /api/v1/products 대기
GET /api/v1/materials 대기
GET /api/v1/pricing 대기
GET /api/v1/employees 대기

8. 관련 문서