back end/java

[Spring boot] Restful API 쉽게 호출하는 방법 by using RestTemplate

노루아부지 2022. 10. 11. 00:35
반응형

RestTemplate란?

Spring 3.0부터 지원하는 라이브러리로 간편하게 Rest 방식 API를 호출할 수 있습니다.

Restful API 서비스를 요청 후 응답받을 수 있도록 설계되었습니다.

Spring 5부터는 WebFlux 스택과 함께 WebClient라는 새로운 HTTP 클라이언트를 도입하여 기존의 동기식 API를 제공할 뿐만 아니라 효율적인 비차단 및 비동기 접근 방식을 지원하여 RestTemplate는 deprecated 되었습니다.

따라서 WebClient 사용을 지향합니다.

 

 

RestTemplate Method

Method Operation Action
delete() DELETE 지정된 URL의 리소스에 대해 HTTP DELETE 요청을 수행합니다. 
getForEntity() GET HTTP GET 요청을 보내 응답 본문에서 매핑된 개체를 포함하는 ResponseEntity를 반환합니다.
getForObject() GET HTTP GET 요청을 보내 응답 본문에서 매핑된 개체를 반환합니다.
postForEntity() POST 데이터를 URL에 POST하고 응답 본문에서 매핑된 개체를 포함하는 ResponseEntity를 반환합니다.
postForLocation() POST 데이터를 URL에 POST하여 새로 생성된 리소스의 URL을 반환합니다.
postForObject() POST 데이터를 URL에 POST하고 응답 본문에서 매핑된 개체를 반환합니다.
put() PUT 리소스 데이터를 지정된 URL에 PUT합니다.
patchForObject() PATCH HTTP PATCH 요청을 보내 응답 본문에서 매핑된 결과 개체를 반환합니다.
headForHeaders() HEAD HTTP HEAD 요청을 보내 지정된 리소스 URL에 대한 HTTP 헤더를 반환합니다.
exchange() ANY URL에 대해 지정된 HTTP 메서드를 실행하여 개체를 포함하는 ResponseEntity를 반환합니다.
execute() ANY URL에 대해 지정된 HTTP 메서드를 실행하여 응답 본문에서 매핑된 개체를 반환합니다.
optionsForAllow() OPTIONS HTTP OPTIONS 요청을 전홍하여 지정된 URL에 대한 Allow 헤더를 반환합니다.

 

메서드를 잘 보시면 postForEntity(), postForObject()와 같이 메서드 이름이 Entity와 Object로 구분되어 있는 것이 있는데 차이점은 Reponse입니다.

 

forEntity는 아래와 같이 ResponseEntity를 반환합니다.

ResponseEntity<CommonResponse> response = 
  restTemplate.postForEntity(USER_URL, request, CommonResponse.class);

 

forObject는 ResponseEntity가 아닌 객체를 직접 반환합니다.

CommonResponse response = 
  restTemplate.postForObject(USER_URL, request, CommonResponse.class);

 

 

메서드의 자세한 내용은 여기에서 확인할 수 있습니다.

 

 

 

 

RestTemplate 사용 방법

  1. RestTemplate 객체 생성
  2. HttpHeader setting
  3. body setting
  4. HttpEntity 생성
  5. API 호출
  6. Response parsing

 

1) RestTemplate 객체 생성

RestTemplate restTemplate = new RestTemplate();

 

2) HttpHeader를 setting

HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.setContentType(MediaType.APPLICATION_JSON);

 

3) Body Setting

parameter를 setting합니다.

MultiValueMap<String, String> body = new LinkedMultiValueMap<>();
body.add("userName", "hong");
body.add("age", 25);

 

4) HttpEntity 생성

HttpEntity<?> requestMessage = new HttpEntity<>(body, httpHeaders);

 

5) API 호출

HttpEntity<String> response = restTemplate.postForEntity(url, requestMessage, String.class);

 

6) Response parsing

Object로 데이터를 받았다면 parsing 단계가 필요 없지만 String으로 받았다면 parsing 단계가 필요합니다.

ObjectMapper objectMapper = new ObjectMapper();
objectMapper.configure(DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT, true);
UserDto dto = objectMapper.readValue(response.getBody(), UserDto.class);

 

 

RestTemplate example

