프로젝트에서 외부 api에 요청을 보내야할 경우들이 있어 FeinClient를 사용해보았다. 이 과정중에 발생한 에러를 해결하며 공부하게된 내용들을 정리해본다.
의존성 관리
해당 의존성은 Springboot 3.2.4에 해당하는 의존성이다.
openfeign 라이브러리는 spring cloud 기반의 라이브러리이다. 때문에 spring cloud 의존성이 필요하며
spring cloud는 spring 과 호환성이 중요함으로 버전관리에 신경써야한다. 아래 공식 문서로 확인 가능하다.
https://spring.io/projects/spring-cloud
ext {
set('springCloudVersion', "2023.0.0")
}
dependencyManagement {
imports {
mavenBom "org.springframework.cloud:spring-cloud-dependencies:${springCloudVersion}"
}
}
dependencies {
implementation "org.springframework.cloud:spring-cloud-starter-openfeign"
}
FeignClient 기술은 RestTemplet과 흡사하지만 직접 API호출 환경을 설정하여 사용하던 RestTemplet 과는 다르게 선언적 방식과 추상화된 인터페이스를 제공함으로써 외부 API 호출이 가능하도록 한다.
기본 세팅
메인 클레스에 @EnableFeignClients 를 추가해주어 하위 패키지에 존재하는 @FeignClient 어노테이션을 찾아 구현체를 만듭니다. (Spring 의 Component와 ComponentScan의 관계와 유사)
@SpringBootApplication
@EnableFeignClients
public class Feign2Application {
public static void main(String[] args) {
SpringApplication.run(Feign2Application.class, args);
}
}
@FeignClient 인터페이스
※주의 :
@FeignClient 어노테이션 내부의 url 옵션은 호출할 api의 도메인 or IP 주소값이 입력되어야한다!!
@RequestMapping + @GetMapping 의 경우 두 경로값을 합쳐 EndPoint를 찾아 가는 점과 다르게 url에 접근할 도메인 or 서버의 주소를 기입해주어야한다.
**맨 마지막에 잘못된 사용예와 수정 후 참고**
테스트 환경 세팅
1. FeignClient 환경(8080 포트)
1-1 FeignClient 인터페이스
@FeignClient(name = "example", url = "http://localhost:8282")
public interface FeignClientService {
@GetMapping(value = "/test")
Result getInfo(
@RequestHeader(value = "Authorization", required = false) String token,
@RequestParam(name = "name", required = false)String name,
@RequestParam(name = "age", required = false) Integer age,
@RequestParam(name = "status" , required = false)Integer status);
}
1-2 FeignClient 컨트롤러
@RestController
@RequiredArgsConstructor
@Slf4j
public class FeignClientController {
private final FeignClientService feignClientService;
@GetMapping("/feign")
public ResponseEntity<Result> feignClientTest(
@RequestHeader(HttpHeaders.AUTHORIZATION) String header,
@RequestParam(name = "name", required = false) String name,
@RequestParam(name = "age", required = false) Integer age,
@RequestParam(name = "status", required = false) Integer status) {
log.info("feign 호출");
Result info = feignClientService.getInfo(header, name, age, status);
return ResponseEntity.ok(info);
}
}
2. 외부 api 환경 세팅 (8282 포트)
받은 요청을 바로 body로 돌려주는 세팅 + 애러 발생 테스트를 위한 HttpStatus를 파라미터 세팅
@Slf4j
@RestController
public class TestController {
@GetMapping("/test")
public ResponseEntity<Result> getInfo(HttpServletRequest request , @RequestParam(name = "status", required = false, defaultValue = "200") int status) {
Result result = new Result();
request.getHeaderNames().asIterator().forEachRemaining((i) -> result.headerResult.add(i + " : " + request.getHeader(i)));
request.getParameterNames().asIterator().forEachRemaining((i) -> result.parameterResult.add(i + " : " + request.getParameter(i)));
HttpStatus httpStatus = HttpStatus.valueOf(status);
return ResponseEntity.status(httpStatus).body(result);
}
@Data
static class Result {
List<String> headerResult = new ArrayList<>();
List<String> parameterResult = new ArrayList<>();
String body;
}
}
요청 및 응답
8080 포트의 애플리케이션을 통해 8282의 응답을 받아온 결과를 볼 수 있음
잘못 된 사용 예
서로 다른 도메인의 api를 호출할 때 아래와 같이 하나의 인터페이스에 몰아 넣고 EndPoint를 합치려 하였으나 애러가 발생했다.
@FeignClient(name = "google-oauth2-client", url = "https://")
public interface GoogleOauth2Client {
@PostMapping("oauth2.googleapis.com/token")
OAuthTokenResponse getToken(@RequestParam(name = "grant_type") String grantType,
@RequestParam(value = "client_id") String clientId,
@RequestParam(value = "client_secret") String clientSecret,
@RequestParam(value = "redirect_uri") String redirectUri,
@RequestParam(value = "code") String code);
@GetMapping(value = "www.googleapis.com/oauth2/v2/userinfo")
GoogleUserInfo getUserInfo(@RequestHeader(value = HttpHeaders.AUTHORIZATION) String token);
}
수정
때문에 아래와 같이 도메인별로 인터페이스를 나누었다.
@FeignClient(name = "google-oauth2-token-client", url = "https://oauth2.googleapis.com")
public interface GoogleOauth2TokenClient {
@PostMapping("/token")
OAuthTokenResponse getToken(@RequestParam(name = "grant_type") String grantType,
@RequestParam(value = "client_id") String clientId,
@RequestParam(value = "client_secret") String clientSecret,
@RequestParam(value = "redirect_uri") String redirectUri,
@RequestParam(value = "code") String code);
}
@FeignClient(name = "google-oauth2-info-client", url = "https://www.googleapis.com")
public interface GoogleOauth2InfoClient {
@GetMapping(value = "/oauth2/v2/userinfo")
GoogleUserInfo getUserInfo(@RequestHeader(value = HttpHeaders.AUTHORIZATION) String token);
}
다음 포스팅에서는 해당 기술을 사용하였을 때 전역, 부분적으로 header등을 컨트롤 하는 방법과 외부 api 호출한 후 애러핸들링 (외부 api 요청이 실패하면 500 서버 애러로 나옴) 을 다룰 예정이다.
'Spring' 카테고리의 다른 글
@FeignClient 요청 및 에러 핸들링 (0) | 2024.05.22 |
---|---|
Spring 외부설정 2 (Profile 사용 예) (0) | 2024.05.06 |
Spring boot 커스텀 메트릭 (프로메테우스/그라파나) (0) | 2024.05.06 |
배포 서버 ClassNotFoundException 트러블 슈팅 (0) | 2024.05.02 |
커스텀 익셉션 적용 (0) | 2024.04.28 |