Spring (3) - Building a Hypermedia-Driven RESTful Web Service
https://spring.io/guides/gs/rest-hateoas
Spring HATEOAS로 구현하는 하이퍼미디어 기반 REST Web Service
REST API를 다루다 보면 단순히 데이터(JSON)만 반환하는 방식을 넘어, 클라이언트가 다음 동작을 수행할 수 있는 URI 정보를 함께 넘겨주는 HATEOAS(Hypermedia As The Engine Of Application State) 구조를 접하게 된다.
하이퍼미디어를 활용하면 클라이언트와 서버 간 결합도를 획기적으로 낮출 수 있어, 양쪽 시스템이 서로에게 영향을 주지 않고 독립적으로 발전할 수 있다.
Spring Boot와 Spring HATEOAS를 활용해 하이퍼미디어 기반 REST 서비스를 구축하는 과정을 정리한다.
1. 무엇을 만드는가?
/greeting 엔드포인트로 GET 요청을 받으면 일반적인 메시지 데이터뿐만 아니라, 해당 리소스 자체를 가리키는 self 링크가 포함된 JSON 응답을 반환하는 서비스를 구축한다.
기본 응답 형태 (/greeting)
1
2
3
4
5
6
7
8
9
{
"content": "Hello, World!",
"_links": {
"self": {
"href": "http://localhost:8080/greeting?name=World"
}
}
}
쿼리 파라미터(name)를 넘기면 content 내용과 함께 self 링크의 URI도 가변적으로 변경된다.
파라미터 전달 시 응답 형태 (/greeting?name=User)
1
2
3
4
5
6
7
8
9
{
"content": "Hello, User!",
"_links": {
"self": {
"href": "http://localhost:8080/greeting?name=User"
}
}
}
2. 의존성 설정 (Dependencies)
Spring Initializr를 통해 프로젝트를 생성하거나 build.gradle / pom.xml에 다음 의존성을 추가한다.
- Language: Java 17 이상
- Dependencies:
Spring HATEOAS(Spring Web 기능 포함)
3. 리소스 표현 클래스 (Resource Representation Class) 작성
응답으로 나갈 JSON 데이터를 모델링할 POJO 클래스를 작성한다. 이때 Spring HATEOAS가 제공하는 RepresentationModel을 상속받는 것이 핵심이다.
RepresentationModel을 상속받으면 Link 객체를 손쉽게 추가할 수 있는 메서드들이 제공되며, 최종적으로 _links 필드로 직렬화된다.
src/main/java/com/example/resthateoas/Greeting.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
package com.example.resthateoas;
import org.springframework.hateoas.RepresentationModel;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
public class Greeting extends RepresentationModel<Greeting> {
private final String content;
@JsonCreator
public Greeting(@JsonProperty("content") String content) {
this.content = content;
}
public String getContent() {
return content;
}
}
@JsonCreator: Jackson이 생성자를 통해 객체를 인스턴스화하도록 지정한다.@JsonProperty: JSON 필드명을 생성자 인자에 매핑한다.
4. REST 컨트롤러 작성
요청을 처리하고 하이퍼미디어 링크를 생성하여 응답을 반환할 Controller를 작성한다.
src/main/java/com/example/resthateoas/GreetingController.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
package com.example.resthateoas;
import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.*;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
@RestController
public class GreetingController {
private static final String TEMPLATE = "Hello, %s!";
@RequestMapping("/greeting")
public HttpEntity<Greeting> greeting(@RequestParam(value = "name", defaultValue = "World") String name) {
Greeting greeting = new Greeting(String.format(TEMPLATE, name));
// 컨트롤러 메서드를 가리키는 self 링크 생성 및 추가
greeting.add(linkTo(methodOn(GreetingController.class).greeting(name)).withSelfRel());
return new ResponseEntity<>(greeting, HttpStatus.OK);
}
}
주요 동작 포인트
WebMvcLinkBuilder활용:linkTo(...)와methodOn(...)정적 메서드를 사용하면 컨트롤러의 매핑 정보를 검사하여 실제 호출 가능한 정확한 URI를 하드코딩 없이 동적으로 생성할 수 있다.withSelfRel(): 생성된 링크의 관계 유형(relation type)을self로 지정하며, 이를greeting.add()를 통해 모델에 추가한다.@RestController: 반환되는HttpEntity<Greeting>페이로드를 JSON 형식으로 직접 응답 본문에 렌더링한다.
5. 메인 애플리케이션 실행
@SpringBootApplication 어노테이션이 붙은 메인 클래스를 실행한다.
1
2
3
4
5
6
7
8
9
10
11
12
13
package com.example.resthateoas;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class RestHateoasApplication {
public static void main(String[] args) {
SpringApplication.run(RestHateoasApplication.class, args);
}
}
Spring Boot 특유의 자동 설정(@EnableAutoConfiguration)과 내장 톰캣 덕분에 과거처럼 web.xml이나 별도의 서블릿 설정 파일 없이 순수 Java 코드만으로 애플리케이션이 즉시 구동된다.
6. 동작 테스트
애플리케이션을 실행한 후 브라우저나 HTTP 클라이언트를 통해 결과를 확인한다.
- 기본 요청:
http://localhost:8080/greetingcontent에 “Hello, World!”가 출력되고_links.self.href에 해당 URL이 매핑된다.
- 파라미터 전달:
http://localhost:8080/greeting?name=Usercontent가 “Hello, User!”로 변경되며_links.self.href역시 파라미터가 포함된 URL로 업데이트된다.
요약
Spring HATEOAS를 사용하면 리소스 클래스에 RepresentationModel을 상속받고 WebMvcLinkBuilder를 통해 몇 줄의 코드만으로 REST API에 하이퍼미디어 링크를 결합할 수 있다.
이를 통해 클라이언트는 Hard-coded된 URL에 의존하지 않고, API가 제공하는 링크 리소스를 따라 유연하게 상태를 전이할 수 있게 된다.