[Proj. SARAMARA] πŸ“ κ°œλ°œμΌμ§€ 2

IToriginalΒ·2023λ…„ 6μ›” 26일
0
post-thumbnail

λ‚΄κ°€ 맑은 κ²Œμ‹œκΈ€ μ„œλΉ„μŠ€λ₯Ό κ°œλ°œν•˜κΈ° μœ„ν•΄ λ¨Όμ € κ²Œμ‹œκΈ€ μž‘μ„±μ— λŒ€ν•œ APIλ₯Ό κ°œλ°œν–ˆλ‹€.

API 개발 μ‹œμž‘μ— μ•žμ„œ μ„€κ³„ν•œ ERD와 API λͺ…μ„Έμ„œλ₯Ό ν†΅ν•΄μ„œ Entity 확인과 API pathλ₯Ό ν™•μΈν–ˆλ‹€.
μ„€κ³„ν•œ Entityλ₯Ό 확인을 ν•œ 이후, κ²Œμ‹œκΈ€ μž‘μ„±μ— ν•„μš”ν•œ Dtoλ₯Ό μž‘μ„±ν–ˆλ‹€.
ν•˜μ§€λ§Œ, 이전에 λΆˆν•„μš”ν•œ μ½”λ“œλ₯Ό 1차적으둜 ν™•μΈν•˜κ³  μ‚­μ œν•˜κ±°λ‚˜ μ£Όμ„μ²˜λ¦¬λ₯Ό ν–ˆμŒμ—λ„ λΆˆκ΅¬ν•˜κ³  λˆ„λ½λœ μ½”λ“œλ₯Ό 확인해고 이 뢀뢄듀을 μ œκ±°ν•΄μ£Όμ—ˆλ‹€.

κ·Έλ¦¬κ³ λ‚˜μ„œ, μ „μ—λŠ” Dto의 이해가 λΆ€μ‘±ν•΄μ„œ Entity의 λͺ¨λ“  값을 λ˜‘κ°™μ΄ λ„£μ–΄μ€˜μ„œ μ‚¬μš©ν–ˆμœΌλ‚˜, ν˜„μž¬λŠ” μš”μ²­μ— ν•„μš”ν•˜μ§€μ•ŠλŠ” Colume을 ν¬ν•¨ν•˜λŠ” 것이 λΉ„νš¨μœ¨μ μœΌλ‘œ μƒκ°ν•΄μ„œ μš”μ²­μ— ν•„μš”ν•œ Columeλ§Œμ„ Dto둜 μƒμ„±ν•΄μ„œ ν•„μš”μ— 맞좰 Dtoλ₯Ό μ‚¬μš©ν•˜λ € ν•œλ‹€.

κ²Œμ‹œκΈ€ μž‘μ„±μ— λŒ€ν•œ Dtoκ°€ ν•„μš”ν•˜κΈ° λ•Œλ¬Έμ— BoardRequestDto 클래슀λ₯Ό μƒμ„±ν•˜κ³  ν•˜μœ„ 클래슀둜 SaveRequestDtoλ₯Ό 생성해 μ£Όμ—ˆλ‹€.

μ΄λ ‡κ²Œ λ‚΄λΆ€ 클래슀(inner class)둜 μ •μ˜ν•˜λŠ” 것은 μ½”λ“œμ˜ ꡬ쑰화와 μΊ‘μŠν™”λ₯Ό μœ„ν•΄ μ‚¬μš©λœλ‹€κ³  ν•œλ‹€.

public class BoardRequestDto {

    @AllArgsConstructor
    @NoArgsConstructor
    @Getter
    @Builder
    public static class SaveRequestDto {

        @NotBlank(message = "제λͺ©μ„ μž…λ ₯ν•΄μ£Όμ„Έμš”.")
        private String title;

        @NotBlank(message = "λ‚΄μš©μ„ μž…λ ₯ν•΄μ£Όμ„Έμš”.")
        private String content;

        @NotNull(message = "μΉ΄ν…Œκ³ λ¦¬λ₯Ό μ„ νƒν•΄μ£Όμ„Έμš”.")
        private Category category;

        @NotNull(message = "μ‚¬μš©μžμ˜ κ³ μœ λ²ˆν˜Έκ°€ μ‘΄μž¬ν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€.")
        private Long memberId;

        private LocalDateTime deadLine;
    }
}

ν•„μžκ°€ ν•˜μœ„ ν΄λž˜μŠ€μ— μž‘μ„±ν•œ μ΄μœ λŠ” κ°„λ‹¨ν•˜λ‹€. μ—¬λŸ¬κ°œμ˜ 클래슀λ₯Ό 생성할 수 μžˆμ§€λ§Œ, 클래슀 파일이 λ§Žμ•„μ§€λ©΄ 였히렀 관리가 λ³΅μž‘ν•΄μ Έμ„œ λΉ„νš¨μœ¨μ μΈ 관리가 될 수 μžˆμ„ 것이라고 μƒκ°ν–ˆκΈ° λ•Œλ¬Έμ΄λ‹€.
(개인적인 μ΄μœ μž…λ‹ˆλ‹€.)

