P3] Ch 07.Server to Server 간 연결

uuuu.jini·2022년 1월 16일
0
post-thumbnail

목차

  1. Server to Server 통신 방법
  2. Rest Template 사용
  3. Naver 지역 검색 API 연동

1. Server to Server 통신 방법

클라이언트로서의 서버와 서버로서의 서버간의 통신 방법을 사용해 볼 것이다. 주로 RestTemplate,WebClient,Apache Client를 이용하며 RestTemplate을 중점적으로 다뤄볼것이다. (스프링에서 주로 사용한다고 하셨음) 그래서 서버를 총 두개를 띄우고 통신할 것 이다.

서버의 포트번호 바꾸는 방법: source 의 application.properties 에서 server.port = 8080식으로 지정한다.

@Autowired : 해당 변수 및 메서드에 스프링이 관리하는 빈을 자동으로 매핑해준다.

서버와 서버간의 통신시에는 한쪽이 client역할로서 요청을 다른 서버로 보내고 해당 서버가 응답하는 형식으로 이루어진다. 즉 어떤 주소로 요청시 해당 서버에서 다른 서버로 다시 요청하여 응답을 받는다. 예로 http:localhost:8080/api/client로 요청시 다른 서버로 요청하기 위한 예제 코드를 밑에 설명하겠다.

@RestController
@RequestMapping("/api/client")
public class ApiController {


    private final RestTemplateService restTemplateService;

    public ApiController(RestTemplateService restTemplateService) { 
        this.restTemplateService = restTemplateService;
    }

    @GetMapping("")
    public UserResponse getHello(){
        return restTemplateService.hello();
    }

}

RestTemplateService라는 객체를 따로 두고 의존성 주입을 통하여 해당 객체를 생성하였으며, getMapping으로 해당 주소를 get요청시 restTemplateService의 hello메서드를 호출하게끔 작성하였다.

hello메서드에서는 다른 서버로 요청하는 방법에 대해 작성해보았다. 먼저 요청을 하기 위해 url주소를 생성하는 방법을 배웠다.

        URI uri = UriComponentsBuilder
                .fromUriString("http://localhost:9090") 
                .path("/api/server/hello")
                .queryParam("name","hey")
                .queryParam("age",99)
                .encode()
                .build()
                .toUri();

UriComponentBuilder를 사용하여 uri를 생성하였다. 만들때 주소 뿐만 아니라 쿼리 파라미터와 인코딩도 가능하며 여러가지 다양한 방법이 존재한다고 하셨다. 이 예제에서는 http://localhost:9090/api/server/hello로 요청을 하기 위한 주소를 생성한 것이다.

RestTemplate

주소로 서버요청을 하기 위해서는 RestTemplate객체를 사용한다. 이 객체에는 다양한 메서드가 존재하며 하나씩 다뤄볼 예정이다. 해당 객체는 모든 http통신방법을 지원하며, 해당 객체에서 메서드를 호출하는 지점에서 서버로 요청을 한다.

서버 역할을 하는 서버에서는 우리가 이때까지 배웟던 대로 수행하면 된다. 단지 클라이언트가 서버로 변경된거 뿐 변한것이 없기 때문이다.

Get 요청

1. GetForObject로 String 응답

RestTemplate restTemplate = new RestTemplate();
String result = restTemplate.getForObject(uri,String.class);
return result;

getForObject는 해당 객체를 원하는 타입으로 지정하여 응답 받을 수 있다.

2. GetForEntity로 String 응답

RestTemplate restTemplate = new RestTemplate();
ResponseEntity<String> result = restTemplate.getForEntity(uri,String.class);
return result.getBody();

getForEntity 는 responseEntity타입으로 응답을 받으며 이 객체는 여러가지 다양한 정보를 포함하고 있다. 예로, http Status나 body등이 있다.

3. Json 응답

        RestTemplate restTemplate = new RestTemplate();
        ResponseEntity<UserResponse> result = restTemplate.getForEntity(uri,UserResponse.class);
        
        System.out.println(result.getStatusCode());
        System.out.println(result.getBody());

        return result.getBody();

getforObject일경우 ResponseEntity타입이 아닌 해당 객체 타입으로 받으면 된다.responseEntity 로 받는 것 추천한다.

Post 요청

post요청도 동일한 형식으로 진행된다. 다만, uri생성시 path variable을 추가하는 방법과 요청할때에 request body를 포함해서 요청하는 방법을 배워보았다.

URI 생성은 위와 동일하다. 여기에 path variable을 위해 {}안에 변수를 작성하고 expand를 추가하여 인자로 지정할 값을 순서대로 작성하면 된다.

        URI uri = UriComponentsBuilder
                .fromUriString("http://localhost:9090")
                .path("/api/server/user/{userId}/name/{userName}")
                .encode()
                .build()
                .expand(100,"yoojin") 
                .toUri();

1. getForObject with request body

request body를 함께 요청시에 전송하기 위해서 object를 생성하고 RestTemplate의 메서드의 인자로 전송하기만 하면 간단하게 body를 함께 전송할수 있다.

        UserRequest userRequest = new UserRequest();
        userRequest.setAge(25);
        userRequest.setName("yoojin");

        RestTemplate restTemplate = new RestTemplate();
        
        ResponseEntity<UserResponse> response = restTemplate
        	.postForEntity(uri,userRequest,UserResponse.class);
        
        System.out.println(response.getStatusCode()); 
        System.out.println(response.getHeaders());
        System.out.println(response.getBody());

        return response.getBody();

postForEntity메서드의 인자로 uri와 request body로서의 object, response 타입을 지정해준다.

2. exchange with header information

header의 정보를 포함하여 요청을 하기 위해서는 requestEntity객체를 생성하여 해당 객체의 정보로 method방법, content-type,header정보, body내용 등을 포함하여 요청해야 한다. 요청시에는 RestTemplate객체의 exchange메소드의 인자로 해당 reqeustEntity 객체와 response응답 객체 타입을 지정해준다.

        RequestEntity<UserRequest> requestEntity  = RequestEntity
                .post(uri)
                .contentType(MediaType.APPLICATION_JSON)
                .header("x-authorization","abcd")
                .header("custom-header","ffff")
                .body(userRequest);

        RestTemplate restTemplate = new RestTemplate();
        
        ResponseEntity<UserResponse> response = restTemplate
        	.exchange(requestEntity,UserResponse.class);

이때, RequestEntity의 제네릭타입은 body에 실어 보낼 객체의 타입으로 지정하며, get방식으로 request body가 비어있을 경우에는 void로 지정한다.

서버에서 요청된 header의 정보를 가져오기 위해서는 @RequestHeader 어노테이션을 사용하여 변수에 할당 해 주어야 한다.

Json 형태의 재사용

json형태가

"header": {
	"status-code": ""
    },
"body":{
	"..":"",
    "..":""
    }
 }

이러한 형태로 header와 body는 고정되어 있고 body안의 값이 변경되는 등의 상황이 발생하면 재사용하기 위하여 제네릭 타입을 이용하여 response body를 생성하여 요청하는 방식을 사용한다.

주의할 점으로 제네릭 타입에는 .class를 붙일 수 없으므로 parameterizeTypeReference객체를 사용하고 , 요청할때의 response body객체의 변수명과 응답하는 서버측에서 해당 객체를 받기위한 객체의 변수명을 일치 시켜주어야한다. (이거 안되서 null값 넘어와서 고생함;)


Naver 지역 검색 API 연동

Naver의 오픈 api인 지역 검색 api를 사용하는 방법에 대해 알아보았다. naver의 Naver Developer 홈페이지에서 여러 다양한 api의 사용법에 대해 알 수 있다. 해당 api는 header로 Client ID 와 Client Secret값을 같이 전송해주면 활용이 가능하다. 자세한 내용은 링크 들어가 보면 나와있다.

Uri는 기존에 만들던 방식과 동일하게 만들었다. url과 path를 작성하고 queryParam으로 필요한 파라미터들을 지정해주고 encode와 build,toUri를 통해 생성하였다. 검색 api에서 검색할 문자를 query라는 이름의 쿼리 파라미터로 전송하는데 이때 utf-8로 인코딩하여 전송하여야한다. 그래서 encode의 인자로 charset.forName("UTF-8")등의 설정을 해주었다. 밑의 예시를 작성하였다.

        URI uri = UriComponentsBuilder
                .fromUriString("https://openapi.naver.com")
                .path("/v1/search/local.json")
                .queryParam("query", "갈비집")
                .queryParam("display", 10)
                .queryParam("start", 1)
                .queryParam("sort", "random")
                .encode(Charset.forName("UTF-8"))
                .build()
                .toUri();

이러면 uri는 완성된다. 여기서 헤더로 Id 와 Secret을 추가하여 요청하여야 한다. 그래서 RequestEntity 객체로 담아서 전송하고자 한다.

RequestEntity<Void> requestEntity = RequestEntity
	.get(uri)
	.header("X-Naver-Client-Id","")
        .header("X-Naver-Client-Secret","")
        .build();

header의 두번째 인자로 실제 자신의 id와 secret을 추가하여 준다.

이제 실제 요청을 위한 restTemplate객체의 exchange메소드를 사용하면 된다.

RestTemplate restTemplate = new RestTemplate();

ResponseEntity<String> response = restTemplate
		.exchange(requestEntity,String.class);

exchange메소드는 요청할 requestEntity객체와 응답받을 객체의 type을 인자로 받는다. (post와 헷갈려서 곤란했음 기억하기!)

profile
멋쟁이 토마토

0개의 댓글