FastAPI — 타입이 곧 계약이다 · 누락과 중복 없는 커서 페이지네이션 · 讲解
누락과 중복 없는 커서 페이지네이션의 설계 원리
한 줄 요약
페이지네이션의 계약은 ‘몇 개를 보여 줄까’가 아니라 어떤 순서에서 어디까지 읽었나다.
왜 이게 필요했나
목록 1페이지를 본 뒤 새 항목이 앞에 들어왔다고 하자. offset=10으로 다음 페이지를
요청하면 앞에서 밀린 항목을 다시 볼 수 있다. 반대로 삭제가 끼면 건너뛸 수 있다.
고유하고 변하지 않는 id로 정렬하고 마지막 id보다 큰 행을 읽으면 이 이동 문제를 줄인다.
하지만 커서는 데이터 전체의 스냅샷이 아니다. 이미 지나온 구간에 나중에 삽입된 행까지
보장하지 않으며, 가격순처럼 정렬 값이 바뀌는 목록에는 복합 키와 별도 계약이 필요하다.
어떻게 동작하나
전체 행 → 범주 필터 → id 오름차순 → id > cursor → limit + 남은 행 확인 ↓ 공개 필드 투영 + next_cursorlimit=2인데 결과가 두 개라는 사실만으로 다음 페이지가 있다고 말할 수 없다.
이 실습에서는 남은 행이 limit보다 많을 때만 마지막 반환 id를 커서로 만든다.
실서비스 SQL에서는 WHERE id > ? ORDER BY id LIMIT (limit+1)로 한 행 더 읽어
같은 판단을 한다. 여기서는 작은 메모리 목록으로 계약을 먼저 검증한다.
현장에서 만나는 모습
커서를 base64로 바꿔도 암호화나 접근 제어가 되지는 않는다. 디코딩 후 양의 정수인지
검사하고, 실제 서비스에서는 필터·정렬 조건에 커서를 묶을지 결정해야 한다.
이 실습의 커서는 id만 담으므로 다음 요청도 같은 category를 보내야 한다.
내부 비용 같은 필드를 원본 딕셔너리째 반환하면 페이지네이션이 맞아도 데이터가 샌다.
공개 필드만 새 딕셔너리에 담는 투영을 마지막에 둔다.
다음 실습에서 할 것
불규칙한 id 순서, 빈 목록, 정확히 마지막 페이지, 잘못된 limit와 커서를 확인한다.
마지막 단계에서는 TestClient로 두 페이지를 이어 읽고 중복·누락·내부 필드 노출을
검사한다. 다음 요청의 category가 달라지거나 정렬 키가 수정되면 무엇이 달라질지
설명할 수 있어야 이 실습이 끝난 것이다.
참고: [FastAPI 테스트](https://fastapi.tiangolo.com/tutorial/testing/)