Notice
Recent Posts
Recent Comments
Link
| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 1 | 2 | |||||
| 3 | 4 | 5 | 6 | 7 | 8 | 9 |
| 10 | 11 | 12 | 13 | 14 | 15 | 16 |
| 17 | 18 | 19 | 20 | 21 | 22 | 23 |
| 24 | 25 | 26 | 27 | 28 | 29 | 30 |
| 31 |
Tags
- Firebase
- KUsic
- 해커톤
- K-nearest neighbor
- text recognition
- google_ml_kit
- flutter
- 고연전
- image_picker
- 이미지 분류
- CS231n
- 앱 출시
- 앱
- 더보기창
- image classification
- 알고리즘
- linear classifier
- 앱 개발
- 다익스트라
- 백준
- OSAM
- 국방오픈소스아카데미
- 뮤직플레이어
- 고려대학교 응원가
- ModalBottomSheet
- 응원가
- 고려대학교
- loss function
- optimization
- Dijkstra
Archives
- Today
- Total
영주머니의 개발주머니
The Art of REST API Design: Idempotency, Pagination, and Security 본문
- API는 예측 가능하고 일관된 구조가 중요하다.
- 반환 형식이 제각각이거나, GET 요청이 상태를 변환하거나, 일관성 없는 네이밍은 혼란을 야기한다.
- 모든 엔드포인트가 동일한 규칙 (날짜 형식, 에러 응답 구조 등)을 따르면 클라이언트 개발이 쉬워지고 유지보수가 용이하다.
- REST에서 자원은 명사로 표현하고 동작은 HTTP 메서드로 표현한다.
- 예를 들어, 회원가입을 할 때 “POST /createUser”보다는 “POST /user”처럼 경로를 나타내는 것이 바람직하다

- 예를 들어, 회원가입을 할 때 “POST /createUser”보다는 “POST /user”처럼 경로를 나타내는 것이 바람직하다
- HTTP 메서드의 의미
- GET
- 리소스를 조회
- 부작용이 없으며 안전하고 캐시 가능하다.
- POST
- 새로운 리소스를 생성
- 기본적으로 idempotent하지 않음 (중복 생성의 위험이 있음)
- idempotent(멱등성) : 어떤 연산을 여러 번 반복해도 결과가 변하지 않는 성질
- PUT
- 리소스를 전체 대체
- 항상 idempotent
- PATCH
- 리소스의 일부만 수정
- DELETE
- 리소스를 삭제
- idempotent가 기대됨
- GET
- HTTP 메소드를 의미에 맞게 사용하지 않으면 예상치 못한 문제가 발생할 수 있다.
- 만약 GET이 상태 변화를 유발하면 캐싱이 깨질 수 있다.
- 만약 POST를 중복 생성에 대한 보호 조치 없이 여러 번 전송하면 동일 리소스가 중복으로 생기는 문제가 발생한다.
- Idempotency
- 네트워크 끊김이나 타임아웃으로 인해 클라이언트는 요청을 재전송하게 된다.
- 이때 적절한 보호가 없으면 주문 중복, 이중 결제, 데이터 불일치 등이 발생할 수 있다.
- 이때, Idempotency Key를 헤더에 담아 같이 보내면 서버는 이전에 처리했던 요청인지 확인하고 동일한 결과를 반환할 수 있다.
Idempotency

- 사용자가 결제 버튼을 누른 뒤 타임 아웃을 당하고, 사용자가 결제 버튼을 다시 누르는 경우에 멱등성 처리가 없다면 중복 결제가 발생한다.
- Operation이 멱등성을 가지기 위해서는 동일한 요청이 여러 개 들어오더라도 결과는 요청이 한번만 들어온 것과 동일해야 한다.
- POST, PATCH 요청은 기본적으로 멱동성을 가지지 않으므로 특별히 주의해야 한다.

- Idempotency를 구현하는 일반적인 흐름
- Client가 idempotency key를 포함한 POST request를 서버로 보낸다.
- 서버는 storage (cache, DB, Redis)를 확인해서 해당 key를 가진 request를 실행한 결과가 존재하는 지 확인한다.
- 결과가 이미 존재하면 기존의 결과를 return 해주고 request를 실행하지 않는다.
- 결과가 존재하지 않는다면 서버는 request를 실행하고 실행 결과를 key값과 함께 storage에 저장한 뒤 실행 결과를 return 한다.
- storage에 저장된 실행 결과는 TTL 만료 이후 삭제된다.
- 멱등성 구현을 위해서 추가 저장소가 필요하고 토큰 저장을 위해서 쓰기 동기화가 필요하다는 단점이 있지만 재시도 가능성이 크고, 부작용이 큰 작업이 포함된 시스템이라면 약간의 인프라 오버헤드를 감수하고도 멱등성 구현이 더 이득이다.
Pagination
- 대부분의 시스템에서 주문 목록, 댓글, 사용자 등의 리스트 데이터를 보여준다.
- 대규모 리스트에서 페이징이 없거나 비효율적인 경우 다음과 같은 문제가 발생할 수 있다.
- 성능 저하: 전체 테이블을 스캔하면 시스템이 느려짐
- 과도한 페이로드: 수천 개 항목을 전송하면 네트워크 및 클라이언트에 부담
- 불안정한 쿼리 결과: 데이터가 요청 사이에 변경되면 누락/중복 발생
- 페이징을 사용하면 한번에 처리할 데이터 범위를 제한하여 성능을 개선할 수 있고 시스템 과부하를 방지할 수 있다.
Offset-Based Pagination

