API
API 페이지네이션이 불안정할 때 확인할 것들
페이지네이션 응답이 일관되지 않을 때 원인을 체계적으로 추적하는 방법.
API에서 페이지네이션을 제공할 때, 같은 요청을 여러 번 해도 다른 결과가 올 수 있다. 이건 데이터 증가, 정렬 불안정성, 또는 캐싱 문제 때문이다.
첫 번째: 상태 코드 확인
# 페이지 1 요청
curl -i 'https://api.example.com/api/items?page=1&limit=10'
응답 상태 코드를 보자.
- 200: 정상
- 400: 페이지 번호 형식 에러
- 500: 서버 에러
각 코드에 따라 접근이 달라진다.
응답 Body의 구조 확인
{
"data": [...],
"meta": {
"page": 1,
"limit": 10,
"total": 100,
"pages": 10
}
}
확인할 것:
data배열의 크기가limit과 일치하나?total이 정말 전체 개수인가?pages계산이 맞나? (total / limit을 올림한 값)
정렬 기준이 명확한가?
# 같은 요청 두 번
curl -s 'https://api.example.com/api/items?page=1' | jq '.data[].id'
curl -s 'https://api.example.com/api/items?page=1' | jq '.data[].id'
결과가 다르면 정렬 기준이 없거나 불안정하다.
안정적인 정렬
# ✅ 좋은 예
curl -s 'https://api.example.com/api/items?page=1&sort=created_at&order=desc'
# ❌ 나쁜 예
curl -s 'https://api.example.com/api/items?page=1' # 정렬 기준 없음
항상 명시적인 정렬 기준이 필요하다. 보통 id 또는 created_at으로 정렬한다.
데이터 변화 감지
페이지네이션 중에 데이터가 추가되거나 삭제될 수 있다.
# 1. 전체 개수 확인
curl -s 'https://api.example.com/api/items?page=1' | jq '.meta.total'
# 결과: 100
# 2. 시간이 지난 후
curl -s 'https://api.example.com/api/items?page=1' | jq '.meta.total'
# 결과: 101 (데이터 추가됨)
Total이 변했다는 건 중간에 데이터가 들어왔다는 뜻이다. 일관성을 유지하려면:
# 같은 cursor를 유지
curl -s 'https://api.example.com/api/items?cursor=abc123&limit=10'
Cursor 기반 페이지네이션이 더 안정적이다.
비교 기준 설정
# 상황 1: Offset-based pagination
API가 page와 limit을 지원
문제: 중간에 삽입/삭제되면 틀림
# 상황 2: Cursor-based pagination
API가 cursor를 지원
문제: 덜 함
# 상황 3: Keyset pagination
API가 after/before를 지원
문제: 거의 없음
로컬과 운영 비교
# 로컬
curl -s 'http://localhost:3000/api/items?page=1&limit=5' > local-page1.json
# 운영
curl -s 'https://api.example.com/api/items?page=1&limit=5' > prod-page1.json
# 비교
jq '.meta' local-page1.json
jq '.meta' prod-page1.json
메타 정보가 일치해야 한다.
경계 케이스 확인
# 마지막 페이지는?
curl -s 'https://api.example.com/api/items?page=10&limit=10' | jq '.data | length'
# 10개가 나오나? 10개 미만이 나오나?
# 존재하지 않는 페이지는?
curl -i 'https://api.example.com/api/items?page=999&limit=10'
# 빈 배열을 반환하나? 404를 반환하나?
# 페이지 0은?
curl -i 'https://api.example.com/api/items?page=0&limit=10'
# 에러? 첫 페이지로 처리?
캐싱이 방해하지 않나?
# 캐시를 무시하고 요청
curl -i -H 'Cache-Control: no-cache' 'https://api.example.com/api/items?page=1'
# CDN 캐시 확인
# 응답 헤더의 Cache-Control, ETag 확인
curl -i 'https://api.example.com/api/items?page=1' | grep -i 'cache-control\|etag'
캐시가 너무 길면 새로운 데이터가 안 보인다.
클라이언트 검증
interface PaginatedResponse<T> {
data: T[];
meta: {
page: number;
limit: number;
total: number;
pages: number;
};
}
function validatePagination<T>(response: PaginatedResponse<T>) {
// 데이터 개수가 limit 이하인가?
if (response.data.length > response.meta.limit) {
throw new Error('Too many items in page');
}
// total이 음수인가?
if (response.meta.total < 0) {
throw new Error('Invalid total count');
}
// pages 계산이 맞나?
const expectedPages = Math.ceil(response.meta.total / response.meta.limit);
if (response.meta.pages !== expectedPages) {
throw new Error('Page count mismatch');
}
return response;
}
응답을 받으면 먼저 검증한다.
문제 해결 체크리스트
- 같은 요청을 반복해서 결과가 일치하나?
- 정렬 기준이 명시되어 있나?
- Total이 일정한가? (데이터 추가/삭제 감지)
- 로컬과 운영이 일치하나?
- 캐싱이 문제는 아닌가?
- 경계 케이스 (마지막 페이지, 존재 없는 페이지)는 안 되나?
- 응답 구조가 일관된가?
페이지네이션이 불안정하다는 건 보통 정렬이 명시되지 않았거나, 캐싱이 너무 길거나, 중간에 데이터가 변했기 때문이다. 체계적으로 하나씩 확인하면 대부분 찾을 수 있다.