본문 바로가기
Spring

인터파크 API 사용하기

by e-pd 2021. 7. 26.

리액트 연습할겸 도서API를 찾다가 

인기 순위같은 것들을 사용하고 싶었기에 인터파크 API를 써보기로했다.

 

http://book.interpark.com/bookPark/html/bookpinion/api_main.html

 

API 키가 필요한데 도서 인터파크로 들어가서

상단 북피니언으로 들어간다.

http://book.interpark.com/bookPark/html/book.html

 

[인터파크도서] 싸니까 믿으니까 인터파크도서

싸니까 믿으니까 인터파크니까 인터파크 도서 책을 고르고, 구매하고, 읽고, 공유하는 것까지 한 번에! 책에 관한 모든 것, '인터파크 도서'를 만나보세요.

book.interpark.com

 

 

여기서 왼쪽 관리에 들어가면 API키를 사용할 수 있다.

 

이제 리액트앱을 만들.......려고 했으나 인터파크에서 CORS 허용을 안해줘서 그냥은 쓸수없다 😱

덕분에 어느정도 만들다가 지웠다.

 

다른 API중에 알라딘 API가 있는데 검색해보니 이것도 클라이언트 호출시 CORS 허용을 안해준 것같다.

그러면 해결방법으로 백엔드에서 외부 API 호출하여 그것을 다시 프론트로 던지기로 했다.

 

 

 

 

백엔드는 Spring Boot를 선택했다. 아무래도 익숙한 것을 쓰는게 마음에 편하다.

인터파크에서 API 연동 예제를 제공하고 있다.

http://www.interpark.com/openapi/site/APIJavaEx.jsp

 

http://www.interpark.com/openapi/site/APIJavaEx.jsp

import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.DataInputStream; import java.io.DataOutputStream; import java.net.Socket; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; i

www.interpark.com

??....뭔가 복잡하다.

 

차라리 익숙한 호출방식을 고려해본다.

보통 외부 API 호출시에 REST TEMPLATE를 많이 쓰는데 REST TEMPLATE가 곧 Deprecated된다고 한다.

그래서 WebClient를 쓰기로 했다.

 

나는 그레이들로 프로젝트를 설정했는데, build gradle에 

implementation 'org.springframework.boot:spring-boot-starter-webflux'

 

웹플럭스를 넣어주면된다. 웹플럭스는 범위가 넓긴한데 그중 WebClient만 쓸 생각이다.

 

외부 key관리는 application.yml에다 많이 쓰지만 property에다가 보관하여 사용하기로했다.

 

해당파일을 버젼관리한다면 .gitignore에 포함하여 커밋제외한다.

 

resources 밑에 interpark라는 프로퍼티를 만든다.

내부 파일에는

interpark.key = [API 키]

이런식으로 설정을 해두었다.

 

이제 인터파크를 사용하는 WebClient를 설정한다.

공용으로 쓸거라 global 패키지 밑에 두었다.

 

@ConfigurationProperties에 properties파일의 prefix을 적어둔다.

나는 interpark.key를 접근할 것이기때문에 필드는 key로 두었다.

key의 setter, getter가 필요해서 롬복의 @Data를 사용했다.

 

PropertiesConfiguration 파일에서 resource 파일의 프로퍼티와 적용할 클래스를 설정할 수 있다.

@Configuration
@EnableConfigurationProperties({
        InterparkProperties.class
})
@PropertySource({
        "classpath:properties/interpark.properties"
})
public class PropertiesConfiguration {
}

이제 준비가 되었다. 이왕하는거 WebClient까지 bean에 등록한다.

 

@RequiredArgsConstructor
@Configuration
public class InterparkConfiguration {

    @Bean
    public WebClient interparkWebClient() {
        return WebClient.builder()
                .baseUrl("http://book.interpark.com/api").build();
    }
}

 

 

이제 controller, service에서 호출해서 쓰기로 한다.

 

BookController.java

@RequiredArgsConstructor
@RestController
@RequestMapping("/api/v1/books")
public class BookController {
    private final BookService bookService;

    @GetMapping("/popular")
    public InterparkResponseDto popular() {
        return bookService.getPopluarBooks();
    }
}

BookService.java

@RequiredArgsConstructor
@Service
@Transactional
public class BookService {
    private final InterparkClient interparkClient;

    public InterparkResponseDto getPopluarBooks() {
        return interparkClient.getPopularBooks();
    }
}

이제 API 호출 클라이언트다.

내가 사용할 것은 베스트 셀러 API이다. 카테고리, 출력, 키값 설정을 한다.

@RequiredArgsConstructor
@Slf4j
@Component
public class InterparkClient {
    private static final int IT_CATEGORY = 122;
    private final InterparkProperties properties;
    private final WebClient webClient;