- 작동 방식
- 쿼리 예시: ?limit=20&offset=40
- offset만큼 건너뛰고, limit만큼의 데이터를 반환
- SQL의 LIMIT과 OFFSET 키워드로 쉽게 구현 가능
- 장점
- 구현이 간단
- 정적인 대시보드, 관리자 페이지 등의 목록에 적합
- 단점
- 실시간으로 페이지 사이에 데이터가 삽입/삭제되면 중복되거나 누락된 데이터가 발생
- OFFSET이 커질수록 전체 테이블 스캔이 발생해서 성능이 저하됨
Cursor-Based Pagination

- 작동 방식
- offset을 사용하지 않고, created_at, id와 같은 고유하고 정렬가능한 필드를 cursor로 두고 이를 기준으로 다음 페이지를 가져옴
- 예를 들어, 쿼리가 ?limit=20&after=1679212341인 경우 1679212341 이후의 데이터를 가져오라는 의미이다.
- 장점
- 삽입/삭제시에도 중복/누락 문제가 없음
- OFFSET 스캔 없이 저장된 마지막 cursor의 위치부터 이어서 조회 가능
- 변동이 많은 대규모 실시간 피드, 이벤트 로그 등에 적합
- 단점
- auto-increment ID, 타임스탬프 등 정렬 가능한 고유 필드가 필요하다.
- 클라이언트가 마지막 cursor 값을 저장해야 함
API Security Considerations
- API는 시스템에서 가장 외부에 노출된 표면이다.
- 데이터, 비즈니스 로직, 권한에 대한 접근을 직접 다루므로, 잘못 구성되면 심각한 정보 유출로 이어질 수 있다.
- API는 항상 공격 받을 것을 전제로 설계되어야 한다.
Authentication(인증) vs Authorization(인가)
- Authentication(인증)
- 이 사용자는 누구인가?
- 사용자의 신원을 확인하는 절차 (ex. 로그인, 토큰 검증)
- Authorization(인가)
- 이 사용자는 이 리소스를 접근할 수 있는가?
- 특정 리소스나 기능에 대한 접근 권한을 검사하는 절차
- 토큰이 유효하다고 해서 요청이 안전한 것은 아니다. 모든 요청은 이 사용자가 이 리소스를 이 방식으로 사용할 수 있는 권한이 있는지를 철저히 확인해야 한다.
Token Types: JWT, OAuth2, API Keys

Rate Limiting and Abuse Protection
- 정상 클라이언트도 의도치 않게 API에 과부하를 줄 수 있고 데이터 스크래핑, DoS 공격을 방어하기 위해 rate limiting이 필요하다.
- Rate Limiting은 클라인언트/IP/토큰별로 요청수를 제한하거나 시간 단위로 요청 수를 추적하여 제한하는 식으로 구현할 수 있다.
Input Validation
- 외부에서 들어오는 모든 입력은 신뢰할 수 없는 데이터로 간주해야 한다.
- 검증하지 않으면 SQL injection, script injection, 경로 탐색, 타입 오류, 서버 충돌 등이 발생할 수 있다.
- 계층별 검증 예시
- Transport-level: 잘못된 JSON 구조, 너무 큰 payload 거부
- Schema-level: 필수 필드, 타입, 형식 검증
- Business logic: 도메인 규칙 적용 (ex. 자기 자신에게 송금 불가)
Error Handling Should Not Reveal Everything
Error: SELECT * FROM users WHERE id = 'abc'::uuid failed
NullReferenceException at AuthService.Authenticate
- 위와 같은 에러 메시지는 DB 구조, 내부 코드, 서비스 이름 등을 노출시켜 공격자에게 힌트를 준다.
- 오류 메시지는 HTTP 표준 코드를 사용하고 “Invalid user ID format”과 같은 간결한 메시지를 제공해야 한다.
- 전체 오류 내용은 내부 로그에 기록하고 클라이언트에는 최소한의 정보만 노출해야 한다.
Comments