Table of contents

스프링부트가 제공하는 Spring HATEOAS관련된 설정을 살펴보자.

HATEOAS

Spring HATEOASHATEOAS를 구현하기 위해 편리한 기능들을 제공해주는 라이브러리이다.

HATEOAS는 Hypermedia As The Engine Of Application State의 약자로 이름이 거창하지만 결국 REST API에서 리소스에 대한 정보를 제공할 때, 현재 리소스와 연관된 링크 정보를 클라이언트에게 제공하는 아키텍쳐이다. 클라이언트는 연관된 링크 정보를 바탕으로 다른 리소스에 접근한다.

온라인 서점에서 루트 페이지의 리소스를 요청하는 상황을 가정해보자. 루트 페이지의 링크는 self 라는 이름으로 제공되고, 책을 조회할 수 있는 링크가 books라는 이름으로 제공된다. 클라이언트는 루트 페이지 응답에서 책을 조회할 수 있는 url을 알 수 있다.

자세한 내용은 위의 링크와 가이드 문서래퍼런스 문서를 참조하자.

실습

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-hateoas</artifactId>
</dependency>

HATEOAS를 추가하면 스프링부트에서 많은 것들을 자동 설정한다. 가장 큰 두가지는 ObjectMapper와 LinkDiscovers이다. LinkDiscovers는 직접 사용할 일이 많지 않지만, ObjectMapper는 객체를 json을 서로 변환할 때 자주 사용한다. ObjectMapper는 spring-boot-starter-web만 등록되어 있어도 설정이 된다.

LinkDiscovers는 클라이언트 쪽에서 링크 정보를 Rel 이름으로 찾을때 사용할 수 있는 HATEOAS용 XPath 확장 클래스이다.

이제 컨트롤러 테스트를 작성해보자.

@RunWith(SpringRunner.class)
@WebMvcTest(SampleController.class)
public class SampleControllerTest {

    @Autowired
    MockMvc mockMvc;

    @Test
    public void hello() throws Exception {
        mockMvc.perform(get("/hello"))
                .andDo(print())
                .andExpect(status().isOk())
                .andExpect(jsonPath("$._links").exists());

    }

}

GET /hello를 요청하면 200 상태코드와 본문에 _links라는 json 속성이 존재하는지 확인하는 테스트 코드이다. 현재 테스트는 당연히 실패한다. 이번엔 컨트롤러와 모델을 구현해보자.

@RestController
public class SampleController {

    @GetMapping("/hello")
    public Hello hello() {
        Hello hello = new Hello();
        hello.setPrefix("Hey,");
        hello.setName("jch");
        return hello;
    }
}

public class Hello {

    private String prefix;
    private String name;

    public String getPrefix() {
        return prefix;
    }

    public void setPrefix(String prefix) {
        this.prefix = prefix;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return prefix + " " + name;
    }
}

GET /hello 요청을 매핑하고, Hello의 인스턴스를 json 데이터로 응답한다. 이번에는 링크 정보가 없기 떄문에 테스트가 실패한다. 링크 정보를 추가해보자.

@RestController
public class SampleController {

    @GetMapping("/hello")
    public Resource<Hello> hello() {
        Hello hello = new Hello();
        hello.setPrefix("Hey,");
        hello.setName("jch");

        Resource<Hello> helloResource = new Resource<>(hello);
        helloResource.add(linkTo(methodOn(SampleController.class).hello()).withSelfRel());

        return helloResource;
    }
}

// Body = {"prefix":"Hey,","name":"jch","_links":{"self":{"href":"http://localhost/hello"}}}

링크 정보를 추가하기 위해 org.springframework.hateoas.Resource를 이용하고, 링크 정보를 생성하기 위해 org.springframework.hateoas.mvc.ControllerLinkBuilder.linkTo와 org.springframework.hateoas.mvc.ControllerLinkBuilder.methodOn를 이용한다.

hateoas의 Resource는 우리가 제공한 리소스에 링크 정보가 추가된 리소스다.

이렇게 만든 리소스를 응답하면서 _links가 추가되기 떄문에 테스트가 성공한다.

ObjectMapper

앞서 설명한 것처럼 ObjectMapper는 자동설정으로 등록되기 때문에 별도로 등록할 필요 없이 바로 주입받아서 사용할 수 있다.

커스터마이징이 필요하다면 spring.jackson에 있는 프로퍼티를 사용하면 된다.

해당 포스팅은 스프링 부트 개념과 활용 강의 내용을 토대로 작성하였습니다.