level2
9 posts
API Break Change 방지를 위한 리스트 형태의 JSON 응답 수정

배경 우아한테크코스의 세 번째 미션을 진행하며, 리뷰어께서 좋은 의견을 주셨습니다. 웹 구현을 처음 해보는 입장에서 생각지도 못했던 에 대한 것인데요, API JSON 응답은 List가 아닌 Object 형식으로 하는 것을 권하셨고 이번 글에서는 이 내용에 대해 기록해보고자 합니다. API Break Change란? 출처에 있는 글에서는 Breaking Change를 다음과 같이 설명합니다. Abreaking changeis when one such change causes a client application to break somehow. While some changes make a minimal impact, breaking changes are those fundamental changes that cause the system to cease functioning. This could be a change in a field name, the removal of an …

Spring Data JPA에서의 동적 쿼리 2 - Specification 활용

목표 이번 글에서는, 지난 편에서 알아본 Specification을 이용해 로 예약을 조회하는 동적 쿼리를 만들어 보겠습니다.😄 기본 코드 Entity 이전 1편에 작성된 내용이지만, 다시 한번 작성하겠습니다. Member, Theme, ReservationTIme는 다음과 같이 구성되어 있습니다. Member: 및 에 해당되는 을 필드로 가집니다. Theme: ID 및 에 해당되는 을 필드로 가집니다. ReservationTime: ID 및 에 해당되는 을 필드로 가집니다. API 를 통해 호출하며, 쿼리 파라미터를 이용합니다. 파라미터의 구성은 다음과 같습니다. 값을 선택하지 않는 경우는 전체를 조회합니다. 회원(memberId): 선택한 회원의 ID(PK)값. 테마(themeId): 회원과 동일합니다. 시작 날짜(startDate): 선택한 날짜도 범위에 포함하며, 형식입니다. 종료 날짜(endDate): 시작 날짜와 동일합니다. Endpoint 설정은 Java…

Spring Data JPA 에서의 동적 쿼리 1 - Specification 탐구

배경 우아한테크코스의 세 번째 스프링 미션의 첫 번째 요구사항은, 기존의 JDBC 구현을 Spring Data JPA로 바꾸는 것이었습니다. 다른 부분은 크게 어렵지 않았지만, 관리자가 특정 조건에 해당하는 예약을 조회하는 기능이 그나마(?) 어려웠던 것 같습니다. 예약 검색은 를 이용하는 것이었는데요, 저는 이전 미션에서 이 네 가지 값이 모두 입력되지 않으면 예외를 발생시켰는데 페어는 동적 쿼리를 이용해서 네가지 값이 모두 입력되지 않으면 전체 예약을 조회하고, 하나의 값만 입력되도 그 값으로 조회하도록 구현을 했었습니다. 결과적으로는 동적 쿼리로 조회하는 것이 사용자에게 더 편하겠다고 생각했고, Spring Data JPA의 Specification을 이용하여 이를 구현할 수 있었습니다. 그래서 이번 글에서는 Specification에 대해 다루고, 다음 글에서는 이를 활용하여 문제를 해결해 보겠습니다😄 Specification 알아보기 개요 JPA 2 introduces …

날짜와 시간의 직렬화 & 역직렬화 시도 - JsonFormat, ObjectMapper

배경 우아한테크코스의 세 번째 스프링 미션을 진행하며 코드 리뷰를 받던 도중 리뷰어께서 좋은 의견을 공유해 주셨습니다. 의견은 기존의 을 중복해서 사용하는 코드를 ObjectMapper를 만들어 해결하는 것이었는데요, 여기에 더해서, 미션을 하며 그냥 대략적으로만 알고 사용했던 @JsonFormat에 대해서도 알아보는 과정을 기록하고자 합니다. @JsonFormat 이란? 공식 문서에 따르면, JsonFormat을 다음과 같이 설명합니다. General-purpose annotation used for configuring details of how values of properties are to be serialized. Unlike most other Jackson annotations, annotation does not have specific universal interpretation: instead, effect depends on datatype of propert…

회원 역할에 따른 API 접근 - Spring Interceptor

배경 우아한테크코스의 두 번째 미션에서의 새로운 요구사항은 JWT를 이용해 로그인 기능을 구현하고, 역할에 따라 접근 권한을 다르게 설정하는 것이었습니다. 요구사항에 명시된 것은 로그인 된 회원이 직접 예약을 추가하는 기능 구현과 관리자 페이지 접근을 제한하는 것이었는데요, 이 두 가지와 더불어 관리자와 회원의 역할을 조금 더 명확하게 나누기 위해 Spring Interceptor를 이용했던 경험을 기록하고자 합니다. 글에서는 스프링 인터셉터를 두 가지 방식으로 구현합니다. 먼저 경로를 지정하는 방법을 사용하여 구현한 후, 커스텀 어노테이션을 이용한 방법으로 개선해보겠습니다. 또한, ArgumentResolver를 사용하는 관점에 대해서도 작성하겠습니다. API 분류 우선, 현재 있는 API를 역할별로 구분해볼 필요가 있을 것 같습니다. 1. 로그인을 하지 않아도 접근 가능 Endpoint HTTP Method 기능 /login POST 로그인 요청 /themes/weekly GE…

