미션
- Soft Delete가 무엇인지 찾아보고 Soft Delete에는 어떠한 HTTP Method가 들어가면 좋을지 적어주세요.
- 컨트롤 URI에 대해서 조사해주시고, 어떠할 때 사용이 가능한 지 예시를 들어 설명해주세요.
- https://learn.microsoft.com/ko-kr/azure/architecture/best-practices/api-design 위 문서를 읽고 주요 내용을 간단히 정리해주세요.
Soft Delete? Hard Delete?
Soft Delete와 Hard Delete는 서로 대조되는 개념이다.
Hard Delete
특정 데이터의 삭제 요청이 들어왔을때 지체 없이 바로 쿼리문을 통해 해당 데이터 레코드를 DELETE하는 삭제 방식을 의미한다. 데이터가 즉각적으로 반영이 된다는 점에서 이점이 있을 수 있으나, 실수로 데이터가 지워졌을때 복구하기가 복잡해지고, 대량의 데이터가 delete가 발생할때 속도 / 성능 저하가 발생할 수 있다.
Soft Delete
논리적 삭제라고도 일컬어지는데 삭제 요청이 들어왔을때 바로 DELETE 쿼리를 바로 실행 하는 것이 아닌 UPDATE 문 등을 이용해 해당 레코드가 삭제되었다는 논리적인 표식만 남기는 것이다. (예 : deletedAt 컬럼 등)
이후 관리자가 정해놓은 스케줄에 맞추어 논리적으로 삭제한 레코드를 확인하고 배치 작업으로 한번에 DELETE 쿼리를 실행하여 제거하는 것이다.
이렇게 했을때 실수로 데이터를 지웠다고 하더라도 삭제 배치 작업이 발생하기 전이라면 쉽게 복구가 가능하고, 특히 즉각적인 응답을 줘야하는 서비스라면 UPDATE문이 DELETE문에 비해서 일반적으로 더 빠르기 때문에 유저 경험 측면에서도 이점이 생긴다.
그러나 구현해야되는 코드, 아키텍처가 Hard Delete에 비해 더 복잡해 지는 경우가 더 많으며, 해당 테이블에서 데이터를 조회할때 추가조건을 지정하지 않으면 이미 논리 삭제 된 데이터까지 조회가 되어버리므로 deletedAt is null 등과 같은 조건을 매번 추가하여 조회를 해야하는 점도 단점이다.
적합한 HTTP Method
Hard Delete는 해당 레코드를 바로 DELETE 쿼리를 통해 지워버리므로 HTTP Method로 DELETE가 적절하다.
그러나 Soft Delete에 경우 이름에 Delete라는 단어가 포함되어 있지만 정작 실제로 API가 요청되어 작업이 수행되는 사이클에서는 해당 레코드에 UPDATE문을 통해 해당 레코드에 삭제 표식만 추가하여 수정하므로 DELETE 보다는 일부만 수정했다는 의미로 PATCH 메소드가 더 적절하다고 볼 수 있다.
컨트롤 URI
일반적으로 RESTful API를 설계할때는 리소스 자체에 초점을 맞추어 API 구조를 작성하는 경우가 일반적이다.
그러나 일부 복잡한 작업에 경우 한 리소스에 한정하여 API 구조를 작성하기 어려운 경우가 있다.
이러한 한계를 극복하기 위해 리소스 자체보다는 리소스에 가해지는 조작이나 상태 변화에 초점을 맞추어 짜는 API 엔드포인트 URI를 컨트롤 URI라고 한다.
예를들어 리소스중심으로 미션 수락 엔드포인트를 만든다고 하면 POST /api/missions/{missionId}
로 표현할 수 있을 것이다.
그러나 만약 미션 거절기능이 있다고 가정해보자. 그러면 미션 거절 기능도 POST /api/missions/{missionId}
로 표현하는것에 무리는 없을것이다. 이 경우 두 기능에 대한 API 엔드포인트가 겹치게 된다. 이럴때 컨트롤 URI를 활용해 볼 수 있다.
미션 수락은 POST /api/missions/{missionId}/accept
으로,
미션 거절은 POST /api/missions/{missionId}/deny
이런식으로 말이다.
API 디자인 모범 사례 문서 요약
RESTful API가 지켜야할 원칙
- 플랫폼 독립성 - 클라이언트의 환경, 구조 관계없이 호출 가능해야함
- 느슨한 결합 - 클라이언트와 웹 서비스가 독립적으로 동작해야함.
- 상태 비저장 - 각 HTTP 요청은 독립적으로 처리되어야한다. 이전 요청에 의존성이 발생하면 안된다.
RESTful API URI 정의 방법
- 리소스 이름에 명사 사용 (동사X)
- 복수 명사로 컬렉션 URI의 이름을 정하기
예)
/restaurants/{restaurantId}
- 리소스간에 관계는 계층적 구조로 나타낼 수 있으나 너무 복잡한 계층 분할은 피한다.
- 너무 세부적인 리소스 노출은 보안에 문제가 될수 있어 피하고, 클라이언트에서 필요한 데이터를 한번에 넘겨주기 위해 어느정도 비정규화를 고려할 수 있다.
- 내부 DB 스키마 구조를 노출하지 말고 클라이언트 관점에서의 리소스 계층을 기반으로 API를 설계할것
HTTP 매서드 & 상태코드 사용
- GET → 리소스 조회
- 200(OK), 204(내용 없음), 404(없음) 등의 응답을 활용
- POST → 새 리소스 생성 또는 비 리소스 작업
- 201 (Created) + 새 리소스에 대한 Location 헤더(새URI) 또는 200/204응답 가능, 실패시 400/405 응답 가능
- PUT → 전체 업데이트 또는 존재하지 않으면 생성
- PUT은 멱등성이 보장되어야함 (같은 요청 여러 번 해도 결과가 동일해야함)
- PATCH → 부분 업데이트
- JSON 병합 패치 또는 JSON 패치 형식 사용 가능
- 200, 400, 409, 415 등의 상태 코드 반환
- DELETE → 리소스 삭제
- 일반적으로 204(콘텐츠 없음) 또는 404 (없음) 반환
비동기 작업 처리
어떤 동작이 오래 걸릴 경우 비동기로 작업을 수행하도록 할 수 있음.
- 먼저 요청에 대해서는 202 Accepted를 반환하고 응답 헤더 Location에 해당 작업의 상태 모니터링이 가능한 엔드포인트를 반환
- 클라이언트가 반환된 엔드포인트에 요청하면 진행현황을 알 수 있게됨
페이징, 필터링, 정렬, 필드 선택
- 클라이언트가 원하는 부분만 요청하게 하기 위해 페이징, 필터링, 정렬, 필드 선택 기능을 구현하면 좋다. (워크북에서 배운 페이지네이션 내용)
- 페이징 요청시, 최대 limit 값을 제한하는것이 좋음(DDOS 방지)
부분 응답 / 범위 요청
- 큰 이진 리소스 (예: 이미지, 파일)는 부분 응답 (Range 요청, Accept-Ranges 헤더) 지원하는 게 좋음 → 여러번에 나누어서 큰 리소스를 내려받을 수 있음
- HEAD 요청도 같이 구현해서 클라이언트가 리소스의 메타 정보만 먼저 얻을 수 있게 함
HATEOAS 구현
- API 응답에 해당 리소스와 관련된 링크 및 가능한 행동을 포함 시켜 클라이언트에서 API의 응답만 보고 바로 이어지는 동작을 바로 진행할 수 있게 함
- 링크 객체는 rel(관계), href( URI ), action (HTTP 메서드) 및 미디어 타입 등을 포함할 수 있다.
- 리소스 상태에 따라 링크 집합에 변동이 생길 수 있음.
버전 관리 전략
- 스키마 수정, 리소스 추가 등으로 API의 수정사항이 발생할때 버전 관리 전략이 필요함.
- 주요 방식 :
- URI 버전 관리 (예 :
/v2/restaurants/…
) - 쿼리 문자열 버전 (
?version=2
) - 헤더 기반 버전 (
X-Api-Version
등) - 미디어 유형 버전 (예:
Accept: application/vnd.contoso.v2+json
)
- URI 버전 관리 (예 :
다중 테넌트 고려
- 여러 테넌트가 같은 API를 사용해야할 경우 테넌트 구분을 명확히 설계해야함
테넌트 식별 방식
- 하위 도메인 기반 (
tenant.api.com
) - HTTP 헤더 (예 :
X-Tenant-ID
) - URI 경로 내 포함 (예:
/tenants/{tenantId}/orders
)
성숙도 모델 & Open API
- 레너드 리처드슨의 리처드슨 성숙 모델(Richardson Maturity Model, RMM)제시
- 수준 0 : 하나의 URI + POST만 (모든 요청을 하나의 URI로 해결하는 방법)
- 수준 1: 리소스별 URI 분리
- 수준 2 : HTTP 메서드 도 활용하여 분리
- 수준 3 : HATEOAS 포함 → 완전 RESTful 수준
- OpenAPI (이전 Swagger) 를 채택하여 API를 계약 우선 접근 방식으로 설계하고, 문서화 / 클라이언트 생성 자동화 활용 가능