WebClient를 이용한 API 호출과 그 리턴 값 다루기(JSON)
반응형

API를 이용한 서비스를 만들어야 할 때가 있다.

 

보통 API를 제공하는 측에서 API를 어떻게 사용할 수 있는지 문서를 제공하거나 

 

그 가이드를 제공한다.

 

www.API주소.com?파라미터1=값1&파라미터2=값2 

 

www.APIAdress.com?parameter=value&key=value  

 

 

이런 식이다

 

 

처음에는 이런 주소형식의 API를 사용하려면

 

자바스크립트 location.href 를 이용해서 주소를 넣고 값을 다루는 줄 알았다.

 

혹은 AJAX를 이용해서 주소를 보내고 리턴값을 받는?

 

href 같은 주소 이동기술?은 오직 프론트에서만 다루는 줄 알았다.

 

국비교육을 들었을때도 프론트에서 처리하는 방법 밖에 안 배웠었던 이유도 있다.

 

 

 

그런데 이런 API를 다루는 로직을 생각하다보니 API의 value를 동적으로 다루거나

 

한 서비스 내에서 API 를 바로 호출해서 데이터를 다뤄야하는 상황이 생기는데

 

매번 서비스를 따로 만들어서 백단에서 프론트로 값을 보내서 매번 매핑하고 다시 백으로 보내서 받아야하는건가...? 라고 의문점을 갖게 되었고

 

백단에서만 다루는 방법이 있는지 찾게 되었다.

 

역시나!! 방법은 있는 것이었다...

 

스프링에서는 WebClient라는 기술을 이용해서 API를 다루는 기술이 있었던 것이다

 

 

그런데 검색을 해도 호출하는 방법만 다루고 호출하고나서 돌아온 리턴값을 다루는 내용이 없었다

 

아무리 생각해도 리턴값의 키값을 DTO로 만들어서 받으면 된다고 생각했는데 

 

이 기술이 어떻게 로직이 흘러가는지 당최 문서를 봐도 모르겠고 예제를 봐도 모르겠는 상황이 와버렸다.

 

WebClient 문서를 봐도 단순 보내고 받는 식으로 나오는 게 아닌 다양한 형태의 방법이 있었기 때문에

 

결국 혼자 공부할 수 밖에 없었다...

 

사실 공부한다 해도 무조건 에러는 나를 기다리고 있기 때문에 그냥 부딪히는게 최고의 공부다

 

 

WebClient 관련 유튜브.. 블로그... 거기서 나오는 예제 등을 보며 공부했다.

 

다 똑같은 얘기들 밖에 없었다.

 

원래 쓰이던 RestTemplate는 WebClient에 밀려 폐기된다느니...

 

Mono...Flux.... 

 

API 호출을 위해 여러 알아야 할 것들이 많았다

 

설명 자체도 복잡하기도 하고 전체 예제 코드를 올린 사람이 많이 없어서 더 애 먹었던 것 같다.

 

내가 활용하려는 단순 보내고 리턴값 받는 식으로 사용하기 위해 너무 많은 시간이 들었다 ㅠ

 

https://jsonplaceholder.typicode.com/ 

 

JSONPlaceholder - Free Fake REST API

{JSON} Placeholder Free fake API for testing and prototyping. Powered by JSON Server + LowDB. Tested with XV. As of Oct 2021, serving ~1.7 billion requests each month.

jsonplaceholder.typicode.com

 

테스트 데이터 JSON을 제공해주는 사이트를 이용하면서 연구를 하다가 어느 정도 틀이 잡혔는데

 

WebClient에 달려있는 기술들이 워낙 많아서 결국엔 더 공부를 해야한다..

 

 

 

WebClient 활용 예시로 회원가입 시에 본인인증을 한다고 가정해보자

 

아래는 가상의 본인인증 API 문서

 

 

 

기본 URI
www.회원인증.co

요청 파라미터값

파라미터값 설명 형식
userId 아이디 영문+숫자 포함
password 비밀번호 암호화 없이 보내야함
phone 전화번호 - 없이 숫자만

 

 

리턴 값

값 이름 설명 형식
result API 요청 결과 성공시 : "SUCCESS"   실패시 : "FAIL"

 

 

 

 

 

이 문서를 보고 아래의 URI를 요청한다고 가정...

 

www.회원인증.co?userId=id&password=1234&phone=01012345678  

 

 

 

스프링의 서비스단에서 실행한다고 가정한다.

 

 

import org.springframework.web.reactive.function.client.WebClient;
import org.springframework.beans.factory.annotation.Autowired;


@Service
public class registService {
	
    @Autowired
    WebClient.Builder webClient;

	@Resource
	HomeMapper homeMapper;