스프링 입력에서의 예외 처리 여정 3 - Custom Deserializer

서론 드디어 마지막이네요. 처음 이 글을 작성하고자 했을 때는 3편까지 쓸 것이라는 생각을 전혀 안했는데..ㅎㅎ 최대한 간단하게 쓴다고 노력해도 역시 욕심은 끝이 없는 것 같습니다. 이번에는 지난번에 학습한 JsonNode를 활용해서 Custom Deserializer를 직접 만들어 볼텐데요, JsonNode가 헷갈리신다면 이전 편를 확인해주시면 감사하겠습니다.🙇 해결해야 할 것 이번 Custom Deserializer를 통해 해결해야 하는 문제는, 1편의 맨 마지막에 나온 두 가지 문제입니다. 본문을 시작하기 전에 간단하게 리마인드 하고 가겠습니다 ㅎㅎ 지금의 예외 핸들링은, 테마, 시간, 멤버를 선택하지 않았을 때 기본 입력값인 등에 의존합니다. 즉 클라이언트 코드에 완전히 의존하는 구조입니다. 예약을 추가할 때 멤버, 시간, 테마 중 2개 이상의 값이 입력되지 않아도 하나의 값만 표시됩니다. 즉 입력되지 않은 모든 값을 예외 메시지에 담을 수 없습니다. 추가적으로, 날짜를 …

스프링 입력에서의 예외 처리 여정 2 - JsonNode

이전 편 내용 요약 어노테이션의 검증을 통해 발생하는 예외는 입니다. 테마, 시간 추가의 경우 값을 입력하지 않으면 빈 문자열()으로 JSON에 담겼기에 를 통해 이 발생했습니다. 예약을 추가할 때는 회원, 날짜, 테마, 시간을 입력받습니다. 날짜의 경우 입력하지 않으면 빈 문자열로 요청 JSON에 담기기에() MethodArgumentNotValidException이 발생합니다. 회원, 테마, 시간은 입력하지 않으면 각각 빈 문자열이 아닌 으로 값이 담기고, 이 값을 Long 타입으로 파싱할 수 없습니다. 따라서 역직렬화 과정에서 InvalidFormatException이 발생하고, Jackson은 이 예외를 HttpMessageNotReadableException으로 던집니다. 결론: 하나의 요청에서 다른 타입의 예외들이 발생하는데 이 예외를 한 번에 처리할 수가 없었습니다. Custom Deserializer 시작 지금 현재의 문제를 크게 보면 역직렬화 과정에서 발생…

스프링 입력에서의 예외 처리 여정 1 - 문제 인식 및 일부 해결

배경 우아한테크코스의 두 번째 스프링 미션을 통해 처음으로 스프링의 예외 처리를 경험하게 되었습니다. 미션의 요구 사항은 예약, 테마, 시간 생성시 발생하는 예외를 적절하게 처리하는 것이었는데요, 와 것과 같은 예외 처리는 크게 어렵지 않았으나 입력에서의 예외, 즉 입력되지 않은 값 등 값 자체가 잘못되었을 때에 대한 처리가 가장 어려웠습니다. 가장 많이 헤맸던 이유는 요청 상황마다 발생하는 예외 타입이 달랐기 때문인데요, 이번 글에서는 해당 문제와 이 문제를 해결해가는 과정에 대해 기록해보려 합니다. 주의 스프링을 이번에 처음 사용하게 되어, 내용이 매우 부실할 수 있습니다. 이 글은 지식을 전달하는 글이 아닌, 개인의 시행착오 과정을 기록하는 글임을 감안해주시면 감사하겠습니다.🙇 API 구성 API - 관리자가 직접 예약을 추가 관리자가 직접 예약을 추가할 땐, 예약 페이지에서 이미 등록된 회원, 테마, 시간과 날짜를 선택합니다. 이때 회원, 테마, 시간은 DB에 저장된 I…

Layered Architecture 적용 과정에서의 DTO 사용에 대한 고민

배경 우아한테크코스의 첫 스프링 미션을 진행하며, 처음으로 레이어드 아키텍쳐를 적용해보는 경험을 하게 되었습니다. Controller에서 JdbcTemplate을 사용하여 DB 처리를 하는 기존 코드에 Service - Repository 계층을 추가하는 과정에서 자연스레 들었던 고민은 도메인과 DTO의 처리를 어떻게 해야할지였고, 이때 가졌던 생각의 흐름을 정리해보고자 합니다. 아래의 예시는 예약을 추가(저장) 하는 기능을 바탕으로 작성하였습니다😄 개요 API의 구성 예약을 추가할 때는 을 JSON 형태로 요청합니다. 예약 시간은 별도의 데이터베이스 테이블에 저장을 해둔 뒤, 시간의 ID값을 이용하여 조회합니다. 요청이 들어오면 ID값은 자동으로 채운 뒤(AUTO_INCREMENT), 입력된 시간 ID에 해당되는 예약 시간까지 불러와서 저장된 예약 내역을 응답하는 구조입니다. 도메인 여기서 날짜와 시간은 각각 LocalDate와 LocalTime을 사용할 수 있으나, 이번 단계…