Skip to content

[3주차] 송유경/[feat] 게시글 도메인 API 구현#124

Open
yukyoungs wants to merge 3 commits intoLeets-Official:송유경/mainfrom
yukyoungs:송유경/3주차

Hidden character warning

The head ref may contain hidden characters: "\uc1a1\uc720\uacbd/3\uc8fc\ucc28"
Open

[3주차] 송유경/[feat] 게시글 도메인 API 구현#124
yukyoungs wants to merge 3 commits intoLeets-Official:송유경/mainfrom
yukyoungs:송유경/3주차

Conversation

@yukyoungs
Copy link
Copy Markdown

1. 과제 요구사항 중 구현한 내용

  • 프로젝트 구조 구성 (Controller/Service/Domain/DTO 레이어 분리)
  • 게시글 생성, 단건 조회, 전체 조회, 수정, 삭제 API 구현
  • BaseTimeEntity를 활용한 생성/수정 시간 자동 기록
  • BaseResponse를 활용한 공통 응답 규격 적용 (timestamp, message, data 구조)
  • Swagger UI 연동 및 API 문서화 완료
  • Global Exception Handler를 통한 예외 처리 기반 마련

2. 핵심 변경 사항

  • BaseResponse 도입: 모든 API 응답을 일정한 규격으로 반환하도록 공통 DTO 설계
  • JPA Auditing 설정: JpaConfig 분리 및 BaseTimeEntity 상속을 통해 createdAt, updatedAt 자동화
  • Controller 레이어 최적화: @PathVariable 명시 및 @RestControllerAdvice를 활용한 예외 처리 구조 잡기
  • Swagger UI 설정: 최신 Spring Boot 버전과의 호환성 문제를 해결하기 위해 의존성 및 설정 최적화

3. 실행 및 검증 결과

  • 실행 결과: Swagger UI(localhost:8080/swagger-ui/index.html) 정상 접속 및 테스트 완료
  • 게시글 생성 (POST): 데이터 생성 시 BaseResponse에 담겨 응답하며 createdAt 값이 정상적으로 출력됨
  • 단건 조회 (GET): {id} 경로 변수를 통해 특정 게시글 조회 기능 확인
스크린샷 2026-04-07 오후 11 34 07 스크린샷 2026-04-07 오후 11 35 08 스크린샷 2026-04-07 오후 11 35 34 스크린샷 2026-04-07 오후 11 36 00 스크린샷 2026-04-07 오후 11 36 08 스크린샷 2026-04-07 오후 11 36 48

4. 완료 사항

  1. 게시판 도메인(Post) 엔티티 설계 및 JPA 연동 완료
  2. 서비스 레이어 로직 구현 (조회 시 예외 발생 처리 포함)
  3. BaseResponse 클래스 생성을 통한 API 응답 표준화
  4. Swagger UI를 통한 API 문서 자동화 및 테스트 환경 구축

5. 추가 사항

제출 체크리스트

  • PR 제목이 규칙에 맞다
  • base가 {이름}/main 브랜치다
  • compare가 {이름}/{숫자}주차 브랜치다
  • 프로젝트가 정상 실행된다
  • 본인을 Assignee로 지정했다
  • 파트 담당 Reviewer를 지정했다
  • 리뷰 피드백을 반영한 뒤 머지/PR close를 진행한다

Reviewer 참고

@yukyoungs yukyoungs requested a review from a team April 7, 2026 14:47
@yukyoungs yukyoungs self-assigned this Apr 7, 2026
@sky-0131
Copy link
Copy Markdown

sky-0131 commented Apr 9, 2026

각 서비스(health, post, user) 패키지를 구분하여, controller, dto, service를 정리한 이 인상 깊습니다! 저번 과제 리뷰에서 언급해주셨 domain 관련 구조 개선과 함께 배워 갑니다. 깔끔한 패키지 구조 덕분에 유지보수성이 크게 높아졌습니다.

Copy link
Copy Markdown
Member

@theSnackOverflow theSnackOverflow left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

도메인별 패키지 구조 리팩토링이 깔끔하게 잘 됐고, @Transactional(readOnly = true) + 변경 메서드 오버라이드 패턴, Post.update()로 dirty checking 활용, BaseResponse<T> 공통 응답 래퍼까지 전반적으로 완성도가 높네요. PostRequest를 inner static class로 Create/Update 분리한 것도 깔끔합니다.

몇 가지 확인해보시면 좋을 것 같은 부분 남겨봅니다!

// 게시글 수정 (PATCH /api/posts/{id})
@PatchMapping("/{id}")
public ResponseEntity<BaseResponse<PostResponse>> update(@Valid @PathVariable("id") Long id, @RequestBody PostRequest.Update request) {
PostResponse response = postService.update(id, request);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Valid@PathVariable("id") Long id에 붙어있는데요, Long 타입의 PathVariable에는 @Valid가 아무 효과가 없습니다. 유효성 검사가 필요한 건 @RequestBody PostRequest.Update request 쪽이에요!

public ResponseEntity<BaseResponse<PostResponse>> update(
    @PathVariable("id") Long id,
    @Valid @RequestBody PostRequest.Update request
)

public PostResponse findById(Long id) {
Post post = postRepository.findById(id)
.orElseThrow(() -> new IllegalArgumentException(ErrorCode.POST_NOT_FOUND.getMessage()));
return new PostResponse(post);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

게시글 미존재 시 IllegalArgumentException을 던지고 있는데요, GlobalExceptionHandlerIllegalArgumentException을 400 Bad Request로 처리하고 있어서 실제로는 400이 반환됩니다. ErrorCode.POST_NOT_FOUNDHttpStatus.NOT_FOUND를 이미 잘 정의해두셨으니 커스텀 예외 클래스를 만들어 연결해주시면 의도대로 404를 반환할 수 있어요!

public class PostNotFoundException extends RuntimeException {
    public PostNotFoundException(Long id) {
        super(ErrorCode.POST_NOT_FOUND.getMessage());
    }
}

// GlobalExceptionHandler
@ExceptionHandler(PostNotFoundException.class)
public ResponseEntity<ErrorResponse> handle(PostNotFoundException e) {
    return ResponseEntity.status(HttpStatus.NOT_FOUND)...;
}

import org.springframework.stereotype.Repository;

@Repository
public interface PostRepository extends JpaRepository<Post, Long> {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Repository가 붙어있는데, Spring Data JPA는 JpaRepository를 상속하면 자동으로 빈 등록이 이루어져서 @Repository를 직접 붙이지 않아도 됩니다. 제거해도 동작은 동일해요!

return postRepository.findAll().stream()
.map(PostResponse::new)
.collect(Collectors.toList());
}
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

.collect(Collectors.toList())는 Java 16부터 .toList()로 대체할 수 있어요. Spring Boot 3.2.5는 Java 17 이상 기반이라 그냥 .toList() 쓰시면 됩니다!

@daekyochung
Copy link
Copy Markdown

각 도메인(post, user, comment)별로 패키지를 구분하고 controller, service, repository, dto를 체계적으로 분리한 구조가 좋은거 같습니다! JPA Auditing 설정도 깔끔하게 되어있고, Swagger UI까지 구현하셔서 API 문서화도 완벽한거 같네요 고생하셨습니다!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants