[Java&Spring 면접 준비] Day 4 - Spring과 API 설계 및 통신

seri·2025년 8월 8일
0

1. RESTful하게 API를 설계할 때 주의해야 할 점은 무엇인가요?

RESTful API를 설계할 때는 자원을 URI로 명확하게 표현하고, 행위를 HTTP 메서드로 구분해 의미에 맞게 사용하는 것이 중요합니다.

예를 들어, 사용자 정보를 가져올 때는 GET /users/{id}처럼 명사 기반의 URI를 사용하고, POST는 자원 생성, PUT은 전체 수정, PUT는 일부수정, DELETE는 삭제로 사용하는 것이 RESTful한 방식입니다.

또한, URI에는 동사를 사용하지 않는 것, 상태 코드는 의도에 맞게 응답하는 것, 응답 포맷은 일관성 있게 JSON 등으로 제공하는 것이 중요한 포인트입니다.

꼬리질문:

→ 현업에서 PATCH보다 PUT을 더 쓰는 이유가 뭘까요?

1. 구현의 복잡성

  • PATCH부분 수정이기 때문에, 각 필드가 존재할 때만 업데이트해야 함
  • 이를 위해서는 DTO에서 null 값을 구분하거나, Optional 필드 처리, dirty checking 등을 별도로 구현해야 함
  • 즉, PUT보다 코드량과 로직 분기가 많아짐

2. 클라이언트가 불완전한 요청을 보낼 가능성

  • 클라이언트가 잘못된 요청으로 불필요한 필드를 누락하거나 이상한 조합으로 보낼 경우 예외 처리 복잡
  • PATCH는 유연하지만, 명확한 구조와 검증이 어려움

2. Spring에서 클라이언트 요청을 처리하는 방식은 어떻게 되나요?

Spring MVC에서는 클라이언트 요청이 들어오면 DispatcherServlet이 가장 먼저 요청을 받아 처리 흐름을 시작합니다.

DispatcherServlet은 요청 URL에 따라 적절한 Controller를 찾고, 그 내부에서 Service, Repository 등을 거쳐 비즈니스 로직이 수행됩니다.
처리 결과는 다시 DispatcherServlet으로 전달되어, 필요시 View로 렌더링되거나 JSON 응답으로 클라이언트에 반환됩니다.

즉, 전체 흐름은 [DispatcherServlet → Controller → Service → Repository → DB] → 응답 처리 순서로 이루어집니다.

3. Spring에서 JSON 데이터를 주고받기 위해 어떤 방식이나 라이브러리를 사용했나요?

Spring에서는 JSON 데이터를 주고받기 위해 @RequestBody@ResponseBody를 주로 사용합니다.

클라이언트로부터 받은 JSON은 @RequestBody를 통해 자바 객체로 변환하고, 서버에서 응답할 객체는 @ResponseBody를 통해 JSON으로 직렬화됩니다.

이 과정은 내부적으로 Jackson 라이브러리가 자동으로 처리해주며, Spring Boot에서는 기본적으로 설정돼 있어서 별도의 설정 없이도 편리하게 사용할 수 있었습니다.

꼬리질문:

→ 캐시 저장 시 JSON 형태를 직접 커스터마이징하거나 직렬화 방식을 변경해본 경험이 있으신가요?"

Jackson의 ObjectMapper를 활용한 JSON 커스터마이징을 진행했습니다.
@JsonInclude(JsonInclude.Include.NON_NULL)을 이용해 불필요한 null 필드를 제거해 캐시 공간 절약하고, JSON 응답을 간결하게 만들었습니다.
또한 @JsonValue@JsonCreator를 사용해 직렬화 방식을 변경해 enum 타입은 사용자 친화적인 값으로 JSON에 노출되도록 했습니다.