    public InterparkResponseDto getPopularBooks() {
        InterparkResponseDto interparkResponseDto = convertToResponse(getBooksFromApi());
        return interparkResponseDto;
    }

    private InterparkResponseDto getBooksFromApi() {
        InterparkResponseDto items = null;
        try {
            items = webClient.get()
                    .uri(builder -> builder.path("/bestSeller.api")
                            .queryParam("categoryId", IT_CATEGORY)
                            .queryParam("output", "json")
                            .queryParam("key", properties.getKey()).build())
                    .retrieve()
                    .bodyToMono(InterparkResponseDto.class).block();
        } catch (Exception e) {
            log.info(e.getMessage());
        }
        return items;
    }

바로 API 호출하면 될 것 같지만 

content type 'text/json;charset=utf-8' not supported

 

라는 오류를 만나며 변환에 실패한다. 구글링을 해보니 Content-Type: 'application/json' 옵션이 없어서 그런 오류가 발생한다고 한다.

.accept(MediaType.APPLICATION_JSON) 옵션을 주었다.

@RequiredArgsConstructor
@Slf4j
@Component
public class InterparkClient {
    private static final int IT_CATEGORY = 122;
    private final InterparkProperties properties;
    private final WebClient webClient;

    public InterparkResponseDto getPopularBooks() {
        InterparkResponseDto interparkResponseDto = convertToResponse(getBooksFromApi());
        return interparkResponseDto;
    }

    private InterparkResponseDto getBooksFromApi() {
        InterparkResponseDto items = null;
        try {
            items = webClient.get()
                    .uri(builder -> builder.path("/bestSeller.api")
                            .queryParam("categoryId", IT_CATEGORY)
                            .queryParam("output", "json")
                            .queryParam("key", properties.getKey()).build())
                    .retrieve()
                    .accept(MediaType.APPLICATION_JSON)
                    .bodyToMono(InterparkResponseDto.class).block();
        } catch (Exception e) {
            log.info(e.getMessage());
        }
        return items;
    }

문제는 같은 오류로 계속 안된다는 것이다.

내가 호출을 잘못했나? 그래서 String으로 받아보기로 했다.

  private String getBooksFromApi() {
        String items = null;
        try {
            items = webClient.get()
                    .uri(builder -> builder.path("/bestSeller.api")
                            .queryParam("categoryId", IT_CATEGORY)
                            .queryParam("output", "json")
                            .queryParam("key", properties.getKey()).build())
                    .accept(MediaType.APPLICATION_JSON)
                    .retrieve()
                    .bodyToMono(String.class).block();
        } catch (Exception e) {
            log.info(e.getMessage());
        }
        return items;
    }

의외로 JSON String이 잘 넘어왔다.

String 값이 잘 넘어왔으니, Jackson을 사용해서 Object로 바꿔주면 끝이다.

 

private InterparkResponseDto convertToResponse(String textData) {
        InterparkResponseDto interparkResponseDto = new InterparkResponseDto();
        try {
            interparkResponseDto = objectMapper.readValue(textData, InterparkResponseDto.class);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return interparkResponseDto;
    }

 

잘된다. 

호출부 전체 소스다

 

@RequiredArgsConstructor
@Slf4j
@Component
public class InterparkClient {
    private static final int IT_CATEGORY = 122;
    private final InterparkProperties properties;
    private final WebClient webClient;
    private ObjectMapper objectMapper = new ObjectMapper();

    public InterparkResponseDto getPopularBooks() {
        InterparkResponseDto interparkResponseDto = convertToResponse(getBooksFromApi());
        return interparkResponseDto;
    }

    private String getBooksFromApi() {
        String items = null;
        try {
            items = webClient.get()
                    .uri(builder -> builder.path("/bestSeller.api")
                            .queryParam("categoryId", IT_CATEGORY)
                            .queryParam("output", "json")
                            .queryParam("key", properties.getKey()).build())
                    .accept(MediaType.APPLICATION_JSON)
                    .retrieve()
                    .bodyToMono(String.class).block();
        } catch (Exception e) {
            log.info(e.getMessage());
        }
        return items;
    }

    private InterparkResponseDto convertToResponse(String textData) {
        InterparkResponseDto interparkResponseDto = new InterparkResponseDto();
        try {
            interparkResponseDto = objectMapper.readValue(textData, InterparkResponseDto.class);
        } catch (Exception e) {
            log.info(e.getMessage());
        }
        return interparkResponseDto;
    }
}

열심히 만들었는데 이제 API 제공자만 살아있으면 된다. 

'Spring' 카테고리의 다른 글

RequestMapping("/") vs RequestMapping("")  (0) 2021.10.07
Propagation 주석  (0) 2021.08.16
@NotNull @NotEmpty @NotBlank  (0) 2021.01.16
Parameterized Test를 이용해서 여러 값 검증하기  (0) 2021.01.16
Component Scan  (0) 2020.08.15