예제를 실행하기 위해 다음과 같은 코드를 미리 작성합니다.

또한 이 게시글에서는 일반적으로 사용하는 GET, POST, PUT, DELETE만 예제를 기록합니다.

package com.example.demo.domain;

import com.example.demo.UserParam;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;

import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;

@Getter
@Setter
@Entity
@AllArgsConstructor
@NoArgsConstructor
@Table(name = "t_user")
public class User {
  @Id
  private String userId;
  private String userName;
  private Integer age;

  public User(UserParam param) {
    this.userId = param.getUserId();
    this.userName = param.getUserName();
    this.age = param.getAge();
  }
}
package com.example.demo.domain;

import org.springframework.data.jpa.repository.JpaRepository;

public interface UserRepository extends JpaRepository<User, String> {
}
package com.example.demo;

import com.example.demo.domain.User;
import com.example.demo.domain.UserRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.*;

import javax.validation.Valid;
import java.util.List;

@RequestMapping("/user")
@RestController
@RequiredArgsConstructor
public class UserController {
  private final UserRepository userRepository;

  /**
   * ContentType에 APPLICATION_FORM_URLENCODED를 사용하지 않는 경우
   * RequestBody Annotation을 사용해야 함.
   * @param param
   * @return
   */
  @PostMapping
  public CommonResponse add(@Valid @RequestBody UserParam param) {
    User user = new User(param);
    userRepository.save(user);

    return new CommonResponse();
  }

  @PostMapping("/form")
  public CommonResponse addForm(@Valid UserParam param) {
    User user = new User(param);
    userRepository.save(user);

    return new CommonResponse();
  }

  @GetMapping("/{id}")
  public UserDto get(@PathVariable String id) throws Exception {
    User user = userRepository.findById(id).orElseThrow(() -> new Exception("사용자 정보가 없습니다."));

    return new UserDto(user);
  }

  @GetMapping
  public List<User> list() {
    return userRepository.findAll();
  }

  @PutMapping("/{id}")
  public void modify(@PathVariable String id, @RequestBody UserDto param) throws Exception {
    User user = userRepository.findById(id).orElseThrow(() -> new Exception("사용자 정보가 없습니다."));

    user.setUserName(param.getUserName());
    user.setAge(param.getAge());

    userRepository.save(user);
  }

  @DeleteMapping("/{id}")
  public void del(@PathVariable String id) {
    userRepository.deleteById(id);
  }
}

 

 

1) postForEntity

@RequestMapping("/user/add/entity")
public CommonResponse addUserEntity() {
  RestTemplate restTemplate = new RestTemplate();

  // 헤더 설정
  HttpHeaders headers = new HttpHeaders();
  // MultiValueMap를 사용할 경우 default값이 APPLICATION_FORM_URLENCODED
  //headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);

  // 파라미터 세팅
  MultiValueMap<String, String> map = new LinkedMultiValueMap<>();
  map.add("userId", "lim");
  map.add("userName", "임꺽정");
  map.add("age", "21");

  HttpEntity<MultiValueMap<String, String>> request = new HttpEntity<>(map, headers);

  ResponseEntity<CommonResponse> response = 
    restTemplate.postForEntity(USER_URL + "/form", request, CommonResponse.class);

  return response.getBody();
}

API 테스트를 위해 제일 먼저 해야 할 것은 ADD입니다. ADD에 해당하는 HTTP method는 POST입니다.

POST로 파라미터를 보내기 위한 방법은 두 가지가 있습니다.

 

  • MultiValueMap
    • MultiValueMap을 사용할 경우 ContentType의 default 값은 application/x-www-form-urlencoded 입니다.
  • Class
    • Class를 사용할 경우 ContentType의 default 값은 application/json입니다.

 

이 글에서는 예제의 다양성을 위해 postForEntity에는 MultiValueMap를 사용하고 postForObject에는 Class를 사용했지만 파라미터를 보내는 방식과 postForEntity/postForObject는 관계없습니다.

 

 

2) postForObject

@RequestMapping("/user/add")
public CommonResponse addUserObject() {
  RestTemplate restTemplate = new RestTemplate();

  // 헤더 설정
  HttpHeaders headers = new HttpHeaders();

  // 파라미터 세팅
  UserDto user = new UserDto();
  user.setUserId("hong");
  user.setUserName("홍길동");
  user.setAge(26);

  HttpEntity<UserDto> request = new HttpEntity<>(user, headers);

  return restTemplate.postForObject(USER_URL, request, CommonResponse.class);
}

 

 