4. HTTP 상태 코드 중 2xx, 4xx, 5xx 은 각각 어떤 의미인가요?

  • 2xx (성공): 클라이언트의 요청이 성공적으로 처리되었음을 의미합니다. 예를 들어 200 OK, 201 Created가 있습니다.
  • 4xx (클라이언트 오류): 클라이언트 요청에 문제가 있을 때 사용되며, 예를 들어 400 Bad Request, 401 Unauthorized, 404 Not Found 등이 있습니다.
  • 5xx (서버 오류): 서버 내부에서 처리 중 예기치 못한 문제가 발생했을 때 사용됩니다. 대표적으로 500 Internal Server Error가 있습니다.

꼬리질문:

→ 상태 코드를 커스텀할때 어떤 식으로 구현하셨나요?

상태 코드를 enum으로 관리해서 코드 번호, 메시지, 대응하는 HTTP 상태 코드를 한 곳에서 정의했습니다.
예를 들어 ErrorCode.INVALID_INPUT(400, "입력값이 유효하지 않습니다")처럼 구성해서 공통 응답 포맷에 적용했습니다.

→ 상태코드 커스텀할때 고민했던 부분이 있나요?

가장 고민했던 부분은 400 Bad Request401 Unauthorized의 구분이었습니다.

HTTP 스펙상으로는 비밀번호가 틀렸을 때 401을 반환하는 것이 맞지만,
실무에서는 401을 사용하면 오히려 “아이디는 맞고 비밀번호만 틀렸다”는 식의 힌트를 공격자에게 줄 수 있다는 보안상 우려가 있었습니다.

그래서 "아이디 불일치, 비밀번호 불일치, 입력값 오류” 같은 로그인 실패 상황을 모두 400 Bad Request로 통일해서 처리하기로 했습니다.

대신, 내부적으로는 AUTH_001, AUTH_002처럼 에러 코드와 메시지를 분리한 커스텀 응답 구조를 설계해서
프론트엔드가 실패 원인을 구분해서 처리할 수 있도록 했습니다.
사용자에게는 항상 “아이디 또는 비밀번호가 일치하지 않습니다.”처럼 안전하고 일반적인 메시지만 노출되도록 조정했습니다.

→ Refresh token이 탈취됐을때 어떻게 처리하나요?

  1. Refresh Token 서버 저장 (예: Redis)
    Refresh Token은 클라이언트에만 보관하지 않고, 서버(Redis)에 사용자 ID 기준으로 저장합니다.
    토큰 재발급 요청 시, 서버에 저장된 토큰과 비교해 일치할 경우에만 발급 처리합니다.

  2. 비밀번호 변경 시 Refresh Token 삭제
    사용자가 비밀번호를 변경하면, 해당 계정의 모든 Refresh Token을 서버에서 삭제합니다.
    이렇게 하면 다른 디바이스에서 로그인 상태라도, 이후 재발급이 불가능해집니다.

  3. Access Token 블랙리스트 처리
    Access Token은 stateless해서 원래는 서버에서 제어가 불가능하지만,
    탈취가 의심되는 경우에는 해당 토큰을 Redis 블랙리스트에 저장해 차단합니다.

  4. 요청 처리 시, 블랙리스트 확인
    클라이언트가 Access Token으로 요청할 때, 먼저 Redis에 블랙리스트 여부를 확인하고, 등록된 경우 401 Unauthorized 응답을 반환합니다.

5. Spring에서 외부 API 호출이 필요한 경우 어떻게 처리하나요?

Spring에서는 외부 API 호출 시 주로 RestTemplate 또는 WebClient를 사용합니다.

전통적으로는 RestTemplate이 많이 사용되며, 동기 방식으로 간단한 호출에 적합합니다.
반면, WebClient는 Spring 5부터 등장한 비동기 방식의 클라이언트로, 비동기 처리나 리액티브 프로그래밍이 필요할 때 적합합니다.

실제로 제가 작업했던 프로젝트에서는 RestTemplate을 사용해 API를 호출하고, 응답을 파싱해 클라이언트에 전달하는 기능을 구현한 경험이 있습니다.

profile
꾸준히 정진하며 나아가기

0개의 댓글