REST API design 면접 질문
REST API 디자인 인터뷰는 확장 가능하고 유지보수 가능하며 사용자 친화적인 웹 API를 구축하는 능력을 평가합니다. 이러한 인터뷰는 백엔드, 풀스택 및 플랫폼 엔지니어링 역할, 특히 시니어 수준에서 일반적입니다. 면접관은 REST 원칙, 리소스 모델링, 오류 처리, 페이지네이션, 버전 관리 및 보안에 대한 이해를 평가합니다. 개념적 논의와 실습 코딩 문제가 모두 포함됩니다.
REST API design 면접에서 다루는 내용
RESTful 원칙 및 제약 조건
무상태성, 균일한 인터페이스, 리소스 식별, HTTP 메서드(GET, POST, PUT, DELETE, PATCH)와 상태 코드의 적절한 사용에 대한 이해.
리소스 모델링 및 명명
중첩 리소스, 복수 명사, 필터링, 정렬에 대한 직관적인 URI 패턴 설계 및 엔드포인트에서 동사 사용 피하기.
페이지네이션, 필터링 및 버전 관리
커서 기반 대 오프셋 페이지네이션 구현, 필터링/정렬 전략, URL 대 헤더 버전 관리 접근 방식.
오류 처리 및 보안
일관된 오류 응답 구조 설계, HTTP 상태 코드의 적절한 사용, 인증, 속도 제한, 입력 검증과 같은 일반적인 보안 관행.
샘플 REST API design 면접 질문
- 뉴스 기사 시스템을 위한 REST API를 설계하세요. 기사, 댓글, 태그에 대한 리소스와 엔드포인트를 어떻게 모델링하겠습니까?좋은 답변이 다루는 것
- 리소스 식별: 기사(articles), 댓글(comments), 태그(tags)를 핵심 리소스로 정의
- 엔드포인트 구조: /articles, /articles/{id}/comments, /tags/{id}/articles 등
- 관계 표현: 중첩 리소스 vs 참조(by ID) - 트레이드오프 고려
샘플 답변 보기
뉴스 기사 시스템의 REST API를 설계할 때, 기사(articles), 댓글(comments), 태그(tags)를 주요 리소스로 모델링합니다. 기사는 /articles 엔드포인트로, 개별 기사는 /articles/{articleId}로 접근합니다. 댓글은 기사에 종속된 리소스이므로 /articles/{articleId}/comments로 표현하며, 특정 댓글은 /articles/{articleId}/comments/{commentId}로 접근합니다. 태그는 독립 리소스로 /tags, /tags/{tagId}로 관리하고, 기사와 태그 간의 다대다 관계는 /articles/{articleId}/tags 또는 /tags/{tagId}/articles로 표현할 수 있습니다. 이때 중첩 리소스는 직관적이지만 깊이가 깊어질 경우 관리가 복잡해질 수 있으므로, 필요에 따라 쿼리 파라미터를 통해 필터링하는 방식도 고려해야 합니다. 또한, 댓글과 태그를 기사와 분리하여 참조 관계로 설계하면 확장성이 높아지지만 클라이언트에서 추가 요청이 필요할 수 있습니다. 트레이드오프를 고려하여, 일반적인 CRUD와 함께 검색, 정렬, 페이지네이션을 지원하는 것이 좋습니다.
- 사용자 CRUD API가 주어졌을 때, 소프트 삭제와 활성/삭제된 사용자 검색을 어떻게 구현하겠습니까?좋은 답변이 다루는 것
- 소프트 삭제: deleted_at 필드 사용, 실제 삭제 대신 플래그
- 활성 사용자: deleted_at IS NULL 조건
- 삭제된 사용자: deleted_at IS NOT NULL 조건
- API 엔드포인트: GET /users?status=active|deleted|all, DELETE /users/{id}는 소프트 삭제
샘플 답변 보기
소프트 삭제를 구현하기 위해 사용자 테이블에 deleted_at 타임스탬프 필드를 추가합니다. 삭제 요청 시 실제로 레코드를 제거하지 않고 현재 시간을 설정합니다. 활성 사용자 조회는 WHERE deleted_at IS NULL, 삭제된 사용자 조회는 WHERE deleted_at IS NOT NULL로 구현합니다. API는 GET /users 엔드포인트에 status 쿼리 파라미터를 추가하여 'active', 'deleted', 'all'을 선택할 수 있게 합니다. 기본값은 active로 합니다. DELETE /users/{id}는 소프트 삭제를 수행하고, 필요에 따라 영구 삭제를 위한 별도 엔드포인트(예: DELETE /users/{id}/hard)를 제공할 수 있습니다. 단, 소프트 삭제는 데이터 무결성을 유지하지만, unique constraint가 있을 경우 삭제된 레코드와 충돌할 수 있으므로 복합 unique 인덱스나 별도의 is_deleted 플래그를 활용할 수 있습니다.
- 대용량 트윗 컬렉션에 대한 페이지네이션을 어떻게 설계하겠습니까? 오프셋 기반과 커서 기반 페이지네이션을 비교하고 하나를 선택하세요.좋은 답변이 다루는 것
- 오프셋 기반: LIMIT/OFFSET, 단점: 큰 오프셋에서 성능 저하, 데이터 변동 시 중복/누락
- 커서 기반: WHERE cursor > last_seen, 안정적인 페이지, 실시간 데이터에 적합
- 선택: 대용량 트윗 컬렉션은 커서 기반 페이지네이션 권장
- 트레이드오프: 오프셋은 랜덤 접근 가능, 커서는 순차적 탐색에 유리
샘플 답변 보기
대용량 트윗 컬렉션의 경우 커서 기반 페이지네이션이 적합합니다. 오프셋 기반 페이지네이션은 LIMIT/OFFSET을 사용하여 구현이 간단하지만, 큰 오프셋에서 데이터베이스가 앞의 레코드를 모두 스캔해야 하므로 성능이 저하됩니다. 또한, 새로운 트윗이 추가되거나 삭제될 경우 페이지 간 중복 또는 누락이 발생할 수 있습니다. 반면, 커서 기반 페이지네이션은 클라이언트가 마지막으로 본 항목의 고유 식별자(예: 트윗 ID 또는 타임스탬프)를 커서로 전달하고, WHERE 조건으로 그 이후의 데이터를 조회합니다. 이는 인덱스를 활용하여 빠르고, 데이터 변동에도 안정적입니다. 단, 이전 페이지로 이동하거나 특정 페이지로 점프하는 것이 어렵다는 단점이 있습니다. 실시간 소셜 미디어 피드에는 커서 기반이 더 적합하므로, API에 cursor 파라미터와 함께 limit을 제공하고, 응답에 next_cursor를 포함시키는 방식을 선택합니다.
- 클라이언트가 특정 필드(희소 필드셋)를 요청하고 관련 리소스(예: 작성자 세부 정보가 포함된 게시물)를 포함할 수 있는 API를 설계하세요.좋은 답변이 다루는 것
- 희소 필드셋: fields 쿼리 파라미터로 요청 필드 명시
- 관련 리소스 포함: include 또는 expand 파라미터로 관련 리소스 요청
- 응답: 요청된 필드만 포함하고, 포함된 리소스는 별도 키로 제공
- GraphQL 대안 고려: REST에서 제한된 유연성, 오버페칭 방지
샘플 답변 보기
클라이언트가 특정 필드만 요청하고 관련 리소스를 포함할 수 있는 API를 설계하기 위해, GET /posts/{id}?fields=title,content&include=author를 예로 들 수 있습니다. fields 파라미터는 쉼표로 구분된 필드 목록을 받아 응답에서 해당 필드만 반환합니다. include 파라미터는 관련 리소스(예: 작성자)를 포함하도록 요청하며, 이 경우 author 객체를 별도 키 아래에 포함하거나, author 필드를 확장하여 author.id, author.name 등을 제공합니다. 서버는 요청된 필드만 선택적으로 로드하여 응답 크기를 줄입니다. 단, 이 방식은 복잡한 중첩 관계나 여러 수준의 포함을 처리할 때 어려움이 있을 수 있으며, GraphQL이 더 적합할 수 있습니다. 또한, 보안상 민감한 필드는 항상 제외하거나 권한에 따라 필터링해야 합니다.
- REST API를 어떻게 버전 관리하겠습니까? URI 버전 관리와 사용자 정의 요청 헤더 버전 관리의 장단점을 설명하세요.좋은 답변이 다루는 것
- URI 버전 관리: /v1/users, 장점: 직관적, 캐싱 용이, 단점: URI 오염, 리소스 식별 복잡
- 헤더 버전 관리: Accept: application/vnd.myapi.v1+json, 장점: URI 깔끔, 동일 리소스 유지, 단점: 클라이언트 구현 복잡, 캐싱 어려움
- 선택: 일반적으로 URI 버전 관리가 더 널리 사용됨
- 트레이드오프: URI는 브라우저에서 직접 테스트 용이, 헤더는 버전 협상에 유리
- 모범 사례: 가능하면 하위 호환성을 유지하고, 변경이 클 때만 버전 업
샘플 답변 보기
REST API 버전 관리에는 URI 버전 관리와 사용자 정의 요청 헤더 버전 관리가 있습니다. URI 버전 관리는 /v1/users처럼 경로에 버전을 포함시킵니다. 장점은 직관적이고, 캐싱이 용이하며, 클라이언트가 쉽게 사용할 수 있다는 점입니다. 단점은 URI가 오염되고, 동일 리소스에 여러 버전이 존재할 때 리소스 식별이 복잡해질 수 있습니다. 헤더 버전 관리는 Accept 헤더에 사용자 정의 미디어 타입(예: application/vnd.myapi.v1+json)을 사용합니다. 장점은 URI가 깔끔하고, 동일 리소스의 표현만 변경된다는 의미를 전달할 수 있습니다. 단점은 클라이언트 구현이 복잡하고, 일부 HTTP 캐시가 헤더를 고려하지 않을 수 있습니다. 일반적으로 URI 버전 관리가 더 널리 사용되며, 테스트와 문서화가 쉽습니다. 버전 관리는 큰 변화가 있을 때만 도입하고, 가능하면 하위 호환성을 유지하는 것이 좋습니다. API 제품에 따라 헤더 버전 관리가 유리할 수 있습니다.
- Authorization 헤더에서 API 키를 검증하고 누락되거나 유효하지 않으면 401을 반환하는 간단한 Express.js 미들웨어를 작성하세요.좋은 답변이 다루는 것
- Express.js 미들웨어 함수 작성
- Authorization 헤더 추출 및 Bearer 토큰 확인
- API 키 검증 로직 (예: 환경 변수와 비교)
- 누락 또는 유효하지 않으면 401 반환
- 유효하면 next() 호출
샘플 답변 보기
다음은 Express.js 미들웨어로 Authorization 헤더에서 API 키를 검증하는 구현 예시입니다. 이 미들웨어는 모든 보호된 라우트에 적용될 수 있습니다. API 키는 환경 변수에 저장되어 있다고 가정합니다. 헤더가 없거나 잘못된 형식이면 401을 반환하고, 키가 유효하지 않으면 403 또는 401을 반환합니다. 일반적으로 인증 실패는 401, 권한 부족은 403을 사용합니다.
참고 코드javascript // API 키 검증 미들웨어 const apiKeyMiddleware = (req, res, next) => { const authHeader = req.headers['authorization']; if (!authHeader) { return res.status(401).json({ error: 'Authorization 헤더가 누락되었습니다.' }); } // Bearer 스키마 확인 const parts = authHeader.split(' '); if (parts.length !== 2 || parts[0] !== 'Bearer') { return res.status(401).json({ error: '잘못된 Authorization 형식입니다. Bearer <token> 사용하세요.' }); } const apiKey = parts[1]; // 환경 변수에 저장된 API 키와 비교 (예: process.env.API_KEY) if (apiKey !== process.env.API_KEY) { return res.status(401).json({ error: '유효하지 않은 API 키입니다.' }); } // 인증 성공, 다음 미들웨어로 next(); }; // 사용 예: app.use('/api', apiKeyMiddleware); - 결제 API에 대한 오류 응답 구조를 설계하세요. 유효성 검사 오류, 잔액 부족, 서버 오류에 대한 예를 포함하세요.좋은 답변이 다루는 것
- 일관된 오류 응답 구조: code, message, details 필드
- 유형별 예: validation_error, insufficient_balance, server_error
- 상태 코드 활용: 400 (Bad Request), 402 (Payment Required), 500 (Internal Server Error)
- 세부 정보: 필드별 오류 배열 포함
샘플 답변 보기
결제 API의 오류 응답은 일관된 구조를 가져야 합니다. 기본 필드로 code (고유 오류 코드), message (사용자 친화적 메시지), details (선택적 상세 정보)를 포함합니다. 예를 들어, 유효성 검사 오류는 400 상태 코드와 함께 { "code": "validation_error", "message": "입력 값이 유효하지 않습니다.", "details": [{ "field": "card_number", "message": "올바른 카드 번호를 입력하세요." }] }를 반환합니다. 잔액 부족 오류는 402 (Payment Required) 상태 코드로 { "code": "insufficient_balance", "message": "잔액이 부족합니다.", "balance": 50 }을 반환할 수 있습니다. 서버 오류는 500과 함께 { "code": "server_error", "message": "내부 서버 오류가 발생했습니다." }를 반환합니다. 이 구조는 클라이언트가 오류를 프로그래밍 방식으로 처리할 수 있게 해줍니다.
- 공개 API에 대해 속도 제한을 어떻게 구현하겠습니까? 알고리즘을 설명하고 클라이언트에게 제한을 어떻게 전달하겠습니까?좋은 답변이 다루는 것
- 속도 제한 알고리즘: Token Bucket, Leaky Bucket, Sliding Window 등
- 구현: Redis를 사용한 Sliding Window Counter 또는 Token Bucket
- 클라이언트 전달: 응답 헤더 RateLimit-Limit, RateLimit-Remaining, RateLimit-Reset, Retry-After
- HTTP 상태 코드: 429 Too Many Requests
- 트레이드오프: 정확성 vs 리소스 사용
샘플 답변 보기
공개 API의 속도 제한은 주로 Sliding Window Log 또는 Token Bucket 알고리즘을 사용합니다. Sliding Window는 Redis의 Sorted Set을 이용해 타임스탬프를 저장하여 정확성을 높이지만, 메모리를 많이 사용할 수 있습니다. Token Bucket은 일정 속도로 토큰을 채우고 요청 시 소모하는 방식으로 간단하고 효율적입니다. 구현 시 Redis나 인메모리 캐시를 사용하는 것이 일반적입니다. 클라이언트에게 제한 정보를 전달하기 위해 응답 헤더에 RateLimit-Limit (허용된 요청 수), RateLimit-Remaining (남은 요청 수), RateLimit-Reset (리셋 시간, Unix 타임스탬프)를 포함시키고, 제한 초과 시 Retry-After 헤더와 함께 429 Too Many Requests 상태 코드를 반환합니다. 이는 클라이언트가 백오프 전략을 구현할 수 있게 합니다. 단, 분산 환경에서는 정확한 카운팅이 어려울 수 있으므로 근사치를 허용할 수도 있습니다.
준비 방법
- 항상 리소스와 그 관계를 식별하는 것부터 시작한 다음 적절한 HTTP 메서드로 엔드포인트에 매핑하세요.
- 선호하는 언어(예: Node.js/Express, Python/Flask)로 간단한 API를 모의하여 CRUD 작업과 오류 처리를 연습하세요.
- HATEOAS, PUT/DELETE의 멱등성, 안전하고 멱등적인 메서드와 같은 일반적인 API 디자인 패턴을 공부하세요.
- 트레이드오프를 논의할 준비를 하세요: 특정 페이지네이션 접근 방식이나 버전 관리 전략을 선택하는 이유.
- 화이트보드 연습을 하세요: 리소스 명명, 상태 코드, 오류 형식에 대한 설계 결정을 명확히 설명하세요.
자주 묻는 질문
REST API 디자인의 가장 흔한 실수는 무엇인가요?
엔드포인트에 동사를 사용하는 것(예: GET /users/:id 대신 /users/getUser). 또한 오류에 적절한 HTTP 상태 코드를 사용하지 않는 것입니다.
항상 HATEOAS를 사용해야 하나요?
HATEOAS는 완전한 REST 준수를 위한 제약 조건이지만, 실용적인 마이크로서비스에서는 단순화를 위해 생략하는 경우가 많습니다. 명확한 리소스 링크에 집중하세요.
부분 업데이트를 어떻게 처리하나요?
JSON Patch 또는 Merge Patch 형식으로 PATCH를 사용하세요. 부분 업데이트의 경우 요청 본문에 변경할 필드만 포함하세요.
API를 버전 관리하는 가장 좋은 방법은 무엇인가요?
URI 버전 관리(예: /v1/users)는 명시적이고 캐싱이 쉽지만, 헤더 버전 관리는 URL을 깔끔하게 유지합니다. 팀의 선호도에 따라 선택하세요.
REST API 디자인 인터뷰를 어떻게 연습하나요?
화이트보드에서 모의 인터뷰를 하거나 Postman과 같은 도구를 사용하세요. 트레이드오프와 사고 과정을 설명하는 데 집중하세요.
즉각적인 AI 피드백으로 REST API design 질문 연습하기
이력서를 업로드하고 맞춤형 모의 면접을 받아 무엇을 개선해야 할지 정확히 확인하세요 — 무료로 시작하세요.