๐Ÿ“š [Spring] - FeignClient

CodeByHanยท2025๋…„ 7์›” 20์ผ

์Šคํ”„๋ง

๋ชฉ๋ก ๋ณด๊ธฐ
28/33

ํ”„๋กœ์ ํŠธ๋ฅผ ์ง„ํ–‰ํ•˜๋˜ ์ค‘ ์šฐ์—ฐํžˆ HTTP ์š”์ฒญ์„ ๋ณด๋‚ด์•ผ ํ•  ์ผ์ด ์ƒ๊ฒผ๋‹ค. HTTP ํด๋ผ์ด์–ธํŠธ๋กœ๋Š” ์ผ๋ฐ˜์ ์œผ๋กœ RestTemplate์ด๋‚˜ WebClient๋ฅผ ๋งŽ์ด ์‚ฌ์šฉํ•˜์ง€๋งŒ, ๋„ทํ”Œ๋ฆญ์Šค์—์„œ ๊ฐœ๋ฐœํ•œ FeignClient์— ํฅ๋ฏธ๊ฐ€ ์ƒ๊ฒจ ์ง์ ‘ ์ ์šฉํ•ด๋ณด์•˜๋‹ค.

๐Ÿ“Œ FeignClient

๋„ทํ”Œ๋ฆญ์Šค์—์„œ ๊ฐœ๋ฐœํ•œ HTTP Client๋กœ, ์›๋ž˜๋Š” Spring Cloud Netflix Feign์˜ ์ผ๋ถ€์˜€์ง€๋งŒ, ์ดํ›„ ๋„ทํ”Œ๋ฆญ์Šค๊ฐ€ ์œ ์ง€๋ณด์ˆ˜์—์„œ ์†์„ ๋–ผ๋ฉด์„œ ํ˜„์žฌ๋Š” OpenFeign์ด๋ผ๋Š” ์ด๋ฆ„์œผ๋กœ ์ปค๋ฎค๋‹ˆํ‹ฐ ์ฃผ๋„์˜ ์˜คํ”ˆ ์†Œ์Šค ํ”„๋กœ์ ํŠธ๋กœ ์ „ํ™˜๋˜์—ˆ๋‹ค. Spring Cloud๋Š” ์—ฌ์ „ํžˆ ์ด๋ฅผ ํ†ตํ•ฉํ•ด ์‚ฌ์šฉํ•˜๊ณ  ์žˆ์œผ๋ฉฐ, ์„ ์–ธํ˜• ๋ฐฉ์‹์œผ๋กœ HTTP ์š”์ฒญ์„ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ์–ด ์ฝ”๋“œ์˜ ๊ฐ„๊ฒฐ์„ฑ๊ณผ ๊ฐ€๋…์„ฑ์„ ๋†’์ด๋Š” ๋ฐ ์œ ์šฉํ•˜๋‹ค.

MSA์˜ ์„œ๋น„์Šค๋“ค์ด ๋งŽ์•„์ง€๋ฉด์„œ ๊ฐ๊ฐ์˜ ์„œ๋น„์Šค๋“ค ์‚ฌ์ด์— ํ†ต์‹ ์ด ๋งŽ์•„์ง€๊ฒŒ ๋˜์—ˆ๋Š”๋ฐ, ์ด๋•Œ FeignClient๋ฅผ ์ ์šฉํ•˜๋ฉด ๊ธฐ์กด ๋ฐฉ์‹๋“ค๋ณด๋‹ค ์กฐ๊ธˆ ๋” ํŽธ๋ฆฌํ•˜๊ฒŒ ์‚ฌ์šฉ ํ•  ์ˆ˜ ์žˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ์ฝ”๋“œ์˜ ์ค‘๋ณต๋„ ์ค„์ผ ์ˆ˜ ์žˆ๋‹ค.

์˜์กด์„ฑ

dependencyManagement {
    imports {
        mavenBom "org.springframework.cloud:spring-cloud-dependencies:2025.0.0"
    }
}

