[컴][웹] Spring 에서 REST API 호출하기

스프링에서 rest api call 하기 / spring 에서 rest call / spring 에서 http request

RestTemplate

Spring framework 에서 Rest API 호출을 위해 RestTemplate 이라는 것을 제공한다. ref. 2, ref. 3 에서 간단한 예제를 확인할 수 있다.

postForObject

Server 에서 RESTful API server 에 request 를 POST 방식으로 form 의 data 는 json 형식으로 보낼 때 방법. ElasticSearch 등을 사용할 때 활용할 수 있다. 혹시나 해서 적어놓는데, ElasticSearch 는 Java API 를 따로 제공한다.(참고)

@Override
public JsonResult retrieve() {

    String JSONInput = ("{\n" +
            "    \"aggs\": {\n" +
            "       \"aggs_stats\" : {\n" +
            "           \"date_histogram\":{\n" +
            "             \"field\" : \"event_timestamp\",\n" +
            "             \"interval\" : \"hour\"\n" +
            "           }\n" +
            "       }\n" +
            "    }\n" +
            "} ");

    HttpHeaders headers = new HttpHeaders();
    headers.setContentType(MediaType.APPLICATION_JSON);
    HttpEntity param= new HttpEntity(JSONInput, headers);


    RestTemplate restTemplate = new RestTemplate();
    String result = restTemplate.postForObject(url, param, String.class);

    return new ElasticSearchResult(result);

}

setMessageConverters

ref. 5ref. 6 을 통해서 MessageConverters 를 설정해서 postForObject 를 이용하는 방법을 알아볼 수 있다.

// RestTemplate 에 MessageConverter 세팅
List<HttpMessageConverter<?>> converters = new ArrayList<HttpMessageConverter<?>>();
converters.add(new FormHttpMessageConverter());
converters.add(new StringHttpMessageConverter());

RestTemplate restTemplate = new RestTemplate();
restTemplate.setMessageConverters(converters);

// parameter 세팅
MultiValueMap<String, String> map = new LinkedMultiValueMap<String, String>();
map.add("name", "xx");
map.add("password", "xx");

// post
String result = rest.postForObject("http://localhost:8080/soa-server/user/", map, String.class);
System.out.println(result);

getForObject 의 한계

Accept 를 따로 정해주지 않는 경우에 RestTemplate#getForObject 에서는 기본적으로 아래 header 를 이용한다. Accept : application/json, application/*+json

그래서 getForObject 를 이용해서 만약에 다른 Accept 를 사용하고 싶다면, 다른 함수를 이용해야 한다.(execute, exchange)

getForObject 에서 param 을 주는 방법

ref. 4 를 참고하자. 대략 아래와 같은 방식을 이용한다.

UriComponentsBuilder urlWithoutParam 
    = UriComponentsBuilder.fromUriString("http://dd.net")
                .path("/path1/ddd");
        
for(Map.Entry<String, Object> e: param.entrySet()){
    urlWithoutParam = urlWithoutParam.queryParam(e.getKey(), e.getValue());
}
URI reqUrl = urlWithoutParam.build().toUri();


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

RestTemplate#execute

좀 더 자유로운 Http request 를 위해서 execute 를 사용하게 되었다. 그리고 이 RestTemplate 의 doExecute 에서 Extractor 를 사용하기 때문에 이 녀석만 제대로 맞춰 주면 된다.

