OpenFeign์ ์ด์ฉํ์ฌ API ํต์ ํด๋ณด๊ธฐ (feat. ๊ณ ์์ด ์ฌ์ง ๊ฒ์)

ํด๋น ์ฝ์ค์ ๊ณผ์ ๋ฅผ ์ํํ ๋ด์ฉ์ ๋๋ค.
[Java/Spring]๊ณ ์์ด ์ฌ์ง ๊ฒ์ ์ฌ์ดํธ API ๊ณผ์ ํ์ด๋ณด๊ธฐ
[Java/Spring]๊ณ ์์ด ์ฌ์ง ๊ฒ์ ์ฌ์ดํธ API ๊ณผ์ ํ์ด๋ณด๊ธฐ
[Java/Spring]๊ณ ์์ด ์ฌ์ง ๊ฒ์ ์ฌ์ดํธ API ๊ณผ์ ํ์ด๋ณด๊ธฐ ์ฝ์ค ๋์ด๋ ์ด๊ธ ์ฌ์ฉ ์ธ์ด # java ๊ฐ์ ์๊ฐ ํ๋ก๊ทธ๋๋จธ์ค ๊ณผ์ ํ ์คํธ ์ฐ์ต์ ์๋ ๊ณ ์์ด ์ฌ์ง ๊ฒ์ ์ฌ์ดํธ์์ ์ฌ์ฉ๋ API๋ฅผ ์ง์ ๊ตฌํํด
school.programmers.co.kr
์ ๊ฐ ์ฐ๋ํ ์ธ๋ถ API๋ ๊ณ ์์ด ์ฌ์ง์ ์กฐํํ๋ The Cat API์ ๋๋ค.
The Cat API - Cats as a Service.
A public service API all about Cats, free to use when making your fancy new App, Website or Service.
TheCatAPI.com
Feign
Feign์ Netflix์ ์ํด ์ฒ์ ๋ง๋ค์ด์ง declarative(์ ์ธ์ ์ธ) web service client์ด๋ฉฐ ์น ์๋น์ค ํด๋ผ์ด์ธํธ๋ฅผ ์ฝ๊ฒ ์์ฑํ ์ ์๋๋ก ๋์์ค๋ค.
โ์ ์ธ์ โ์ด๋ annotation์ ์ฌ์ฉ์ ์๋ฏธํ๋ฉฐ ์ธํฐํ์ด์ค๋ฅผ ์์ฑํ๊ณ ์ด๋ ธํ ์ด์ ์ ์ ์ธํ๊ธฐ๋ง ํ๋ฉด ์ธ๋ถ API๋ฅผ ์ฝ๊ฒ ํธ์ถ์ ํ ์ ์๋ค๋ ๊ฒ์ด๋ค. ๋ง์น Spring Data JPA์์ ์ค์ ์ฟผ๋ฆฌ๋ฅผ ์์ฑํ์ง ์๊ณ ์ธํฐํ์ด์ค๋ง ์ง์ ํ๋ฉด ์ฟผ๋ฆฌ ์คํ ๊ตฌํ์ฒด๋ฅผ ๋ง๋ค์ด์ฃผ๋ ๊ฒ๊ณผ ์ ์ฌํ๋ค!
Spring Cloud๊ฐ Open Feign์ ์คํ๋ง ํด๋ผ์ฐ๋ ์ํ๊ณ๋ก ํตํฉ ์ํค๋ฉฐ Spring MVC ์ด๋ ธํ ์ด์ ์ ์ง์ํ๊ฒ ๋์๋ค.
Spring Cloud OpenFegin
https://cloud.spring.io/spring-cloud-openfeign/reference/html/
Spring Cloud OpenFeign
Feign is a declarative web service client. It makes writing web service clients easier. To use Feign create an interface and annotate it. It has pluggable annotation support including Feign annotations and JAX-RS annotations. Feign also supports pluggable
cloud.spring.io
์ฌ์ฉํด๋ณด๊ธฐ
์์กด์ฑ ์ถ๊ฐ(Gradle)
Spring Cloud ์์กด์ฑ ์ถ๊ฐ
plugins {
id 'java'
id 'org.springframework.boot' version '3.0.5'
id 'io.spring.dependency-management' version '1.1.0'
}
ext {
set('springCloudVersion', "2022.0.1")
}
dependencyManagement {
imports {
mavenBom "org.springframework.cloud:spring-cloud-dependencies:${springCloudVersion}"
}
}
OpenFeign ์์กด์ฑ ์ถ๊ฐ
implementation 'org.springframework.cloud:spring-cloud-starter-openfeign'
OpenFeign ํ์ฑํ
Main ํด๋์ค์ ๋ถ์ฌ์ค๋ ๋์ง๋ง ๋ณ๋์ Config ํ์ผ์ ๋ง๋ค์ด ์ค๋๋ค. (์ฐธ๊ณ ํ ๊ด๋ จ ๋ด์ฉ์ ๋๋ค. https://mangkyu.tistory.com/243)
@Configuration
@EnableFeignClients("com.search.cat_picture") // ์ ์ ํ๋ก์ ํธ ํจํค์ง ๊ฒฝ๋ก์
๋๋ค
public class OpenFeignConfig {
}
@EnableFeignClients์ ์ถ๊ฐํ๋ฉด ์ง์ ๋ ๊ฒฝ๋ก ์ดํ์ ํจํค์ง๋ฅผ ํ์ํ๋ฉด์ @FeignClient ์ด๋ ธํ ์ด์ ์ด ๋ถ์ ์ธํฐํ์ด์ค์ ๊ตฌํ์ฒด๋ฅผ ๋ง๋ค์ด ์ค๋๋ค.
๊ตฌํํ๊ธฐ
ํ์ฌ ์๊ตฌ ์ฌํญ์ ๋ฐ๋ผ GET ์์ฒญ๋ง ํ์ํ๊ธฐ ๋๋ฌธ์ ์๋์ ๊ฐ์ด ์ฝ๋๋ฅผ ์์ฑํด ๋ณด์์ต๋๋ค.
@FeignClient(name = "TheCatImageClient", url = "${THE_CAT_CLIENT_URL}/images")
@Headers("x-api-key: ${THE_CAT_CLIENT_KEY}")
public interface TheCatImageClient {
@GetMapping(value = "/search")
List<TheCatSimpleImageResponse> findRandomPictures(@RequestParam("limit") Integer limit);
@GetMapping(value = "/{imagesId}")
TheCatImageResponse findCatPictureById(@PathVariable String imagesId);
@GetMapping(value = "/search")
List<TheCatSimpleImageResponse> findPicturesByBreed(@RequestParam("breed_ids") String breedId);
}
- ํ์ํ ํ๋๋ง ๋ฐ์์ ๋งคํ๋ ์ ์๊ฒ DTO๋ฅผ ๊ตฌ์ฑํฉ๋๋ค.
- The Cat API ์์ฒญ์ ๊ฐ์ ํ ๋ ์ ๊ณต๋ฐ์ key๋ฅผ ์ ๋ฌ ํด์ค์ผํ๊ธฐ ๋๋ฌธ์ ๊ณตํต Header๋ฅผ ์ถ๊ฐํด ์ค๋๋ค.
๋ก๊น ์ฒ๋ฆฌ
Fegin ๋ก๊น ์ ์ค์ง DEBUG ๋ ๋ฒจ์์๋ง ๋์ํ๋ฉฐ ํด๋ผ์ด์ธํธ๋ณ๋ก Logger.Level ์ ์ค์ ํ ์ ์์ต๋๋ค.
- NONE : ๋ก๊น ํ์ง ์์.(default)
- BASIC : Request Method์ URL ๊ทธ๋ฆฌ๊ณ Reponse ์ํ ์ฝ๋์ ์คํ ์๊ฐ์ ๋ก๊น
- HEADERS : Request, Response Header ์ ๋ณด์ ํจ๊ป BASIC ์ ๋ณด๋ฅผ ๋ก๊น
- FULL : Request์ Response์ Header, Body ๊ทธ๋ฆฌ๊ณ ๋ฉํ๋ฐ์ดํฐ๋ฅผ ๋ก๊น
๋ก๊น ์ ํ๋ ๋ฐฉ๋ฒ์ application.yml์ ์ด์ฉํ๊ฑฐ๋ Configuratin ์ค์ ์ ์ด์ฉํด์ ์ค์ ํ ์ ์์ต๋๋ค. ์ ๋ Configuratin์ ํตํด ์ค์ ํ์์ต๋๋ค.
์ฐ์ ํด๋น ํจํค์ง์ ๋ก๊น ๋ ๋ฒจ์ DEBUG level๋ก ์ค์ (application.yml)
logging:
level:
com.search.cat_picture.global.openFeign: DEBUG
API ๋ก๊น ๋ ๋ฒจ์ BASIC์ผ๋ก ์ง์ ํ์์ต๋๋ค.
@Configuration
@EnableFeignClients("com.search.cat_picture")
public class OpenFeignConfig {
@Bean
Logger.Level feignLoggerLevel(){
return Logger.Level.BASIC;
}
}
๋ก๊ทธ ํ์ธ

์์ธ ์ฒ๋ฆฌ
Feign์ ๊ธฐ๋ณธ ์๋ฌ ์ฒ๋ฆฌ๊ธฐ์ธ ErrorDecoder.default ๋ ํญ์ FeignException ์ ๋ฐ์์ํต๋๋ค.
ErrorDecoder๋ฅผ ๊ตฌํํ์ฌ ํด๋น ์์ธ๋ค์ ์ฌ์ฉ์ ์ ์ํ ์ ์์ต๋๋ค.
import feign.codec.ErrorDecoder;
public class FeignErrorDecider implements ErrorDecoder {
@Override
public Exception decode(String methodKey, Response response) {
return switch (response.status()) {
case 400 -> new BadRequestException();
case 404 -> new ResourceNotFoundException();
default -> new OpenFeignServerException();
};
}
}
์๋ก ๋์ง ์์ธ ๋ชจ๋ ์ ๊ฐ ๋ง๋ Custom Exception์ ๋๋ค. ์์ธ ์ํฉ์ ๋ํด ๊ฐ๋ฐ์๊ฐ ์ข๋ ์์ํ๊ฒ ํต์ ํ ์ ์๋๋ก ์ฌ์ฉ์ ์ ์ Exception์ ๊ตฌ์ฑํ์์ต๋๋ค.
Configuratin์ ํตํด ๊ตฌํํ ErrorDecoder ๋ฑ๋ก.
@Configuration
@EnableFeignClients("com.search.cat_picture")
public class OpenFeignConfig {
@Bean
Logger.Level feignLoggerLevel(){ // ๋ก๊น
return Logger.Level.BASIC;
}
@Bean
public FeignErrorDecider commonFeignErrorDecoder() { // ์์ธ ์ฒ๋ฆฌ
return new FeignErrorDecider();
}
}
์์ค์ฝ๋
https://github.com/youngjijang/cat_picture_search
GitHub - youngjijang/cat_picture_search: OpenFeign์ ์ด์ฉํ API ์ฐ๋ ์ค์ต
OpenFeign์ ์ด์ฉํ API ์ฐ๋ ์ค์ต. Contribute to youngjijang/cat_picture_search development by creating an account on GitHub.
github.com
๋ง๋ฌด๋ฆฌ
OpenFeign์ ์ฌ์ฉ๋ฒ์ ๊ทธ๋ฆฌ ์ด๋ ต์ง ์๋ค๊ณ ์๊ฐํฉ๋๋ค. ํ๋ก์ ํธ๋ฅผ ์งํํ ๋ ์ธ๋ถ API๋ฅผ ์ฌ์ฉํ๊ฒ ๋๋ค๋ฉด, ์ด๋ค์์ผ๋ก ํด๋น API์ ๋ํ ์์กด์ฑ์ ์ค์ผ ์ ์์๊น ๊ณ ๋ฏผํ๊ฒ ๋๋๋ฐ OpenFeign์ ์ฌ์ฉํ๋ ๊ฒ๋ง์ผ๋ก๋ API๋ฅผ ๊ฐ์๋ผ์ฐ๊ธฐ๊ฐ ํจ์ฌ ์์ํด์ก์ผ๋ ์ ์ง๋ณด์ ์ธก๋ฉด์์๋ ๋ถ๋ช ์ฅ์ ์ด ์์ด๋ณด์ด๋ค์.
ํ์ ๋ค๋ฅธ ๋ฐฉ์์ผ๋ก๋ ์ธ๋ถ API๋ฅผ ์ฐ๋ํด๋ณด๊ณ ๋น๊ตํ๋ ๊ธ์ ์จ๋ด๋ ์ฌ๋ฏธ์์ ๊ฒ ๊ฐ์ต๋๋ค. ์ด์จ๋ OpenFeign์ ๊ฒฝํํด๋ณด๊ณ ์ถ๊ฑฐ๋ ํ์ ์์ ์ฝ๋๋ฆฌ๋ทฐ๋ฅผ ๋ฐ์๋ณด๊ณ ์ถ์ผ์๋ค๋ฉด ํด๋น ์ฝ์ค๋ฅผ ์ถ์ฒํฉ๋๋ค. ์ฌ๋ฏธ์์์ด์. ๐
Reference.
'Spring' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
Spring Security์์ ๋ฐ์ํ ์์ธ๊ฐ ControllerAdvice์์ ํธ๋ค๋ง๋๋ ๋ฌธ์ (2) | 2024.04.25 |
---|---|
[Spring] Filter์ Interceptor ์ฐจ์ด (2) | 2023.04.22 |
[JPA] ์ปค์ ๊ธฐ๋ฐ pagenation ๊ตฌํํ๊ธฐ (8) | 2023.03.01 |
[JPA] ์คํ์ ๊ธฐ๋ฐ Pagenation ๊ตฌํํ๊ธฐ (0) | 2023.03.01 |
[Spring] Spring MVC (0) | 2023.02.18 |
๋๊ธ