개발 고찰 #1

아야하면우유·2025년 7월 16일

개발 고찰

목록 보기
1/2

개발하다가 막히는 내용이 있으면, 다음부터는 이런 식으로 작성하려고 한다. 추가적으로, FastAPI와 리액트를 태그에 달았지만, 직접 다루지는 않았다. 메인을 Spring으로 두고, FastAPI, React와 통신하면서 생기는 일에 대해 적으려고 한다.

1. Server to Server Archtecture

 요즘 이슈가 되고 있는 내용인데, AI 응답을 API로 받아볼 수 있다. LLM의 수익 구조가 이제는 API 중심이 될거라나 뭐라나.
 아무튼, 우리 서비스는 Spring서버와 FastAPI 서버를 따로 두어, FastAPI에서 AI 호출 및 응답을 반환하고, Spring 서버에서 그 AI 응답을 받기 위한 데이터셋을 Front-End측 RequestBody + DB query로 구성하여 AI 서버로 던지는 역할이다. AI 서버와 클라이언트가 직접 통신하는 구조도 괜찮을 것 같다고 생각하지만, 우리 서비스는 클라이언트가 요청했을 때의 시간과 장소 데이터를 추후 다른 API로 조회하려고 하므로, 이러한 요청을 묶어서 Spring에서 처리하기로 했다.

 그렇다면, 메인 백서버에서 어떻게 AI서버로 통신해야 할까가 주된 관심사였다.

"프론트 컨트롤러와 연결된 서비스 계층에서 해결해야 하는가?"
-> 서비스의 책임이 너무 무거워짐 (DB 쿼리, 데이터 파싱, AI 호출 ... )

따라서, AI 서버와 통신하기 위한 새로운 패키지를 만들기로 했다.

  • domain : 의존해야 하는 객체끼리 모아두는 패키지. (의존 범위 국소적)
  • global : 전역적으로 처리해야할 것들(ex. http 통신 예외, Security, JWT, 공통 응답 객체 등)
  • AI : AI 서버와 통신하기 위한 RestTemplate, 그리고 DTO를 통해 호출 및 반환

Call AI Server Code

 public ResponseEntity<SuccessResponse<?>> callAiServer(ToAiReq req) {
        URI uri = UriComponentsBuilder
                .fromUriString("http://localhost:5000") // FastAPI 서버 띄워지는 주소로 변경
                .path("/ai") // 해당 path로 수정 요망
                .encode()
                .build()
                .toUri();

        // 추후에 Object를 받을 Res로 선언. 이것도 global 패키지에 선언하면 될듯 -> 완
        ResponseEntity<SuccessResponse<?>> responseEntity = restTemplate
                .exchange(uri,
                        HttpMethod.POST,
                        new HttpEntity<>(req),
                        new ParameterizedTypeReference<SuccessResponse<?>> () {}
                );

        if(responseEntity.getStatusCode().is2xxSuccessful()) {
            return responseEntity;
        } else {
            log.info("AI 서버 호출 실패" + responseEntity.getStatusCode());
            throw new RuntimeException("AI 서버 호출 실패" + responseEntity.getStatusCode());
        }
    }

이 코드에는 적지 않았지만 아래와 같은 추가적인 설정을 해두었다.

  • RestTemplate : global/configuration에 @Bean으로 등록하고, 클래스 private 상수로 선언
  • 이 메서드의 주인인 구현체는 @Component 등록

 RestTemplate에 선언된 여러 메서드들이 있지만, 여기에 쓰여진 것과 같이 ResponseEntity를 제네릭 클래스로 하려면, RestTemplate.exchange()가 유용한 것 같다. - 같다. 라고 이야기하는 이유는, 아직 자세히 공부하지 않아서 확정짓기 힘들어서 이렇게 적었다. 나중에 공부해볼 예정 -
 그래서 이 메서드를 사용했고, 이후에 조건문으로 성공 여부를 확인하고 반환하는 모습이다. - 이것도 FastAPI 개발자와 이야기해봐야 할 것 같지만, 나머지 400이나 500번대 상태코드로 반환하는 로직을 짜두셨다면, 그냥 조건문째로 날릴 예정이다. - 그리고 반환 타입은 그냥 Http 응답 객체인 ResponseEntity로 주어서, 이것 그대로 프론트 엔드로 전달하려고 한다.

아직 객체지향 설계에 대해서 잘 아는 것은 아니라서, 나중에 더 공부해볼 생각이다.

  • 서버와 서버 간의 통신에 대해 책임 분리하는 법
  • RestTemplate의 동작 방식
  • 타 서버 응답을 파싱해야 할 경우, 어떻게 해야 하는지
profile
우유가 넘어지면 아야

0개의 댓글