활동 점수 적립 (POST /users/activity-score/add) - 내부용 API
활동 점수 차감 (POST /users/activity-score/deduct) - 내부용 API
[게시글 서비스]
게시글 생성 (POST /boards) - 외부용 API
특정 게시글 조회 (GET /boards/{boardId}) - 외부용 API
전체 게시글 조회 (GET /boards) - 외부용 API
[포인트 서비스]
포인트 적립 (POST /points/add) - 내부용 API
포인트 차감 (POST /points/deduct) - 내부용 API
MSA에서는 위와 같이 반드시 외부 클라이언트가 사용할 API와 내부 마이크로서비스끼리 사용하는 API를 구분해야 한다. 그래야 나중에 구분해서 보안 처리를 하기가 쉽다. 한 마디로, 외부 클라이언트가 ‘내부 마이크로서비스끼리 사용하는 API’에 접근하지 못하도록 설정하기가 쉽다.
외부 클라이언트용 API 주소와 내부 마이크로서비스용 API를 구분하기 위해 아래와 같이 URL을 구분하자.
외부 클라이언트용 API 주소 : /api/____
내부 클라이언트용 API 주소 : /internal/____
✅ 사용자 서비스 코드 수정하기
UserController 복사해서 UserInternalController 만들기
controller/UserInternalController
@RestController
@RequestMapping("/internal/users")
public class UserInternalController {
...
@PostMapping("sign-up")
public ResponseEntity<Void> signUp() {...}
@GetMapping("{userId}")
public ResponseEntity<UserResponseDto> getUser(...) {...}
@GetMapping()
public ResponseEntity<List<UserResponseDto>> getUsersByIds() {...}
@PostMapping("activity-score/add")
public ResponseEntity<Void> addActivityScore() {...}
}
UserController 코드 수정하기
controller/UserController
@RestController
@RequestMapping("/api/users")
public class UserController {
...
@PostMapping("sign-up")
public ResponseEntity<Void> signUp() {...}
@GetMapping("{userId}")
public ResponseEntity<UserResponseDto> getUser(...) {...}
@GetMapping()
public ResponseEntity<List<UserResponseDto>> getUsersByIds() {...}
@PostMapping("activity-score/add")
public ResponseEntity<Void> addActivityScore() {...}
}
Client 코드 수정하기
client/PointClient
@Component
public class PointClient {
...
public void addPoints(Long userId, int amount) {
AddPointsRequestDto addPointsRequestDto
= new AddPointsRequestDto(userId, amount);
this.restClient.post()
.uri("/internal/points/add")
.contentType(MediaType.APPLICATION_JSON)
.body(addPointsRequestDto)
.retrieve()
.toBodilessEntity();
}
}
서버 다시 실행시키기
✅ 게시글 서비스 코드 수정하기
게시글 서비스는 외부용 API만 존재한다.
BoardController 코드 수정하기
controller/BoardController
@RestController
@RequestMapping("/api/boards")
public class BoardInternalController {
...
@PostMapping
public ResponseEntity<Void> create(...) {...}
@GetMapping("/{boardId}")
public ResponseEntity<BoardResponseDto> getBoard(...) {...}
@GetMapping()
public ResponseEntity<List<BoardResponseDto>> getBoards() {...}
}
Client 코드 수정하기
client/PointClient
@Component
public class PointClient {
...
public void deductPoints(Long userId, int amount) {
DeductPointsRequestDto deductPointsRequestDto
= new DeductPointsRequestDto(userId, amount);
this.restClient.post()
.uri("/internal/points/deduct")
.contentType(MediaType.APPLICATION_JSON)
.body(deductPointsRequestDto)
.retrieve()
.toBodilessEntity();
}
public void addPoints(Long userId, int amount) {
AddPointsRequestDto addPointsRequestDto
= new AddPointsRequestDto(userId, amount);
this.restClient.post()
.uri("/internal/points/add")
.contentType(MediaType.APPLICATION_JSON)
.body(addPointsRequestDto)
.retrieve()
.toBodilessEntity();
}
}
client/UserClient
@Component
public class UserClient {
...
public Optional<UserResponseDto> fetchUser(Long userId) {
try {
UserResponseDto userResponseDto = this.restClient.get()
.uri("/internal/users/{userId}", userId)
.retrieve()
.body(UserResponseDto.class);
return Optional.ofNullable(userResponseDto);
} catch (RestClientException e) {
// 로깅 : 예외 발생 시 로그를 남겨 문제를 파악할 수 있게 해야 함
// log.error("사용자 정보 조회 실패: {}", e.getMessage(), e);
return Optional.empty();
}
}
public List<UserResponseDto> fetchUsersByIds(List<Long> ids) {
try {
return this.restClient.get()
.uri(uriBuilder -> uriBuilder
.path("/internal/users")
.queryParam("ids", ids)
.build()
)
.retrieve()
.body(new ParameterizedTypeReference<>() {});
} catch (RestClientException e) {
// 로깅 : 예외 발생 시 로그를 남겨 문제를 파악할 수 있게 해야 함
// log.error(...)
return Collections.emptyList();
}
}
public void addActivityScore(Long userId, int score) {
AddActivityScoreRequestDto addActivityScoreRequestDto
= new AddActivityScoreRequestDto(userId, score);
this.restClient.post()
.uri("/internal/users/activity-score/add")
.contentType(MediaType.APPLICATION_JSON)
.body(addActivityScoreRequestDto)
.retrieve()
.toBodilessEntity();
}
}
서버 다시 실행시키기
✅ 포인트 서비스 코드 수정하기
포인트 서비스는 내부용 API만 존재한다.
PointController를 PointInternalController로 이름 바꾸기
@RestController
@RequestMapping("/points")
public class PointInternalController {
...
}
PointInternalController로 코드 수정하기
@RestController
@RequestMapping("/internal/points")
public class PointInternalController {
...
}