protected <T> T doExecute(URI url, HttpMethod method, 
                        RequestCallback requestCallback,
                        ResponseExtractor<T> responseExtractor) 
                        throws RestClientException {
    try {
        ClientHttpRequest request = createRequest(url, method);
        if (requestCallback != null) {
            requestCallback.doWithRequest(request);
        }
        response = request.execute();
        if (!getErrorHandler().hasError(response)) {
            logResponseStatus(method, url, response);
        }
        else {
            handleResponseError(method, url, response);
        }
        if (responseExtractor != null) {
            return responseExtractor.extractData(response);
        }

Example

// ApiCallResponseExtractor.java
public class ApiCallResponseExtractor extends HttpMessageConverterExtractor<String> {

    public ApiCallResponseExtractor (Class<String> responseType,
                                List<HttpMessageConverter<?>> messageConverters) {
        super(responseType, messageConverters);
    }

    @Override
    public String extractData(ClientHttpResponse response) throws IOException {

        String result;

        if (response.getStatusCode() == HttpStatus.OK) {
            Scanner scanner = new java.util.Scanner(response.getBody()).useDelimiter("[\\(\\)]");
            scanner.next(); // callback name,
            String json = scanner.next();
            result = json;

        } else {
            result = null;
        }

        return result;
    }
}
// MyController.java
final String url = "http://10.10.2.100:8080/portal/customer/getCustomerList?" +
                JsonKey.CALLBACK + "={" + JsonKey.CALLBACK + "}" + "&" +
                JsonKey.USER_ID + "={" + JsonKey.USER_ID + "}";
Map<String, String> vars = new HashMap<String, String>();
vars.put(JsonKey.CALLBACK, JsonKey.API_CALLBACK_NAME);
vars.put(JsonKey.USER_ID, "test_id");

RestTemplate restTemplate = new RestTemplate();
ResponseExtractor<String> responseExtractor =
        new ApiCallResponseExtractor(String.class, restTemplate.getMessageConverters());

String response = restTemplate.execute(url, HttpMethod.GET, null, responseExtractor, vars);

Header field Accept

참고로 execute 를 사용하면 기본 Accept 는 아래를 사용하게 된다.

Accept : text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2

RestTemplate 을 이용해서 json request

ref. 7에 잘 나와 있다.

slack webhook message 보내기

ref.8 참고

curl -X POST -H 'Content-type: application/json' --data '{"text":"Hello, World!"}' https://hooks.slack.com/services/xxxxx/xxxxx/xxxxx
package myapp.slack

import com.fasterxml.jackson.databind.ObjectMapper
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.web.client.RestTemplateBuilder
import org.springframework.http.HttpEntity
import org.springframework.http.HttpHeaders
import org.springframework.http.HttpMethod
import org.springframework.http.MediaType
import org.springframework.stereotype.Component
import org.springframework.web.client.RestTemplate


@Component
public class SlackClient {

    private final RestTemplate restTemplate;

    @Autowired
    public SlackClient(RestTemplateBuilder restTemplateBuilder) {
        this.restTemplate = restTemplateBuilder.build();
    }

    public String sendMessage(String text) {
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);

        //  JsonObject obj = new JsonObject();
        //  obj.addProperty("text", text);

        // using jackson, create a jsonObject
        ObjectMapper mapper = ObjectMapper()
        ObjectNode data = mapper.createObjectNode()
        data.put("text", text)

        HttpEntity<String> request = new HttpEntity<>(data.toString(), headers);
        final ResponseEntity<String> entity = restTemplate.exchange("https://hooks.slack.com/services/xxxxx/xxxxx/xxxxx", HttpMethod.POST, request, String.class);
        if(entity.getStatusCode().is2xxSuccessful()) {
            return entity.getBody();
        }
        return null;
    }
}

Reference

  1. RestTemplate (Spring Framework 4.1.3.RELEASE API)
  2. http://spring.io/guides/gs/consuming-rest/#initial
  3. http://spring.io/blog/2009/03/27/rest-in-spring-3-resttemplate
  4. android - How to send a getForObject request with parameters Spring MVC - Stack Overflow
  5. java - Spring RestTemplate postForObject with Header: webservice can't find my header parameters - Stack Overflow
  6. Sending POST parameters with RestTemplate requests - Spring Forum
  7. Rest Template Json Request | Spring Tutorials
  8. Slack Webhook Message from Spring Boot

댓글 없음:

댓글 쓰기