	//회원가입
	@Transactional
	public int registUser(User user) {			//유저의 정보가 담겨있는 DTO
		
		
        
        //기본Url 설정
        WebClient webClients = webClient.baseUrl("www.회원인증.co").build();
		
        
        	//WebClientReturnDTO 라는 리턴 값을 받을 DTO를 만든다            
			Mono<WebClientReturnDTO> webClientReturn = webClient.get().	//GET 방식으로 요청
            
            //기본Url 뒤에 파라미터 값 붙여주기
            uri(uri -> uri.path("")		//여기 이후부터 ?가 붙음
					.queryParam("userId", user.getUserId)
                    .queryParam("password", user.getPassword)
                    .queryParam("phone", user.getPhone)
					.build())
					.retrieve().bodyToMono(WebClientReturnDTO.class);

			//요청이 성공했을 때
			webClientReturn.doOnSuccess(rt ->{
					//어떤 값이 왔는지 리턴 값 보기
					System.out.println(rt);
                    
                    //요청이 성공하면 WebClientReturnDTO에 담겨 콘솔창에 나온다.
                    //예시 : result="SUCCESS"
                    
                    
                    //요청 성공후 값을 다룰 로직
                    if(rt.getResult.equals("SUCCESS")){
                    	user.setKyc(1)	//인증 성공 시 1 저장
                   }else{
                   	//본인인증 실패 시 로직
                   }
                    
                    
                    
			}).subscribe();	//최종 요청.. subscribe가 없으면 호출이 되지 않음.
            
            int result = homeMapper.registUser(user);	//회원정보 DB등록 매퍼
        
		return result;
	}


}

 

 

 

그런데?! 상황에 따라서 요청은 성공하는데 contentType 에러가 나는 경우가 있다.

 

JSON 형태로 값이 넘어오는 게 html 창에서는 확인이 되는데 백단에서 결과를 받을 때 

 

contentType이 안맞는 경우가 있다.

 

검색을 해도 헤더를 지정하라고 하는데 헤더를 지정해도 안되고...

 

contentType 설정 메소드로 설정해도 안되고...

 

 

 

 

그럴땐 일단 결과를 String 클래스로 받아보자

 

 

import org.springframework.web.reactive.function.client.WebClient;
import org.springframework.beans.factory.annotation.Autowired;


@Service
public class registService {
	
    @Autowired
    WebClient.Builder webClient;

	@Resource
	HomeMapper homeMapper;

	//회원가입
	@Transactional
	public int registUser(User user) {			//유저의 정보가 담겨있는 DTO
		
		
        
        //기본Url 설정
        WebClient webClients = webClient.baseUrl("www.회원인증.co").build();
		
        
        	//다양한 에러로 도저히 결과가 돌아오지 않을 때는 String으로 받아보자         
			Mono<String> webClientReturn = webClient.get().
            
            //기본Url 뒤에 파라미터 값 붙여주기
            uri(uri -> uri.path("")		//여기 이후부터 ?가 붙음
					.queryParam("userId", user.getUserId)
                    .queryParam("password", user.getPassword)
                    .queryParam("phone", user.getPhone)
					.build())
					.retrieve().bodyToMono(String.class);

			//요청이 성공했을 때
			webClientReturn.doOnSuccess(rt ->{
					//어떤 값이 왔는지 리턴 값 보기
					System.out.println(rt);
                    
                    //요청이 성공하면 JSON 형식이지만 String으로 받았기에 String으로 들어올 것이다.
                    //예시 : [result : "SUCCESS"]...    혹은   {result : "FAIL"}...
                    
                    
                   
                    
                    
                    
			}).subscribe();	
            
            int result = homeMapper.registUser(user);	//회원정보 DB등록 매퍼
        
		return result;
	}


}

 

 

처음 WebClient를 사용할 때 사용방법 블로그 보면서 contentType을 설정하고 온갖 방법을 다 동원했는데 클라이언트 측의 보내는 방식이 달랐던 건지 contentType 에러를 겪어서 해결에 시간을 너무 쏟은 기억이 있다...

 

 

 

 

 

어떤 API 요청을 하느냐에 따라 다르겠지만

 

String으로 받고 나면 JSON 형식으로 구성이 된 결과를 받을 수 있을 것이다.

 

그런데 String은 그저 문자열이라서 키값으로 데이터를 꺼낼 수 없고 

 

그렇다고 문자열 자르기를 하자니 받아오는 value가 매번 다르다면 그 분기를 정할 수가 없다.

 

 

다행히도 JSON형식의 String을 JSON데이터로 다룰 수 있게끔 바꿔주는 라이브러리가 있으니 참고하자

 

String to JSON

 

 

(물론 이런 식으로 하면 코드가 너무 원시적이고 더러워질 수 있으니 최대한 깨끗한 코드를 쓸 수 있는 방향으로 진행하자..)

반응형