πŸ‘¨πŸ»β€πŸ’» λ‚΄λΆ€ 클래슀λ₯Ό μ‚¬μš©ν•˜λŠ” 이점

  • μ½”λ“œ ꡬ쑰화
    λ‚΄λΆ€ 클래슀λ₯Ό μ‚¬μš©ν•˜λ©΄ μ—°κ΄€λœ 클래슀λ₯Ό λ…Όλ¦¬μ μœΌλ‘œ κ·Έλ£Ήν™”ν•  수 μžˆλ‹€.
    SaveRequestDtoλŠ” BoardRequestDto에 κ΄€λ ¨λœ κΈ°λŠ₯을 μ œκ³΅ν•˜λ―€λ‘œ, 클래슀 λ‚΄μ—μ„œ ν•¨κ»˜ μ„ μ–Έν•¨μœΌλ‘œμ¨ κ΄€λ ¨λœ μ½”λ“œλ₯Ό ν•œ 곳에 μœ„μΉ˜μ‹œν‚¬ 수 μžˆλ‹€.
  • μ ‘κ·Ό μ œμ–΄
    λ‚΄λΆ€ 클래슀λ₯Ό μ‚¬μš©ν•˜λ©΄ μ™ΈλΆ€ ν΄λž˜μŠ€μ—μ„œ λ‚΄λΆ€ 클래슀의 멀버에 직접 μ ‘κ·Όν•˜λŠ” 것을 μ œν•œν•  수 μžˆλ‹€.
    λ‚΄λΆ€ 클래슀λ₯Ό private으둜 μ„ μ–Έν•˜κ±°λ‚˜, ν•„μš”μ— 따라 public, protected λ“±μ˜ μ ‘κ·Ό μ œμ–΄μžλ₯Ό μ‚¬μš©ν•˜μ—¬ μ™ΈλΆ€μ—μ„œμ˜ 접근을 μ œν•œν•  수 μžˆλ‹€.
  • μ½”λ“œ 응집성
    λ‚΄λΆ€ 클래슀λ₯Ό μ‚¬μš©ν•˜λ©΄ 클래슀 κ°„μ˜ κ΄€λ ¨λœ 데이터와 λ™μž‘μ„ ν•œ 곳에 μœ μ§€ν•  수 μžˆλ‹€.
    SaveRequestDtoκ°€ BoardRequestDto의 μΌλΆ€λ‘œ μ •μ˜λ˜μ–΄ 있기 λ•Œλ¬Έμ—, SaveRequestDto의 데이터와 λ™μž‘μ€ BoardRequestDto와 λ°€μ ‘ν•˜κ²Œ μ—°κ΄€λ˜μ–΄ μžˆμ„ 것이닀.

λ‚΄λΆ€ 클래슀λ₯Ό μ‚¬μš©ν•˜λŠ” 것은 선택사항이고, μ½”λ“œμ˜ ꡬ쑰와 섀계에 따라 μœ μ—°ν•˜κ²Œ λŒ€μ²˜ν•  수 μžˆλ‹€.

이제, Dto μž‘μ„±μ„ μ™„λ£Œν–ˆκ³  Service μΈν„°νŽ˜μ΄μŠ€μ— κ²Œμ‹œκΈ€ μž‘μ„±μ— λŒ€ν•œ λ©”μ„œλ“œ(saveBoard)λ₯Ό 생성해주고 κ΅¬ν˜„μ²΄μΈ BoardServiceImpl 클래슀λ₯Ό μƒμ„±ν–ˆλ‹€.

public interface BoardService {

    //κ²Œμ‹œκΈ€ 등둝 μš”μ²­ Method
    Board saveBoard(BoardRequestDto.SaveRequestDto requestDto);
}
@RequiredArgsConstructor
@Log4j2
@Service
public class BoardServiceImpl implements BoardService {

    private final BoardRepository boardRepository;
    private final MemberRepository memberRepository;

    @Override
    public Board saveBoard(BoardRequestDto.SaveRequestDto requestDto) {

        // μš”μ²­λœ λ°μ΄ν„°λ‘œ Member 객체λ₯Ό 쑰회
        Member member = memberRepository.findById(requestDto.getMemberId())
            .orElseThrow(() -> new IllegalArgumentException("μ‚¬μš©μžλ₯Ό 찾을 수 μ—†μŠ΅λ‹ˆλ‹€."));

        // μΉ΄ν…Œκ³ λ¦¬ κ°’ μ„€μ •
        Category category = requestDto.getCategory();

        // Board Entity 생성
        Board board = Board.builder()
            .member(member)
            .category(category)
            .title(requestDto.getTitle())
            .content(requestDto.getContent())
            .build();

        return boardRepository.save(board);
    }
}

