프로젝트/BookSNS

[Project] BookSNS - OPENAPI 모듈 만들기 with SpringBoot,JPA

IT록흐 2023. 7. 12. 11:49
반응형

 

책으로 연계된 Social Network Service 사이트를 만들어 보려고 한다. 우선, 개발하려는 기능은 책 추천 기능이다. 

 

 

 

 

 

원하는 특징이나 분야를 입력하면 ChatGPT에서 책추천을 받고 추천된 책정보는 네이버BookAPI에서 가져오려고 한다.  구글링하여 ChatGPT와 네이버API에서 데이터를 가져오는 코드는 쉽게 구현하였으나 객체지향적이지 않다. BookSNS가 챗GPT와 네이버API와 직접 의존하기보다 중간에 모듈을 하나 두어야 확장성이 좋다.

 

 

1. OPEN API 모듈 만들기

 

 

 

 

BookSNS가 원하는 데이터를 요청하면 OpenAPI 모듈이 중간에서 매개하도록 구성했다. 이로써 챗GPT와 네이버BookAPI가 아닌 다른 OPENAPI가 추가되어도 중복코드를 작성하지 않아도 된다. 그럼 구체적인 설계를 해보자. 

 

OpenAPI 종류는 다양하지만 결국 기능은 하나이다. 요청 데이터를 보내고 결과 데이터를 받는 것이다. 그러므로 Command Pattern으로 설계하면 효율적으로 객체를 설계할 수 있다.

 

 

[OOP] 커맨드 패턴(Command Pattern)

디자인 패턴이란? 객체지향설계 과정에서 발생하는 문제들을 해결하기 위한 패턴(Pattern) 문제 상황 RemoteController 객체 안 필드변수에 Light 객체의 주소가 담겨진다. 그리고 RemoteController의 버튼이

lordofkangs.tistory.com

 

 

 

OPENAPI로 메시지를 보내는 기능을 가진 인터페이스를 만들고 POST방식과 GET방식에 따라 구현체를 두었다. 챗GPT API는 POST방식으로 네이버BookAPI는 GET방식으로 통신한다. 이로써, OpenApiMachine은 POST방식, GET방식에 상관없이 그저 HttpMessageSender가 제공하는 기능만 사용하면 된다. 

 

하지만 완벽하게 분리가 된 것이 아니다. BookSNS가 ChatGPT 데이터를 요청하면 OpenAPIMachine은 HttpPostSender 구현객체를 생성해야 한다. 아직 결합이 남아 있다. 그러므로 Factory Pattern을 사용하여 결합을 모두 제거해보자. 

 

 

[OOP] 추상 팩토리 패턴(Abstract Factory Pattern)

디자인 패턴이란? 객체지향설계 과정에서 발생하는 문제들을 해결하기 위한 패턴(Pattern) 문제 상황 결합도를 낮추기 위해 인터페이스를 사용하지만 구현객체를 생성(new)하는 과정에서 결합이

lordofkangs.tistory.com

 

OpenApiMachine은 OpenApiFactory를 의존한다. OpenApiFactory가 생성한 HttpMessageSender 객체만 받아서 사용하면 된다. 이로써 완전한 분리가 이루어졌다. 

 

 

2. 데이터 객체 만들기 

 

이제 HttpMessageSender 객체에 HTTP 요청데이터를 넘겨야 한다. 

 

요청데이터는 ChatGPT용 VO, NaverBoo용 VO를 만들었다. 그런데 API-KEY 같은 민감한 데이터가 있다. 민감한 데이터는 외부설정파일에 저장하고 설정파일에서 데이터를 읽어들이는 방향으로 설계해 보았다. 

 

 

 

 

외부설정파일에서 데이터를 우선 @ConfigurationProperties 어노테이션이 선언된 클래스에 저장한다. 설정데이터를 중간의 클래스에 저장하여 유효성검사를 진행할 수 있다. 

 

@Getter
@ConfigurationProperties("openapi.chatgpt")
public class ChatGptProperties {
    @NotEmpty
    private String apikey;
    @NotEmpty
    private String url;
    private String role;
    private String model;
    @NotEmpty
    private double temperature;

    public ChatGptProperties(String apikey, String url, @DefaultValue("user")String role, @DefaultValue("gpt-3.5-turbo")String model, double temperature) {
        this.apikey = apikey;
        this.url = url;
        this.role = role;
        this.model = model;
        this.temperature = temperature;
    }
}

 

@ConfigurationProperties 어노테이션으로 데이터를 담을 범위("openapi.chatgpt")도 설정가능하여 깔끔하게 데이터를 담을 수 있다. 그리고 이를 실제 VO에 저장하면 된다. 

 

@Getter
public class ChatGptData implements OpenApiData {

    private String apikey;
    private String url;
    private String role;
    private String model;
    private double temperature;

    public ChatGptData(ChatGptProperties chatGptProperties) { // 설정객체에 있는 데이터 옮기기
        this.apikey = chatGptProperties.getApikey();
        this.url = chatGptProperties.getUrl();
        this.role = chatGptProperties.getRole();
        this.model = chatGptProperties.getModel();
        this.temperature = chatGptProperties.getTemperature();
    }

    @Override
    public OpenApiHttpVo getOpenApiData(String input) {
        return new OpenApiHttpVo(generateHeader(),generateApiData(input));
    }
 }

 

 

이로써, OpenAPI 모듈로 전송할 데이터 객체도 만들어졌다. 

 

 

BookSNS 사이트의 Controller

@RestController
@RequiredArgsConstructor
public class TestController {

    private final OpenApiMachine openApiMachine;

    @GetMapping("/chatgpt")
    public String getChatGptResult(){
        return openApiMachine.sendMessage(OpenApiMode.CHATGPT,"비오는 날에 어울리는 책을 [ 도서명 : 저자명 ] 형식으로 알려줘");
    }

    @GetMapping("/naverbook")
    public String getNaverBookResult(){
        return openApiMachine.sendMessage(OpenApiMode.NAVERBOOK,"황야의이리");
    }
}

 

BookSNS 사이트는 OpenApiMachine이 제공하는 sendMessage 기능만 사용하면 원하는 데이터를 얻을 수 있다. 그저 원하는 OpenApi만 설정해주면 된다. 그럼 결과를 확인해보자. 

 

 

url : http://localhost:8080/chatgpt

 

 

url : http://localhost:8080/naverbook

 

 

 

데이터를 잘 가져왔다. 

이제 데이터를 화면 스펙에 맞는 DTO로 변환하는 로직과 DB에 저장하는 로직을 구현해보아야 겠다.

반응형