[네이버 클라우드 서포터즈] 스텝페이 API 연결편

himitery·2022년 10월 28일
0

오늘의빵 서비스에서는 빵을 구독하는 기능을 제공하기 위해 스텝페이의 API를 사용합니다. 오늘은 오늘의빵 서비스에서 스텝페이의 API를 연결하는 과정을 담아봤습니다.

Spring Boot에서는 외부의 REST API를 사용하기 위해 Rest Template를 많이 사용하는 것 같습니다. Rest Template는 Spring 3부터 제공되는 기능으로 동기적으로 REST API를 요청하고 응답을 기다리는 방식입니다.
오늘의빵 서비스에서도 Rest Template을 사용하여 스텝페이의 API를 사용하였습니다.

먼저 Rest Template을 사용하기 위해 RestTemplateConfig 파일에서 Bean을 등록해주었습니다. Bean으로 등록하지 않아도 new RestTemplate()로 사용이 가능하긴 하지만, 기본 설정 값을 유지시키기 위해 Bean에 등록하게 되었습니다.

/* RestTemplateConfig */

@Configuration
public class RestTemplateConfig {

    @Value("${steppay.end-point}")
    String baseUri;
    
    @Value("${steppay.secret}")
    String secretKey;

    @Bean
    public RestTemplate restTemplate() {
        return new RestTemplateBuilder()
            .rootUri(baseUri)
            .defaultHeader(HttpHeaders.ACCEPT, MediaType.ALL_VALUE)
            .defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
            .defaultHeader("Secret-Token", secretKey)
            .build();
    }
}

스텝페이의 API 사용하기 위해 Header에 Content-Type을 지정하였고, 발급 받은 Secret-Token을 넣어줬습니다.

Bean으로 등록된 RestTemplate는 Spring에서 관리되고, 의존성을 주입 받을 수 있게 됩니다. 이제 RestTemplate를 이용하여 실제로 스텝페이에 요청을 보내고 응답을 받는 서비스를 만들었습니다. 먼저, 스텝페이에 상품을 등록할 수 있는 API를 요청하는 부분입니다.

/* SteppayProductServiceImpl */

@Service
@RequiredArgsConstructor
public class SteppayProductServiceImpl implements SteppayProductService {

    private final RestTemplate template;

    public SteppayProductResponse create(SteppayCreateProductRequest request) {
        return template.postForObject(
            "/products",
            request,
            SteppayProductResponse.class
        );
    }
}
/* SteppayCreateProductRequest */

@Getter
public class SteppayCreateProductRequest {

    String type;
    String status;
    String name;
    String featuredImageUrl;
    String description;

    @Builder
    public SteppayCreateProductRequest(
        String name,
        String featuredImageUrl,
        String description
    ) {
        this.type = "BOX";
        this.status = "SALE";
        this.name = name;
        this.featuredImageUrl = featuredImageUrl;
        this.description = description;
    }
}
/* SteppayProductResponse */

@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class SteppayProductResponse {

    Integer id;
    LocalDateTime createdAt;
    LocalDateTime modifiedAt;
    String code;
    String type;
    String status;
    String name;
    String featuredImageUrl;
    String description;
    List<SteppayPricePlanResponse> prices;

    @Builder
    public SteppayProductResponse(
        Integer id,
        LocalDateTime createdAt,
        LocalDateTime modifiedAt,
        String code,
        String type,
        String status,
        String name,
        String featuredImageUrl,
        String description,
        List<SteppayPricePlanResponse> prices
    ) {
        this.id = id;
        this.createdAt = createdAt;
        this.modifiedAt = modifiedAt;
        this.code = code;
        this.type = type;
        this.status = status;
        this.name = name;
        this.featuredImageUrl = featuredImageUrl;
        this.description = description;
        this.prices = prices;
    }
}

스텝페이에서 상품 생성을 할때의 Request DTO는 SteppayCreateProductRequest라는 이름으로 사용하였습니다. SteppayCreateProductRequest에서 type과 초기의 status 값은 일정하게 고정하기 위해 외부로부터 값을 받지 않고, 내부에서 초기화를 해주고 있습니다. status의 경우 나중에 판매 상태를 종료하기 위해 변경할 수 있도록 '상품 수정' API를 호출하여 변경할 수 있도록 할 예정입니다.

또한 스텝페이에서 반환 받는 상품의 Response DTO는 SteppayProductResponse라는 이름으로 사용하였습니다. SteppayProductResponse에는 실제로 더 많은 값이 반환되지만, 저희의 서비스에서 필요한 부분만 객체로 변환하여 저장할 수 있도록 하였습니다.

API가 잘 작동하는지 확인하기 위해 테스트 코드를 작성하였습니다.

/* SteppayProductServiceImplTest */

@SpringBootTest
class SteppayProductServiceImplTest {

    @Autowired
    private SteppayProductServiceImpl steppayCreateProductService;

    @Test
    @DisplayName("스텝페이 상품을 생성할 수 있어요.")
    public void create() {
        SteppayProductResponse response = steppayCreateProductService.create(
            SteppayCreateProductRequest.builder()
                .name("test_package")
                .featuredImageUrl("featured_image_url")
                .description("test_package_description")
                .build()
        );

        assertThat(response).isNotNull().isInstanceOf(SteppayProductResponse.class);

        assertThat(response.getId()).isNotNull();
        assertThat(response.getType()).isEqualTo("BOX");
        assertThat(response.getStatus()).isEqualTo("SALE");
        assertThat(response.getName()).isEqualTo("test_package");
        assertThat(response.getFeaturedImageUrl()).isEqualTo("featured_image_url");
        assertThat(response.getDescription()).isEqualTo("test_package_description");
    }
}

Intellij에서 테스트를 진행했을때 다행히 테스트를 통과하는 것을 확인할 수 있었습니다.

이번에는 RestTemplate로 API 호출이 잘 되는지 확인할 목적으로 직접 API 요청을 통해 테스트를 작성하였지만, SteppayProductServiceImpl 서비스가 다른 기능에서 사용될 때에는 해당 기능의 테스트에서 스텝페이의 API의 호출이 테스트를 실패시킬 수 있기 때문에 다른 방법을 이용하였습니다.

다른 기능을 테스트 할 때에 오늘의빵에서 적용한 테스트 방법은 다음 포스트에서 살펴보도록 하겠습니다!

0개의 댓글