Spring Cloud with Apache Kafka - 5

최혜성·2024년 2월 15일
0

msa

목록 보기
3/7

오랫만에 써보는 MSA 글이다.. 어쩌다 보니 시간이 나서 조금 더 진도를 나가보려 한다.

Common 모듈

응답을 반환할때 Response 클래스를 이용해서 반환했는데, 멀티모듈로 구성하다 보니 해당 클래스를 모듈간에 공유할 수 없는 문제가 있었다.

분명히 User 모듈에 Response 잘 적어놨는데 왜 참조가 안될까? 하다 common 모듈로 분리하라는것이 생각났다.

Common에 모든 코드를 다 때려박는 불상사가 아닌이상 Common 모듈이 한개쯤은 있긴 해야한다.

  • setting.gradle
    include("common") 추가
  • Common을 사용하는 모듈의 build.gradle
 implementation(project(":common"))

이렇게 common 모듈을 하나 만들고 사용할 모듈의 dependency에다 잘 넣어주면 맛있게 돌아간다

User, Event 생성

User와 Event는 각 모듈로 분리되어 있어 실질적인 데이터는 별개의 테이블로 저장된다.

User (Member)는 고유 id, 닉네임, 로그인 아이디/비밀번호 필드를 갖고 있다.
Event는 고유 id, 이름, 상태(개최여부), 개최자 id, 좌석(고유 id, 이름, 상태)를 갖고있다.

좌석 (Seat)는 Event에 대해 1:N으로 구성되어 있다. 이번엔 양방향으로 잘 구성했다.

User의 정보가 많이 없다고 볼 수 있는데, 사실 User는 Auth를 담당하는 주체로써 사용되지 않을까 싶다. 부가 정보가 좀더 추가 될 순 있지만, 핵심 도메인(뭐.. 결제를 하기 위한 보유 금액, 참여 이력)등등은 User가 아닌 다른 모듈로써 구성되어야 하니.

  • User
{
    "success": true,
    "message": "회원가입이 완료 되었습니다. 유저 ID : 1"
}
  • Event
{
    "success": true,
    "message": "이벤트가 생성되었습니다.",
    "data": {
        "name": "My Event",
        "status": "OPEN",
        "id": 4,
        "ownerId": 1,
        "seats": [
            {
                "id": 7,
                "name": "A1",
                "status": "CLOSE"
            },
            {
                "id": 8,
                "name": "A2",
                "status": "OPEN"
            }
        ]
    }
}

따라서 현재 4개의 엔드포인트가 생성되었다.

  • [POST] /api/user/register - 회원가입
  • [GET] /api/user/{id} - 유저 조회
  • [POST] /api/event - 이벤트 생성
  • [GET] /api/event/{id} - 이벤트 조회

정보 수정, 삭제는 나중에 여유가 있을때 하고, 우선적으로 기능만 러프하게 돌아가게 만들어 보자.

OpenFeign

원래는 여기에서 안쓸 것 같았는데, Event 생성시 User Id가 올바른지 체크하는겸, OpenFeign도 한번 써보는겸 해서 Event에 적용해보기로 한다.

https://velog.io/@haerong22/Spring-Cloud-%EB%A5%BC-%EC%9D%B4%EC%9A%A9%ED%95%9C-MSA-3.-%EC%84%9C%EB%B9%84%EC%8A%A4%EA%B0%84-%ED%86%B5%EC%8B%A0Open-Feign

Retrofit이랑 거의 유사하게 되어 있어 인터페이스도 그냥 유스케이스로 구현하기로 했다.

간단하게 유저 존재 여부를 확인할 수 있는 엔드포인트와, 해당 FeignClient를 구성했다.

  • MemberController
    @GetMapping("/exist/{id}")
    suspend fun existUser(@PathVariable(value = "id") id : Long) : Boolean {
        return memberService.existById(id)
    }
    
  • ExistUser
//유저 존재하는지 여부 체크
@FeignClient(name = "USER-API")
interface ExistUser {

    @GetMapping("/api/user/exist/{id}")
    fun existUser(@PathVariable id : Long) : Boolean
}

유레카를 사용하면 따로 url base 지정할 필요 없이 module 이름만 지정하면 된다

  • EventService
    @Transactional
    suspend fun createEvent(eventRequestDTO: EventRequestDTO) : EventResponseDTO {
        val event = eventRequestDTO.toEntity()
        withContext(Dispatchers.IO) {
            if (!existUser.existUser(event.ownerId))
                throw EventException("존재하지 않는 유저의 id입니다.", event.ownerId)
        }
        return eventRepository.save(event).toResponseDTO()
    }

유저가 존재하지 않을경우 exception을 발생한다.

클래스 구조

도메인 기반으로 패키지를 구성했는데.. 어처피 MSA면 한 모듈이 하나의 도메인 아닌감

  • User
  • Event

Conclusion

코드는 아래 깃허브에 항상 최신화 되어 있다.
https://github.com/choi-hyeseong/MSAEvent

다음편엔 Kafka와 연동해서 좌석 예약을 할경우 해당 좌석의 Status를 Close로 바꾸는 작업을 해보고자 한다.

profile
KRW 채굴기

0개의 댓글