그리고 API λ™μž‘μ„ μœ„ν•΄μ„œ μž‘μ„±ν•œ Controller μ½”λ“œλŠ” μ•„λž˜μ™€ κ°™λ‹€.

@RestController
@RequiredArgsConstructor
@RequestMapping("/api/v1/board")
public class BoardController {

    private final BoardService boardService;

    @PostMapping("/register")
    public ResponseEntity<?> createBoard(@RequestBody @Valid BoardRequestDto.SaveRequestDto requestDto) {
        Board savedBoard = boardService.saveBoard(requestDto);

        // 응닡 데이터 생성
        Map<String, Object> response = new HashMap<>();
        response.put("code", 200);
        response.put("msg", "success");

        // κ²Œμ‹œκΈ€ 정보
        response.put("data", savedBoard);

        return ResponseEntity.ok(response);
    }
}

μ΄λ ‡κ²Œ ν•΄μ„œ κ²Œμ‹œκΈ€ μž‘μ„± APIλ₯Ό κ°œλ°œν•  수 μžˆμ—ˆκ³  PostMan을 톡해 APIκ°€ 잘 λ™μž‘ν•˜λŠ”μ§€ ν…ŒμŠ€νŠΈλ₯Ό ν•΄λ³΄μ•˜λ‹€.

κ²°κ³ΌλŠ”?

1μ°¨ μ‹œλ„: 401 Error

μƒκ°ν•΄λ³΄λ‹ˆ 이번 ν”„λ‘œμ νŠΈλŠ” ν•œ λͺ¨λ“ˆμ— Member와 JWT μ„€μ • νŒ¨ν‚€μ§€λ₯Ό κ°€μ§€κ³  있기 λ•Œλ¬Έμ— κ°œλ°œν•˜λŠ” 도쀑에도 JWT의 인증을 거치게 λœλ‹€. 전에 JWTλ₯Ό 닀룬 κ²½ν—˜μ΄ μžˆμ–΄μ„œ 401 μ—λŸ¬μ— νŒ€μ›μ΄ 성심껏 μž‘μ„±ν•΄μ€€ message 덕뢄에 μ–΄λ–€ 것이 λ¬Έμ œμΈμ§€ λ°”λ‘œ μ•Œμ•„μ°¨λ¦΄ 수 μžˆμ—ˆλ‹€.

JWTλ₯Ό ν™•μΈν•˜λŠ” κ³Όμ •μ—μ„œ λ‚΄κ°€ μ§€μ •λœ pathκ°€ κ²€μ¦λŒ€μƒμ΄ λ˜μ—ˆκ³ , Member의 개발이 μ™„μ„±λ˜μ§€ μ•Šμ€ μƒνƒœμ—μ„œ κ²Œμ‹œκΈ€μ„ μž‘μ„±ν•˜λ €λ‹ˆ, 정석 μ ˆμ°¨λŒ€λ‘œ ν•΄κ²°ν•  μˆ˜λŠ” μ—†μ—ˆλ‹€.

κ·Έλž˜μ„œ 개발 단계이기 λ•Œλ¬Έμ—, ν•„μžκ°€ μ§€μ •ν•΄λ‘” API path 경둜λ₯Ό κ²€μ¦ν•˜μ§€ μ•Šλ„λ‘ μž„μ‹œλ‘œ κ΅¬ν˜„ν•΄λ‘” λ‹€μŒμ— Member와 Board의 개발이 μ™„λ£Œλ˜λ©΄ κ·Έ 이후에 μž„μ‹œλ‘œ μ§€μ •ν•œ configλ₯Ό μˆ˜μ •ν•΄μ„œ ν…ŒμŠ€νŠΈ ν•˜κΈ°λ‘œ ν–ˆλ‹€.

2μ°¨ μ‹œλ„: 200 Succes

μ›ν•˜λŠ” 값을 DB에 잘 μ €μž₯μ‹œν‚¨ 것도 ν™•μΈν–ˆλ‹€. (ν•„μžλŠ” MariaDBλ₯Ό μ‚¬μš©ν•΄ κ°œλ°œμ„ μ§„ν–‰ν•˜κ³  Tool둜 DBeaverλ₯Ό μ‚¬μš©ν•˜κ³  μžˆλ‹€.)

μ½”λ“œ 리뷰λ₯Ό 톡해 μˆ˜μ •λœ λ‚΄μš©μ΄ μžˆλ‹€λ©΄ μΆ”κ°€λ‘œ 기둝을 ν•  μ˜ˆμ •
profile
πŸ‘ΎISTP의 개발자 λ„μ „κΈ°πŸ§

0개의 λŒ“κΈ€