Conversation
|
커밋 메시지가 참 보기 좋네요 👍 |
| // [헬퍼 메서드] 채널 존재 여부를 검증하고 엔티티를 반환 (중복 코드 제거 및 예외 처리 공통화) | ||
| private Channel findChannelEntityById(UUID id) { | ||
| return channelRepository.findById(id) | ||
| .orElseThrow(() -> new IllegalArgumentException("채널을 찾을 수 없습니다.")); | ||
| } |
There was a problem hiding this comment.
좋습니다 👍 사실 여기서 한단계 더 나아가면 ~finder와 같은 네이밍으로 별도 컴포넌트로 빼도 좋습니다. ChannelFinder와 같은 모듈로 분리하여 처리하면 재사용성도 챙길 수 있고 더 깔끔해지거든요. 나중에 한 번 적용해보세요
| return convertToResponse(findUserEntityById(id)); | ||
| User user = findUserEntityById(id); | ||
| loadUserStatus(user); | ||
| return convertToResponse(user); |
There was a problem hiding this comment.
ResponseDto로 변환하는 역할이 Service의 책임일까요? 한번 고민해보시면 좋을 것 같습니다! 이 로직이 Service 말고 Controller로 빼면 해당 메서드가 하나의 Response로 국한되지 않을 수 있습니다
There was a problem hiding this comment.
이건 .gitignore로 뺴야 합니다!
| import org.springframework.web.bind.annotation.RestController; | ||
|
|
||
| @RestController | ||
| @RequestMapping("/api/auth") |
There was a problem hiding this comment.
v1 버저닝을 추가 해주는 것도 좋습니다 (계속 버전이 변화될 수 있기 때문에) 나중에 추가하긴 어렵거든요
| @RequestMapping(value = "/find", method = RequestMethod.GET) | ||
| public ResponseEntity<BinaryContent> find(@RequestParam("binaryContentId") UUID binaryContentId) { | ||
| BinaryContent content = binaryContentService.findEntityById(binaryContentId); | ||
| return ResponseEntity.ok(content); | ||
| } |
There was a problem hiding this comment.
이것도 ResponseDTO 별도로 선언해주는게 더 좋을 것 같습니다!
| // TODO: 채널 생성자 정보가 없으므로 로직 추가 예정. (채널을 누가 만들었는지 모름) | ||
| @RequestMapping(value = "/public", method = RequestMethod.POST) | ||
| public ChannelDto.Response createPublicChannel(@RequestBody ChannelDto.CreatePublicRequest createPublicRequest) { | ||
| return channelService.createPublicChannel(createPublicRequest); | ||
| } | ||
|
|
||
| // TODO: UUID 형식이 맞으면 비공개 채널 생성이 가능한 상태, 추후 전역 처리 시 검증 로직 추가 예정 | ||
| @RequestMapping(value = "/private", method = RequestMethod.POST) | ||
| public ChannelDto.Response createPrivateChannel(@RequestBody ChannelDto.CreatePrivateRequest createPrivateRequest) { | ||
| return channelService.createPrivateChannel(createPrivateRequest); | ||
| } |
There was a problem hiding this comment.
과제에서 요구사항 대로 하신 것 같아 이해하지만, [POST] "/api/channels/public, private" private, public을 Body 값 안에 넣어서 처리하는 방식이 더 깔끔할 것 같긴 합니다. 정말 분리되어야 하면 모르겠지만 거의 구현 코드가 비슷할거거든요
| // 유저 등록 | ||
| @RequestMapping(method = RequestMethod.POST) | ||
| public UserDto.Response create(@RequestBody UserDto.CreateRequest request) { | ||
| return userService.create(request); | ||
| } |
There was a problem hiding this comment.
ResponseDTO 별도로 선언해주신 것 좋네요 👍
| @Getter | ||
| public enum ErrorCode { | ||
| // Global (0~99) | ||
| INVALID_INPUT_VALUE(HttpStatus.BAD_REQUEST, "G001", "잘못된 요청입니다."), | ||
| REQUIRED_PARAMETER_MISSING(HttpStatus.BAD_REQUEST, "G002", "필수 입력 값이 누락되었습니다."), | ||
| PATH_ID_MISMATCH(HttpStatus.BAD_REQUEST, "G003", "요청 경로의 ID와 데이터의 ID가 일치하지 않습니다."), | ||
| INTERNAL_SERVER_ERROR(HttpStatus.INTERNAL_SERVER_ERROR, "G004", "서버 내부 오류가 발생했습니다."), | ||
|
|
||
| // System (100~199) | ||
| DIRECTORY_CREATE_FAILED(HttpStatus.INTERNAL_SERVER_ERROR, "S101", "디렉토리 생성에 실패했습니다."), | ||
| FILE_SAVE_ERROR(HttpStatus.INTERNAL_SERVER_ERROR, "S102", "파일 저장 중 오류가 발생했습니다."), | ||
| FILE_DELETE_ERROR(HttpStatus.INTERNAL_SERVER_ERROR, "S103", "파일 삭제 중 오류가 발생했습니다."), | ||
| BINARY_CONTENT_NOT_FOUND(HttpStatus.BAD_REQUEST, "S104", "첨부된 파일 정보를 찾을 수 없습니다."), | ||
|
|
||
| // Auth (200~299) | ||
| LOGIN_FAILED(HttpStatus.UNAUTHORIZED, "A201", "아이디 또는 비밀번호가 일치하지 않습니다."), | ||
|
|
||
| // User (300~399) | ||
| INVALID_USERNAME(HttpStatus.BAD_REQUEST, "U301", "이름은 공백 없이, 2~10자 사이여야 합니다."), | ||
| INVALID_EMAIL(HttpStatus.BAD_REQUEST, "U302", "이메일은 공백 없이 필수 입력 사항입니다."), | ||
| INVALID_PASSWORD(HttpStatus.BAD_REQUEST, "U303", "비밀번호는 공백 없이 8자 이상이어야 합니다."), | ||
| USER_NOT_FOUND(HttpStatus.BAD_REQUEST, "U304", "존재하지 않은 사용자입니다."), | ||
| DUPLICATE_EMAIL(HttpStatus.BAD_REQUEST, "U305", "이미 존재하는 이메일입니다."), | ||
| DUPLICATE_USERNAME(HttpStatus.BAD_REQUEST, "U306", "이미 존재하는 이름입니다."), | ||
|
|
||
| // Channel (400~499) | ||
| INVALID_CHANNEL_NAME(HttpStatus.BAD_REQUEST, "C401", "채널 이름은 공백없이, 2~15자 사이여야 합니다."), | ||
| CHANNEL_NOT_FOUND(HttpStatus.BAD_REQUEST, "C402", "채널을 찾을 수 없습니다."), | ||
| ALREADY_IN_CHANNEL(HttpStatus.CONFLICT, "C403", "이미 채널에 참여 중인 유저입니다."), | ||
| NOT_A_MEMBER(HttpStatus.BAD_REQUEST, "C404", "채널 멤버가 아니면 요청을 수행할 수 없습니다."), | ||
| PRIVATE_CHANNEL_NOT_UPDATABLE(HttpStatus.BAD_REQUEST, "C405", "비공개 채널은 수정할 수 없습니다."), | ||
|
|
||
| // Message (500~599) | ||
| EMPTY_MESSAGE_CONTENT(HttpStatus.BAD_REQUEST, "M501", "메세지 내용을 입력해주세요."), | ||
| MESSAGE_TOO_LONG(HttpStatus.BAD_REQUEST, "M502", "메세지는 500자 이하로 작성해주세요."), | ||
| MESSAGE_NOT_FOUND(HttpStatus.BAD_REQUEST, "M503", "존재하지 않는 메세지입니다."), | ||
|
|
||
| // Status (600~699) | ||
| USER_STATUS_NOT_FOUND(HttpStatus.BAD_REQUEST, "STAT601", "유저 상태 정보를 찾을 수 없습니다."), | ||
| USER_STATUS_ALREADY_EXISTS(HttpStatus.CONFLICT, "STAT602", "해당 유저의 상태 정보가 이미 존재합니다."), | ||
| READ_STATUS_ALREADY_EXISTS(HttpStatus.CONFLICT, "STAT603", "이미 존재하는 읽음 상태입니다."), | ||
| READ_STATUS_NOT_FOUND(HttpStatus.BAD_REQUEST, "STAT604", "읽음 상태 정보를 찾을 수 없습니다."); | ||
|
|
||
| private final HttpStatus status; | ||
| private final String code; | ||
| private final String message; | ||
|
|
||
| ErrorCode(HttpStatus status, String code, String message) { | ||
| this.status = status; | ||
| this.code = code; | ||
| this.message = message; | ||
| } | ||
| } No newline at end of file |
| List<UUID> attachmentIds = new ArrayList<>(); | ||
| if (request.attachments() != null && binaryContentRepository != null) { | ||
| request.attachments().forEach(att -> { | ||
| BinaryContent content = new BinaryContent( | ||
| UUID.randomUUID(), | ||
| att.fileName(), | ||
| att.data(), | ||
| Instant.now() | ||
| ); | ||
| binaryContentRepository.save(content); | ||
| attachmentIds.add(content.getId()); | ||
| }); | ||
| } |
There was a problem hiding this comment.
만약 실제 DB가 연동됐다면 attachments 수 만큼 save가 실행되고 insert 문이 실행됐을겁니다. 한번에 호출하여 처리할 방법은 없을지 고민해보시죠!
기본 요구사항
컨트롤러 레이어 구현
웹 API 요구사항
사용자 관리
권한 관리
채널 관리
메시지 관리
메시지 수신 정보 관리
바이너리 파일 다운로드
예외 처리
API 테스트
Sprint-Mission 4.postman_collection.json
심화 요구사항
정적 리소스 서빙
생성형 AI 활용