Skip to content

[3주차] 정대교/[feat] 게시글 도메인 API 구현#113

Open
daekyochung wants to merge 2 commits intoLeets-Official:정대교/mainfrom
daekyochung:정대교/3주차

Hidden character warning

The head ref may contain hidden characters: "\uc815\ub300\uad50/3\uc8fc\ucc28"
Open

[3주차] 정대교/[feat] 게시글 도메인 API 구현#113
daekyochung wants to merge 2 commits intoLeets-Official:정대교/mainfrom
daekyochung:정대교/3주차

Conversation

@daekyochung
Copy link
Copy Markdown

@daekyochung daekyochung commented Apr 7, 2026

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

  • Post CRUD API 구현 (Controller/Service 레이어 변경)
  • 에러처리 API 구현 ('GET /health')
  • 문제점 2개 변경 API 구현 ('POST /string/repeat')
  • 공통 추가 구현 내용 (전체)

2. 핵심 변경 사항

  • GlobalExceptionHandler 및 Custom Exception 클래스 추가
  • PostListResponse, PostResponse 등 DTO 구현
  • 조회수 증가 기능 (increaseViewCount) 추가

3. 실행 및 검증 결과

구현 내용:

  • GET /posts - 게시글 목록 조회 (pagination)
  • GET /posts/{postId} - 게시글 상세 조회
  • POST /posts - 게시글 작성
  • PUT /posts/{postId} - 게시글 수정
  • DELETE /posts/{postId} - 게시글 삭제
image image image image

4. 완료 사항

  1. Build successful

5. 추가 사항

  • 관련 이슈: closed #이슈번호

제출 체크리스트

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

Reviewer 참고

@daekyochung daekyochung requested a review from a team April 7, 2026 13:53
@daekyochung daekyochung self-assigned this Apr 7, 2026
@daekyochung daekyochung changed the title 3주차 과제: [3주차] 정대교/[feat] 게시글 도메인 API 구현 [3주차] 정대교/[feat] 게시글 도메인 API 구현 Apr 7, 2026
- Post Entity nullable 설정 수정
- PostListResponse null 처리 추가
- API 테스트 완료 (POST, GET, PUT, DELETE)
@sky-0131
Copy link
Copy Markdown

sky-0131 commented Apr 9, 2026

상황 별로 예외 처리 파일을 세분화 한 이 인상 깊습니다! 예외 처리를 하나로 묶어서 관리하는 것이 편하다고 생각했는데, 이렇게 나누어 관리하니 의도가 명확하게 다가오고 오류가 발생할 때 유지 보수에도 좋을 것 같습니다.

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.

커스텀 예외 클래스를 PostNotFoundException, ForbiddenException 등 타입별로 분리하고 GlobalExceptionHandler에서 각각 처리하는 구조가 깔끔하게 잡혀있네요. 생성 시 201 Created, 삭제 시 204 No Content 등 HTTP 상태 코드도 의미에 맞게 잘 반환해주셨습니다.

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

public class PostListResponse {

private List<Long> postId;
private List<String> title;
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.

응답 DTO가 컬럼별로 List<Long> postId, List<String> title처럼 구성되어 있는데요, 이 구조는 게시글 하나를 표현하는 단위가 없어서 클라이언트가 인덱스로 각 필드를 조합해야 합니다. 일반적으로는 게시글 하나를 나타내는 inner DTO를 만들고 List<PostSummary> 형태로 감싸는 구조를 사용해요!

@Getter
@AllArgsConstructor
public class PostListResponse {
    private List<PostSummary> posts;

    @Getter
    @Builder
    public static class PostSummary {
        private Long postId;
        private String title;
        private String nickname;
        private LocalDateTime createdAt;
    }
}

@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@Setter
@NoArgsConstructor
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.

엔티티에 @Setter가 추가됐는데요, 이렇게 하면 서비스나 컨트롤러 어느 곳에서든 post.setTitle(...) 형태로 필드를 직접 변경할 수 있어서, 데이터가 어디서 바뀌는지 추적하기 어려워집니다. JPA 엔티티는 변경이 필요한 경우 의미 있는 이름의 메서드(예: post.update(title, content))를 정의하고, @Setter는 제거하는 패턴을 권장해요!

@NoArgsConstructor(access = AccessLevel.PROTECTED)도 무분별한 new Post() 생성을 막아주는 좋은 패턴이라, 원래대로 되돌려주시면 좋을 것 같아요.

private Long id;

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "user_id", nullable = false)
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.

user_idnullable = true로 변경하셨는데, 혹시 의도하신 건가요? 게시글에 작성자 정보가 없어도 되는 구조라면 맞지만, 대부분의 경우 게시글은 반드시 작성자가 있어야 하므로 nullable = false가 더 적절할 것 같아요.

*/
@PostMapping
public ResponseEntity<PostResponse> createPost(@RequestBody PostCreateRequest request) {
PostResponse response = postService.createPost(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.

@RequestBody 앞에 @Valid가 빠져 있어서 PostCreateRequest@NotBlank 검증이 실제로 동작하지 않는 상태예요. @Valid를 추가해주시면 GlobalExceptionHandlerMethodArgumentNotValidException 처리와 바로 연결됩니다!

public ResponseEntity<PostResponse> createPost(@RequestBody @Valid PostCreateRequest request)

updatePost@RequestBody에도 동일하게 적용해주시면 좋을 것 같아요.

.orElseThrow(() -> new PostNotFoundException(postId));
post.increaseViewCount();
postRepository.save(post);
return PostResponse.from(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.

increaseViewCount() 호출 후 postRepository.save(post)를 명시적으로 부르고 계신데요, @Transactional 어노테이션이 있으면 트랜잭션 안에서 엔티티 상태가 변경될 때 Hibernate의 dirty checking이 자동으로 감지해서 커밋 시 UPDATE 쿼리를 날려줍니다. save를 명시적으로 부를 필요가 없어요!

현재 PostService@Transactional이 없는 상태라 increaseViewCount의 변경이 DB에 반영되지 않을 수도 있어요. @Transactional을 추가해주시면 save 호출도 함께 제거할 수 있습니다.

spring.jpa.hibernate.ddl-auto=update
spring.jpa.hibernate.ddl-auto=create-drop
spring.jpa.show-sql=true
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQLDialect No newline at end of file
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.

ddl-auto=create-drop은 애플리케이션이 시작될 때마다 테이블을 새로 만들고 종료 시 삭제해서, 재시작하면 데이터가 모두 사라집니다. 개발 초기에 스키마 확인용으로 쓰셨을 것 같은데, updatevalidate로 되돌려두시는 게 안전할 것 같아요.

return PostResponse.from(post);
}

public PostResponse createPost(PostCreateRequest 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.

titlecontent의 null/blank 체크를 서비스에서 직접 하고 계신데, PostCreateRequest에 이미 @NotBlank가 달려있으니 컨트롤러에 @Valid를 추가하면 이 검증 로직은 서비스에서 제거해도 됩니다. 검증은 진입점(컨트롤러)에서 한 번만 하는 게 역할 분리에 더 맞아요!

@yukyoungs
Copy link
Copy Markdown

CRUD 기능을 정말 꼼꼼하게 다 구현하셨네요! 특히 별도의 .http 파일로 테스트 환경까지 구성하신 점이 인상 깊어요 더 좋은 코드를 위해 몇 가지 의견 드려요!

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