3) getForObject

@RequestMapping("/user/list")
public List<User> list () {
  RestTemplate restTemplate = new RestTemplate();
  User[] users = restTemplate.getForObject(USER_URL, User[].class);
  if(users == null) {
    return new ArrayList<>();
  }

  return Arrays.asList(users);
}

추가를 했으면 목록에서 확인해야겠죠. 목록 조회를 getForObject로 만들어 봤습니다.

목록을 받기 위해서 responseType을 배열로 선언했습니다. User[].class 대신 List.class를 사용하면 ClassCastException이 발생합니다.

 

 

4) getForEntity

@RequestMapping("/user/info")
public UserDto info () {
  RestTemplate restTemplate = new RestTemplate();
  UserDto user = restTemplate.getForObject(USER_URL + "/{id}", UserDto.class, "hong");
  if(user == null) {
    return new UserDto();
  }

  return user;
}

데이터를 수정하기 전에 수정 화면을 호출하기 위한 사용자 정보 조회입니다.

Restful API에서는 보통 pk를 URL/PK 와 같이 사용하는데, 위 코드에서 USER_URL/hong으로 직접 URL을 입력해도 되지만, 아래 첨부된 이미지와 같이 3번째 인자부터는 uriVariables이기 때문에 "hong"을 3번째 인자에 넣었습니다.

 

만약 인자를 2개, 3개 넣어야 하는 경우에는 아래와 같이 하면 됩니다.

restTemplate.getForObject(
    USER_URL + "/{id}/{id2}/{id3}", 
    UserDto.class, 
    "hong", 
    "id2", 
    "id3");

 

5) put

@RequestMapping("/user/modify")
public boolean modify() {
  RestTemplate restTemplate = new RestTemplate();

  // 헤더 설정
  HttpHeaders headers = new HttpHeaders();

  // 수정할 정보를 setting
  UserDto user = new UserDto();
  user.setUserName("홍길동2");
  user.setAge(30);

  HttpEntity<UserDto> request = new HttpEntity<>(user, headers);

  restTemplate.put(USER_URL + "/{id}", request, "hong");

  return true;
}

 

 

6) delete

@RequestMapping("/user/del")
public boolean del() {
  RestTemplate restTemplate = new RestTemplate();
  restTemplate.delete(USER_URL + "/{id}", "hong");
  return true;
}

 

 

 

 

 

 

 

 

 

 

참고

https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/web/client/RestTemplate.html

 

RestTemplate (Spring Framework 5.3.23 API)

Synchronous client to perform HTTP requests, exposing a simple, template method API over underlying HTTP client libraries such as the JDK HttpURLConnection, Apache HttpComponents, and others. The RestTemplate offers templates for common scenarios by HTTP m

docs.spring.io

https://www.geeksforgeeks.org/spring-resttemplate/

 

Spring - RestTemplate - GeeksforGeeks

A Computer Science portal for geeks. It contains well written, well thought and well explained computer science and programming articles, quizzes and practice/competitive programming/company interview Questions.

www.geeksforgeeks.org

https://juntcom.tistory.com/141

 

[spring] 스프링에서 사용하는 RestTemplate - http 라이브러리

RestTemplate이란 스프링에서 제공하는 http 통신에 유용하게 쓸 수 있는 템플릿 Spring 3부터 지원 되었고 REST API 호출이후 응답을 받을 때까지 기다리는 동기방식이다 AsyncRestTemplate Spring 4에 추가된

juntcom.tistory.com

https://blog.naver.com/hj_kim97/222295259904

 

[Spring]스프링 RestTemplate

스프링 RestTemplate - RestTemplate란? - RestTemplate의 특징 - RestTemplate 동작 원리 - AP...

blog.naver.com

https://luvstudy.tistory.com/52

 

RestTemplate list 반환하기

요청을 반환받는 클래스가 다음과 같다고 가정한다. @Data public class ResultClass { private long idx; private String name; } List로 리턴 받는 방법 - 문제가 있음. 비추천 List list = restTemplate.getFor..

luvstudy.tistory.com

 

728x90
반응형
loading