Feign Client 사용해서 외부 api 연동

wellbeing-dough·2023년 11월 7일
0

1. Feign 사용 이유

  • SpringMvc에서 제공되는 익숙한 어노테이션을 그대로 사용할 수 있다.
  • RestTemplate 보다 간편하게 사용할 수 있으며 가독성이 좋다.
  • 요청에 대한 커스텀이 간편하다.

이 외에 여러가지 이유가 있지만 RestTemplate를 사용해봤는데 코드 가독성이 너무 떨어지고 WebClient는 Spring WebFlux 에서 HTTP Client로 사용되는 비동기적으로 작동하는 모듈인데 굳이 비동기가 지원될 필요가 없다고 판단했고 Feign을 사용했다

implementation 'org.springframework.cloud:spring-cloud-starter-openfeign:3.1.3'
runtimeOnly 'io.github.openfeign:feign-httpclient:12.1'
implementation 'com.netflix.feign:feign-jackson:8.18.0'
@SpringBootApplication
@EnableFeignClients
public class TripComesTrueServerApplication {

	public static void main(String[] args) {
		SpringApplication.run(TripComesTrueServerApplication.class, args);
	}

}

이렇게 해도 되고 따로 Config 클래스 만들어서 @Configuration @EnableFeignClients 해도된다

2. 외부 api requset, response 확인해보기

request는 http://iq.ifac.or.kr/openAPI/real/search.do?apiKey=20231102R2W9E6KMUQO33ZZZ0FJQS8JG&svID=culture&resultType=json&cPage=1&pSize=10 이고

[
    {
        "item": [
            {
                "idx": 12086,
                "title": "[마이 리틀 콘텐츠 5회] "앨범 커버 속에 담아놓은 다채로운 나만의 상상" 그래픽 아티스트 로지킴의 그래픽 디자인 특강",
                "link": "https://iq.ifac.or.kr/culture/view.do?key=m2102173814702&category=CUL03&eventSn=12086",
                "category": "행사/축제",
                "sdate": "20231121",
                "edate": "20231121",
                "place": "틈 문화창작지대",
                "placeSido": "인천광역시",
                "placeGugun": "인천광역시 미추홀구",
                "management": "문화체육관광부, 인천광역시",
                "feeCase": "유료",
                "fee": "",
                "tel": "인천콘텐츠코리아랩",
                "homepage": "https://www.inckl.or.kr/user/program/view.do?prgrm_ifmt_sq=606",
                "poster": "https://iq.ifac.or.kr/fileManager/www/cultureEvent/poster/12086/1696908689402.png",
                "posterThumb": "https://iq.ifac.or.kr/fileManager/www/cultureEvent/poster/12086/1696908689402.png",
                "description": "[마이 리틀 콘텐츠 5회]\r\n"앨범 커버 속에 담아놓은 다채로운 나만의 상상" 그래픽 아티스트 로지킴의 그래픽 디자인 특강\r\n\r\n콘텐츠 제작 과정을 실시간으로 시청하고 채팅으로 소통하며 함께 즐기는 온라인 강연 프로그램 마이 리틀 콘텐츠! \r\n\r\n다채로운 나만의 상상력을 통해 콘텐츠를 만들어 내는 그래픽 아티스트 로지킴님과 함께 그래픽 디자인 작업 노하우를 알아보고, 작업 과정을 함께 살펴봐요!\r\n\r\n▶ 일시: 2023. 11. 21. (화), 19:00 ~ 20:00 (약 1시간 예정)\r\n▶ 장소: [ON-LINE] 인천콘텐츠코리아랩 유튜브 채널 라이브 스트리밍\r\n▶ 신청: 인천콘텐츠코리아랩 홈페이지  ‘프로그램 신청’ 또는 구글 폼을 통한 신청(https://zrr.kr/eVCR)\r\n▶ 문의: 032) 876-6426 / inckl2023@gmail.com (인천콘텐츠코리아랩 운영사무국)\r\n\r\n",
                "reserveInfo": "",
                "reserveUrl": "",
                "pubDate": "2023-11-07 17:08"
            },
            {
                "idx": 12085,
                "title": "크리스마스 콘서트 퍼니밴드",
                "link": "https://iq.ifac.or.kr/culture/view.do?key=m2102173812856&category=CUL01&eventSn=12085",
                "category": "공연",
                "sdate": "20231225",
                "edate": "20231225",
                "place": "엘림아트센터 엘림홀(대공연장)",
                "placeSido": "인천광역시",
                "placeGugun": "인천광역시 서구",
                "management": "엘림아트센터",
                "feeCase": "무료",
                "fee": "전석 30,000원",
                "tel": "032-289-4275",
                "homepage": "www.elimartcenter.co.kr/sub/performance/guide_view.asp?b_idx=991",
                "poster": "https://iq.ifac.or.kr/fileManager/www/cultureEvent/poster/12085/1696908689394.png",
                "posterThumb": "https://iq.ifac.or.kr/fileManager/www/cultureEvent/poster/12085/1696908689394.png",
                "description": "2023년 12월25일\r\n월요일 오후 4시 30분",
                "reserveInfo": "",
                "reserveUrl": "https://tickets.interpark.com/goods/23016081",
                "pubDate": "2023-11-07 16:25"
            },
            {
                "idx": 12084,
                "title": "이강호 첼로 독주회",
                "link": "https://iq.ifac.or.kr/culture/view.do?key=m2102173812856&category=CUL01&eventSn=12084",
                "category": "공연",
                "sdate": "20231223",
                "edate": "20231223",
                "place": "엘림아트센터 엘림홀(대공연장)",
                "placeSido": "인천광역시",
                "placeGugun": "인천광역시 서구",
                "management": "엘림아트센터",
                "feeCase": "무료",
                "fee": "전석 10,000원",
                "tel": "032-289-4275",
                "homepage": "www.elimartcenter.co.kr/sub/performance/guide_view.asp?b_idx=1030",
                "poster": "https://iq.ifac.or.kr/fileManager/www/cultureEvent/poster/12084/1696908689390.png",
                "posterThumb": "https://iq.ifac.or.kr/fileManager/www/cultureEvent/poster/12084/1696908689390.png",
                "description": "2023년 12월 23일\r\n토요일 오후 4시 30분\r\n",
                "reserveInfo": "",
                "reserveUrl": "https://tickets.interpark.com/goods/23016366?app_tapbar_state=hide&",
                "pubDate": "2023-11-07 16:22"
            }
        ],
        "totalCnt": 10400,
        "resultCode": "0000",
        "errorMsg": "",
        "resultMsg": "정상 처리되었습니다."
    }
]

