스프링 애플리케이션은 아래와 같은 방법을 통해 REST API를 사용할 수 있다.
- RestTemplate: 스프링 프레임워크에서 제공하는 간단하고 동기화된 REST 클라이언트
- Traverson: 스프링 HATEOAS에서 제공하는 하이퍼링크를 인식하는 동기화 REST 클라이언트
- WebClient: 반응형 비동기 REST 클라이언트
RestTemplate
- 클라이언트 입장에서 REST 리소스와 상호작용하려면, 클라이언트 인스턴스와 요청 객체를 생성하고, 해당 요청을 실행하고, 응답을 분석하여 관련 도메인 객체와 연관시켜 처리하면서, 도중에 발생할 수 있는 예외까지 처리해야 한다.
- 이러한 장황한 코드를 피하기 위해 스프링은 RestTemplate을 제공하며, RestTemplate은 REST 리소스를 사용하는 데 필요한 반복되고 귀찮은 작업을 처리해준다.
- RestTemplate은 REST 리소스와 상호작용하기 위해, 고유한 작업을 수행하는 12개의 메서드와 이 메서드들을 오버로딩한 29개의 메서드를 포함한 41개의 메서드를 제공한다.
delete(...) | 지정된 URL의 리소스에 HTTP DELETE 요청을 수행한다. |
exchange(...) | 지정된 HTTP 메서드를 URL에 대해 실행하며, 응답 바디와 연결되는 객체를 포함하는 ResponseEntity를 반환한다. |
execute(...) | 지정된 HTTP 메서드를 URL에 대해 실행하며, 응답 바디와 연결되는 객체를 반환한다. |
getForEntity(...) | HTTP GET 요청을 전송하며, 응답 바디와 연결되는 객체를 포함하는 ResponseEntity를 반환한다. |
getForObject(...) | HTTP GET 요청을 전송하며, 응답 바디와 연결되는 객체를 반환한다. |
headForHeaders(...) | HTTP HEAD 요청을 전송하며, 지정된 리소스 URL의 HTTP 헤더를 반환한다. |
optionsForAllow(...) | HTTP OPTIONS 요청을 전송하며, 지정된 URL의 Allow 헤더를 반환한다. |
patchForObject(...) | HTTP PATCH 요청을 전송하며, 응답 바디와 연결되는 객체를 반환한다. |
postForEntity(...) | URL에 데이터를 POST하며, 응답 바디와 연결되는 객체를 포함하는 ResponseEntity를 반환한다. |
postForLocation(...) | URL에 데이터를 POST하며, 새로 생성된 리소스의 URL을 반환한다. |
postForObject(...) | URL에 데이터를 POST하며, 응답 바디와 연결되는 객체를 반환한다. |
put(...) | 리소스 데이터를 지정된 URL에 PUT 한다. |
- RestTemplate은 TRACE를 제외한 표준 HTTP 메서드 각각에 대해 최소한 하나의 메서드를 가지고 있다.
- execute()와 exchange()는 모든 HTTP 메서드의 요청을 전송하기 위한 저수준 범용 메서드를 제공한다.
- 위의 메서드들은 아래 세 가지 형태로 오버로딩 되어 있다.
- 가변인자 리스트에 지정된 URL 매개변수에 URL 문자열을 인자로 받는다.
- Map<String, String>에 지정된 URL 매개변수에 URL 문자열을 인자로 받는다.
- java.net.URI를 URL에 대한 인자로 받으며, 매개변수화된 URL은 지원하지 않는다.
- RestTemplate을 사용하려면 필요한 시점에 RestTemplate 인스턴스를 생성하거나, 빈으로 선언하고 필요할 때 주입할 수 있다.
RestTemplate rest = new RestTemplate();
GET
getForObject()
만약 해당 API에 HATEOAS가 활성화되지 않았다면 getForObject()를 사용해서 리소스를 가져올 수 있다.
1. URL 문자열을 받는 경우
public User getUserById(String userId) {
return rest.getForObject("http://localhost:8080/users/{id}", User.class, userId);
}
- getForObject()에 전달된 userId 매개변수는 지정된 URL의 {id} 플레이스홀더에 넣기 위해 사용된다.
- 변수 매개변수가 여러 개인 경우, 주어진 순서대로 플레이스홀더에 지정된다.
- getForObject()의 두 번째 매개변수는 응답이 바인딩되는 타입으로, 여기서는 JSON 형식인 응답 데이터가 객체로 역직렬화되어 반환된다.
2. 인자로 Map<string, string>을 받는 경우
public User getUserById(String userId) {
Map<String, String> urlVariables = new HashMap<>();
urlVariables.put("id", userId);
return rest.getForObject("http://localhost:8080/users/{id}", User.class, urlVariables);
}
- userId 값의 키는 "id"이며, 요청이 수행될 때 {id} 플레이스홀더는 키가 id인 Map 항목의 값으로 교체된다.
3. 인자로 URI를 받는 경우
public User getUserById(String userId) {
Map<String, String> urlVariables = new HashMap<>();
urlVariables.put("id", userId);
URI url = UriComponentsBuilder
.fromHttpUrl("http://localhost:8080/users/{id}")
.builder(urlVariables);
return rest.getForObject(url, User.class);
}
- URI 객체는 URL 문자열 명세로 생성되며, 이 문자열의 {id} 플레이스홀더는 Map 항목 값으로 교체된다.
getForEntity()
- getForObject() 메서드는 리소스로 도메인 객체만 가져와서 응답 결과로 반환한다.
- 클라이언트가 이외에 추가로 필요한 것이 있다면 getForEntity()를 사용할 수 있다.
- getForEntity()는 응답 결과를 나타내는 도메인 객체를 반환하는 대신 도메인 객체를 포함하는 ResponsEntity 객체를 반환한다.
- ResponsEntity에는 응답 헤더와 같은 더 상셍한 응답 컨텐츠를 포함시킬 수 있다.
public User getUserById(String userId) {
ResponsEntity<User> responseEntity = rest.getForEntity("http://localhost:8080/users/{id}",
User.class,
urlVariables);
log.info(responseEntity.getHeaders().getDate());
return responseEntity.getBody();
}
- getForEntity() 메서드는 getForObject()와 동일한 매개변수를 갖도록 오버로딩 되어 있으므로, URL 변수들을 가변 인자 리스트나 URI 객체로 전달할 수 있다.
PUT - put()
- HTTP PUT 요청을 전송하기 위한 메서드로, 직렬화된 후 지정된 URL로 전송되는 Object 타입을 인자로 받는다.
- 이때, URL 자체는 URI 객체나 문자열로 지정될 수 있다.
- getForObject()처럼 URL 변수들은 가변 인자 리스트나 Map으로 제공될 수 있다.
public void updateUser(User user) {
rest.put("http://localhost:8080/users/{id}",
user,
user.getId());
}
- URL은 문자열로 지정되었고 인자로 전달된 User 객체의 id 속성 값으로 교체되는 프레이스 홀더를 갖는다.
- put() 메서드는 User 객체 자체를 전송하며, 반환타입은 void로 반환값을 처리할 필요는 없다.
DELETE - delete()
public void deleteUser(User user) {
rest.delete("http://localhost:8080/users/{id}",
user.getId());
}
- 문자열로 지정된 URL과 URL 변수 값만 delete()의 인자로 전달한다.
- 다른 RestTemplate과 마찬가지로, URL은 Map으로 된 URL 매개변수나 URI 객체로 지정될 수 있다.
POST
postForObject()
- POST 요청이 수행된 후 새로 생성된 리소스를 반환받고 싶다면 postForObject()를 사용한다.
public User createUser(User user) {
return rest.postForObject("http://localhost:8080/users",
user,
User.class);
}
- postForObject() 메서드는 문자열 URL과 서버에 전송될 객체 및 이 객체의 타입을 인자로 받는다.
- 또한, URL 변수 값을 갖는 Map이나 URL을 대체할 가변 매개변수 리스트를 네 번재 매개변수로 전달할 수 있다.
postForLocation
- 만약 클라이언트에서 새로 생성된 리소스의 위치가 추가로 필요하다면 postForLocation()을 사용한다.
public User createUser(User user) {
return rest.postForLocation("http://localhost:8080/users",
user);
}
- postForLocation()은 리소스 객체 대신 새로 생성된 리소스의 URL를 반환한다.
- 반환된 URI는 해당 응답의 Location 헤더에서 얻을 수 있다.
postForEntity()
- 만약 새로 생성된 리소스의 위치와 리소스 객체 모두가 필요하다면 postForEntity()를 사용한다.
public User createUser(User user) {
ResponseEntity<User> responseEntity = rest.postForEntity("http://localhost:8080/users",
user,
User.class);
log.info("New resource created at " + responseEntity.getHeaders().getLocation());
return responsEntity.getBody();
}
Traverson
- Traverson은 스프링 데이터 HATEOAS와 같이 제공되는 자바 기반의 라이브러리로, 스프링 애플리케이션에서 하이퍼미디어 API를 사용할 수 있게 해준다.
- Traverson를 사용할 때는 우선 해당 API의 기본 URI를 갖는 객체를 생성해야 한다.
- RestTemplate처럼 Traverson 객체를 생성한 후 사용하거나, 주입되는 빈으로 선언 가능
Traverson traverson = new Traverson(
URI.create("http://localhost:8080/api"), MediaTypes.HAL_JSON);
- 이후 follow("관계 이름") 메서드를 통해 원하는 리소스로 이동할 수 있고, toObject()를 통해 해당 리소스의 컨텐츠를 가져올 수 있다.
- toObject() 메서드의 인자에는 데이터를 읽어 들이는 객체의 타입을 지정해야 하며, CollectionModel<>과 같은 제네릭 타입 대신에 ParameterizedTypeReference를 생성하여 리소스 타입을 지정한다.
- follow() 메서드는 두 개 이상의 관계 이름을 인자로 지정하여 한 번만 호출하는 것도 가능하다.
정리
- Traverson을 사용하면 HATEOAS가 활성화된 API를 이동하면서 해당 API의 리소스를 쉽게 가져올 수 있지만, API에 리소스를 쓰거나 삭제하는 메서드를 제공하지 않는다.
- 반대로 RestTemplate은 리소스를 쓰거나 삭제할 수 있지만 API를 이동하는 것이 쉽지 않다.
- 따라서, API의 이동과 리소스의 변경이나 삭제를 모두 해야 한다면 RestTemplate와 Traverson을 함께 사용해야 한다.
- Traverson은 새로운 리소스가 생성될 링크로 이동할 때도 사용할 수 있으며, 이동한 다음에는 해당 링크를 RestTemplate에 지정하여 필요한 HTTP 요청을 수행할 수 있다.
private User addUser(User user) {
String usersUrl = traverson.follow("users")
.asLink()
.getHref();
return rest.postForObject(usersUrl,
user,
User.class);
}
users 링크를 따라간 후, asLink()를 호출하여 users 링크 자체를 요청한다.
-> getHref()를 호출하여 이 링크의 URL을 가져온다.
-> URL을 얻은 다음 postForObject()를 호출하여 새로운 리소스를 추가할 수 있다.
'Spring > Rest API' 카테고리의 다른 글
아파치 카프카 (Kafka) (0) | 2022.02.09 |
---|---|
비동기 메시지 전송 (JMS, RabbitMQ) (0) | 2022.02.09 |
스프링 데이터 REST (0) | 2022.01.30 |
REST 엔드포인트 정의 (0) | 2022.01.30 |
RestContoller 요청과 응답 방법 (0) | 2022.01.20 |