public class HttpUtil {
public static JSONObject getHTTP(String apiURL, Map<String, String> requestHeaders) throws IOException, ParseException {
URL url = new URL(apiURL);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("GET");
for (Map.Entry<String, String> rqheader : requestHeaders.entrySet()) {
connection.setRequestProperty(rqheader.getKey(), rqheader.getValue());
}
return getHTTPResponse(connection);
}
public static JSONObject postHTTP(String apiURL, String request) throws IOException, ParseException {
URL url = new URL(apiURL);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("POST");
connection.setDoOutput(true);
connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded;charset=utf-8");
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(connection.getOutputStream()));
bw.write(request);
bw.flush();
bw.close();
return getHTTPResponse(connection);
}
private static JSONObject getHTTPResponse(HttpURLConnection connection) throws IOException, ParseException {
InputStreamReader streamReader;
if (connection.getResponseCode() == HttpURLConnection.HTTP_OK) { // 정상 호출
streamReader = new InputStreamReader(connection.getInputStream());
} else { // 에러 발생
streamReader = new InputStreamReader(connection.getErrorStream());
}
BufferedReader lineReader = new BufferedReader(streamReader);
StringBuilder responseBody = new StringBuilder();
String line;
while ((line = lineReader.readLine()) != null) {
responseBody.append(line);
}
String body = responseBody.toString();
connection.disconnect();
return (JSONObject) new JSONParser().parse(body);
}
}
레시피 조회 시 네이버 검색과 유튜브 검색 기능이 필요하여 외부 API를 호출하고 있다.
또한, SNS 로그인을 위해 네이버/카카오/구글 회원정보 조회 API를 호출하고 있다.
이런 외부 API 호출을 위해서 HttpUtil 클래스를 작성하여 활용하고 있었다.
FeignClient 라이브러리를 활용하면 외부 API 호출 시 코드를 좀 더 쉽고 깔끔하게 작성할 수 있었다.
implementation 'org.springframework.cloud:spring-cloud-starter-openfeign:4.1.0'
@EnableFeignClients
@SpringBootApplication
public class AppApplication extends SpringBootServletInitializer {
...
}
@EnableFeignClients 어노테이션을 springboot application 실행 클래스에 추가@FeignClient(name = "google-client", url = "https://oauth2.googleapis.com")
public interface GoogleOAuthFeignClient {
@PostMapping("/token")
GoogleAccessTokenResponse getAccessToken(@RequestParam(name = "grant_type") String grantType,
@RequestParam(name = "client_id") String clientId,
@RequestParam(name = "client_secret") String clientSecret,
@RequestParam(name = "redirect_uri") String redirectUri,
@RequestParam(name = "code") String code);
@GetMapping("/tokeninfo")
GoogleAuthResponse getAuthInfo(@RequestParam(name = "id_token") String accessToken);
}
@FeignClient(name = "kakao-client", url = "https://kapi.kakao.com")
public interface KakaoFeignClient {
@GetMapping("/v2/user/me")
KakaoAuthResponse getAuthInfo(@RequestHeader("Authorization") String authorization);
}
@FeignClient(name = "kakao-oauth-client", url = "https://kauth.kakao.com/oauth")
public interface KakaoOAuthFeignClient {
@PostMapping(value = "/token", consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
KakaoAccessTokenResponse getAccessToken(@RequestParam(name = "grant_type") String grantType,
@RequestParam(name = "client_id") String clientId,
@RequestParam(name = "redirect_uri") String redirectUri,
@RequestParam(name = "code") String code);
}
@FeignClient(name = "naver-client", url = "https://openapi.naver.com")
public interface NaverFeignClient {
@GetMapping("/v1/search/blog")
NaverBlogSearchResponse searchNaverBlog(
@RequestHeader("X-Naver-Client-Id") String clientId,
@RequestHeader("X-Naver-Client-Secret") String clientSecret,
@RequestParam(value = "start") int start,
@RequestParam(value = "display") int display,
@RequestParam(value = "sort") String sort,
@RequestParam(value = "query") String query);
@GetMapping("/v1/nid/me")
NaverAuthResponse getAuthInfo(@RequestHeader("Authorization") String authorization);
}
@FeignClient(name = "naver-oauth-client", url = "https://nid.naver.com/oauth2.0")
public interface NaverOAuthFeignClient {
@GetMapping("/token")
NaverAccessTokenResponse getAccessToken(
@RequestParam(value = "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,
@RequestParam(value = "state") String state
);
}
@FeignClient(name = "이름", url = "외부 API 호출 URL") 설정하여 특정 URL 호출을 위한 FeignClient 적용@DataJpaTest
@ImportAutoConfiguration(classes = FeignAutoConfiguration.class)
@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
@TestPropertySource(locations = "classpath:application-test.yml")
class IngredientCustomRepositoryTest extends Specification {
...
}
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'org.springframework.cloud.netflix.feign.FeignContext' available
@ImportAutoConfiguration(classes = FeignAutoConfiguration.class) 을 추가하면 해결됨@EnableFeignClients 어노테이션을 적용하여 생기는 문제라는 것 같음