공공데이터 api와는 살짝 다른느낌이다 그래도 json depth만 잘 파악하면 쉽다

@Service
@RequiredArgsConstructor
public class FestivalService {

    private final FestivalClient festivalClient;

    @Value("${iq.api.apikey}")
    private String apikey;


    public List<FestivalResponse> getFestival(int page, int size) {

        List<FestivalResponse> festivalDataList = festivalClient.getFestivalInfo(
                apikey,
                "culture",
                "json",
                page,
                size);

        return festivalDataList;
    }
}
@FeignClient(value = "tour-api", url = "${iq.api.url}", configuration = FeignMapperConfig.class)
public interface FestivalClient {


    @GetMapping(value = "")
    List<FestivalResponse> getFestivalInfo(@RequestParam("apiKey") String apiKey,
                                           @RequestParam("svID") String svID,
                                           @RequestParam("resultType") String resultType,
                                           @RequestParam("cPage") int cPage,
                                           @RequestParam("pSize") int pSize);
}
@Data
public class FestivalList {

    private FestivalData item;
    private int totalCnt;
    private String resultCode;
    private String errorMsg;
    private String resultMsg;
}
@Data
public class FestivalData {

    private Long idx;
    private String title;
    private String link;
    private String category;
    private String sdate;
    private String edate;
    private String place;
    private String placeSido;
    private String placeGugun;
    private String management;
    private String feeCase;
    private String fee;
    private String tel;
    private String homepage;
    private String poster;
    private String posterThumb;
    private String description;
    private String reserveInfo;
    private String reserveUrl;
    private String pubDate;

}

이런식으로 하면 된다

그리고

public class FeignMapperConfig {

    private ObjectMapper customObjectMapper = new ObjectMapper()
            .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
            .enable(DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT);

    @Bean
    public Decoder feignDecoder() {
        return new ResponseEntityDecoder(new JacksonDecoder(customObjectMapper)); // 디코딩 과정에서 사용할 수 있는 Decoder Bean을 생성
    }

    @Bean
    public Encoder feignEncoder() {
        return new JacksonEncoder(customObjectMapper); //인코딩 과정에서 사용할 수 있는 Encoder Bean을 생성
    }
}

이코드도 추가해주는데 page를 너무 크게 보내거나 데이터가 더 없으면 오지 않은 데이터들을 못읽는것을 방지하기 위해서 저런 코드를 추가했는데

customObjectMapper: 이 부분은 Jackson ObjectMapper를 구성. ObjectMapper는 JSON 데이터를 Java 객체로 변환하거나 Java 객체를 JSON으로 직렬화하는 데 사용. 여기에서는 다음과 같은 설정을 수행:

  1. FAIL_ON_UNKNOWN_PROPERTIES: 이 설정을 비활성화하여 JSON 응답에 매핑되지 않은 프로퍼티가 있을 때 오류를 발생시키지 않도록 한다. 즉, JSON 응답에 불일치하는 프로퍼티가 있어도 무시한다.
  2. ACCEPT_EMPTY_STRING_AS_NULL_OBJECT: 이 설정을 활성화하여 빈 문자열("")을 null 객체로 처리. 이것은 JSON 데이터에서 빈 문자열을 null로 취급한다.
  3. feignDecoder(): 이 메서드는 Feign 클라이언트에서 응답을 처리하는 데 사용되는 Decoder를 설정. JacksonDecoder를 사용하여 JSON 응답을 Java 객체로 변환하고, 이때 이전에 정의한 customObjectMapper를 사용. customObjectMapper의 설정에 따라 불일치하는 프로퍼티를 무시하고 빈 문자열을 null로 처리.
  4. feignEncoder(): 이 메서드는 Feign 클라이언트에서 요청을 보낼 때 사용하는 Encoder를 설정. JacksonEncoder를 사용하여 Java 객체를 JSON으로 직렬화하고 요청 본문으로 전송. 이 역시 customObjectMapper를 활용하여 설정한다.

이 설정을 통해 Feign 클라이언트는 외부 API와의 통신 시 JSON 데이터를 요청하고 응답을 처리하며, 불일치하는 프로퍼티를 무시하고 빈 문자열을 null로 처리한다

그리고 @Configuration이 없는 이유는 컴포넌트 스캔이 발생할때 빈으로 등록되서 모든 FeignClient에 적용된다 그러면 다른 api를 연동할때 또 뜯어고쳐야되서

@FeignClient(value = "tour-api", url = "${iq.api.url}", configuration = FeignMapperConfig.class)

이렇게 해서 직접 Config를 읽어오게했다

0개의 댓글

관련 채용 정보