implementation 'org.springframework.cloud:spring-cloud-starter-openfeign'

์Šคํ”„๋ง๋ถ€ํŠธ์™€์˜ ํ˜ธํ™˜์„ฑ ์ฃผ์˜!!

@SpringBootApplication
@EnableFeignClients(basePackages = "com.deal4u.fourplease.domain.payment")
public class FourPleaseBeApplication {

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

@EnableFeignClients ์–ด๋…ธํ…Œ์ด์…˜์„ ๋ถ™์—ฌ์ฃผ๋ฉด ๋˜๋Š”๋ฐ ํ•„์š”์— ๋”ฐ๋ผ ๋ฒ”์œ„๋ฅผ ์ง€์ • ๊ฐ€๋Šฅํ•˜๋‹ค.

@FeignClient(
        name = "tossClient",
        url = "https://api.tosspayments.com",
        configuration = TossFeignConfig.class
)
public interface TossApiClient {

    @PostMapping("/v1/payments/confirm")
    TossPaymentConfirmResponse confirmPayment(
            @RequestBody
            TossPaymentConfirmRequest request
    );
}
@Configuration
public class TossFeignConfig {

    @Value("${toss.secret-key}")
    private String secretKey;

    @Bean
    public RequestInterceptor requestInterceptor() {
        return requestTemplate -> {
            String encodedKey = Base64.getEncoder().encodeToString((secretKey + ":").getBytes());
            requestTemplate.header("Authorization", "Basic " + encodedKey);
            requestTemplate.header("Content-Type", "application/json");
        };
    }
}

๋‚ด ํ”„๋กœ์ ํŠธ์—์„œ๋Š” ์™ธ๋ถ€ ๊ฒฐ์ œ API์ธ ํ† ์ŠคํŽ˜์ด๋จผ์ธ  API๋ฅผ ํ˜ธ์ถœํ•ด์•ผ ํ•˜๋Š” ๋กœ์ง์ด ํ•„์š”ํ–ˆ๋‹ค. ๋”ฐ๋ผ์„œ HTTP ์š”์ฒญ์„ ๋ณด๋‹ค ์„ ์–ธ์ ์ด๊ณ  ๊ฐ„๊ฒฐํ•˜๊ฒŒ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ๋Š” FeignClient๋ฅผ ํ™œ์šฉํ•ด ๊ตฌํ˜„ํ–ˆ๋‹ค. ์œ„ ์˜ˆ์‹œ๋Š” /v1/payments/confirm ์—”๋“œํฌ์ธํŠธ๋กœ ๊ฒฐ์ œ ์Šน์ธ ์š”์ฒญ์„ ๋ณด๋‚ด๋Š” ์ธํ„ฐํŽ˜์ด์Šค์ด๋ฉฐ, TossFeignConfig๋ฅผ ํ†ตํ•ด ์ธ์ฆ ํ—ค๋”์™€ Content-Type ๋“ฑ์„ ์ „์—ญ ์„ค์ •์œผ๋กœ ์ง€์ •ํ–ˆ๋‹ค. ์ด์ฒ˜๋Ÿผ ์™ธ๋ถ€ API ์—ฐ๋™ ์‹œ ํ•„์š”ํ•œ ๊ณตํ†ต ํ—ค๋”๋ฅผ RequestInterceptor์—์„œ ์ฒ˜๋ฆฌํ•จ์œผ๋กœ์จ ์ฝ”๋“œ์˜ ์žฌ์‚ฌ์šฉ์„ฑ๊ณผ ์œ ์ง€๋ณด์ˆ˜์„ฑ์„ ๋†’์ผ ์ˆ˜ ์žˆ์—ˆ๋‹ค.

profile
๋…ธ๋ ฅ์€ ๋ฐฐ์‹ ํ•˜์ง€ ์•Š์•„ ๐Ÿ”ฅ

0๊ฐœ์˜ ๋Œ“๊ธ€