[SpringBoot][WebMVC] Hateoas

2022. 12. 13. 14:59JAVA/Spring

HATEOAS(Hypermedia As The Engine Of Application State)란 무엇인가

  • REST API를 사용하는 클라이언트가 전적으로 서버와 동적인 상호작용이 가능하도록 하는 것 
  • 클라이언트가 서버로부터 어떠한 요청을 할 때, 요청에 필요한 URL를 응답에 포함시켜 반환하는 것으로 가능하게 할 수도 있음

 

REST API 정의

웹 애플리케이션이 제공하는 각각의 데이터를 리소스, 즉 자원으로 간주하고 각각의 자원에 고유한 URI(Uniform Resource Identifier)를 할당함으로써 이를 표현하는 API를 정의하기 위한 소프트웨어 아키텍처 스타일입니다.

 

REST API 구현 단계

  • 잘 설계된 REST API의 마지막 단계가 HATEOAS
  • HATEOAS라는 개념을 통해 자원에 호출 가능한 API 정보를 자원의 상태를 반영하여 표현하는 것

 

 

REST API 구현 단계별 예시

다음 그림에서 REST API 구현 3단계는 HATEOAS로써 어떤 리소스 자원 + 리소스 자원과 관련된 링크가 같이 클라이언트에게 전달됩니다.

 

HATEOAS 사용 예시

계좌번호가 “12345”인 계좌의 정보를 조회하는 경우에 해당 계좌의 상태(잔여 금액 등)에 따라 접근 가능한 추가 API들이 LINKS라는 이름으로 제공됩니다.

 

기존의 전형적인 REST API 응답
HATEOAS가 적용된 REST API 응답(balance와 관련된 추가 API들이 링크들로 제공)

 

HATEOAS 실습

0. 의존성 추가

implementation 'org.springframework.boot:spring-boot-starter-hateoas'

 

1. 리소스를 표현하기 위한 클래스 정의

@Getter
@Setter
@AllArgsConstructor
public class Hello {
    private String prefix;
    private String name;

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

 

2. RestController를 생성하고 "/hateoas"라는 url 요청시 Hello라는 리소스를 반환한다고 가정합니다. 이때 Hello 샘플 객체와 url 셀프 정보를 같이 첨부하여 반환합니다.

@RestController
@RequestMapping("/hateoas")
public class HateoasSampleController {

    @GetMapping
    public EntityModel<Hello> hello() {
        Hello hello = new Hello("Hey,","yonghwan");

        // HATEOAS
        EntityModel<Hello> resource = EntityModel.of(hello);

        // 이 hello값을 반환시킬때 hello가 사용할 수 있는 추가 정보를 하이퍼링크로 넣어놓을 예정
        Link link = linkTo(methodOn(this.getClass()).hello()).withSelfRel();
        resource.add(link);
        return resource;
    }
}

 

3. 테스트 코드를 작성하고 실행 결과를 확인합니다.

@WebMvcTest(HateoasSampleController.class)
public class SampleControllerTest {
    @Autowired
    MockMvc mockMvc;

    @Test
    @WithMockUser
    public void testHello() throws Exception {
        //given
        String url = "/hateoas";
        //when
        this.mockMvc.perform(MockMvcRequestBuilders.get(url))
                .andExpect(status().isOk())
                .andExpect(jsonPath("$._links.self").exists())
                .andDo(print());
        //then
    }
}

실행결과는 다음과 같습니다.

MockHttpServletResponse:
           Status = 200
    Error message = null
          Headers = [Content-Type:"application/hal+json", X-Content-Type-Options:"nosniff", X-XSS-Protection:"1; mode=block", Cache-Control:"no-cache, no-store, max-age=0, must-revalidate", Pragma:"no-cache", Expires:"0", X-Frame-Options:"DENY"]
     Content type = application/hal+json
             Body = {"prefix":"Hey,","name":"yonghwan","_links":{"self":{"href":"http://localhost/hateoas"}}}
    Forwarded URL = null
   Redirected URL = null
          Cookies = []

위 실행결과에서 Response body를 보면 Hello 리소스 객체의 멤버 정보뿐만 아니라 그와 연관된 링크 정보들도 첨부된 것을 볼 수 있습니다.

 

References

source code : https://github.com/yonghwankim-dev/springboot_study/tree/main/springboot_webmvc/src/main/java/kr/yh/hateoas
https://joomn11.tistory.com/26
[인프런] 스프링부트 개념과 활용