HAL_JSON_VALUE (feat. RESTful API)

SexyWoong·2024년 10월 16일

'우이삭' 프로젝트를 진행하며 팀원들과 함께 아래의 영상을 시청하였다.
그 결과, HAL_JSON_VALUE라는것을 적용해보았다.
그 외적으로도 아래의 영상을 보며 느낀것이 많았기에 적어본다.

영상에 대한 설명을 하자면

1991년 '팀 버너스리' 선생님께서 WEB을 만드셨다.

고민 : 인터넷으로 정보 공유할때, 어떻게 할 것인가
해답 : 정보들을 하이퍼텍스트로 연결한다.

  • 표현 형식: HTML
  • 식별자: URI
  • 전송 방법: HTTP

'로이 필딩' 선생님은 HTTP의 기능을 더하고, 수정해야했음. 하지만 이미 WEB상에는 HTTP가 많이 사용되고 있었음. 따라서 호환성의 문제가 있음.

어떻게 하면 기본의 호환성을 유지하며 HTTP를 발전시킬 수 있을까? -> HTTP Object Model (=REST)

REST API: REST 아키텍쳐 스타일을 따르는 API
REST: 분산 하이퍼미디어 시스템(예:웹)을 위한 아키텍처 스타일
아키텍처 스타일: 제약조건의 집합

=> 즉, 제약조건들을 다 따르는 스타일을 REST API라고 한다.

그렇다면, REST를 구성하는 스타일에는 무엇이 있는가

  • client- server
  • stateless
  • cache
  • uniform interface
  • layered system
  • code-on-demand(optional)

나머지는 대부분 잘 지켜지고있다. 하지만 Uniform Interface가 잘 지켜지지 않는다.

Uniform Interface의 제약조건에는 무엇이 있는가

  • identification of resources - URI로 자원을 식별할 수 있는가
  • manipulation of resources through representations - 표현을 통해 CRUD가 가능한가
  • self-descriptive messages - 메시지는 스스로를 설명해야한다.
  • hypermedia as the engine of application state (HATEOAS) - 페이지를 이동하는 과정에서는 상태의 전이가 발생한다. 이전의 페이지는 무엇이고, 다음의 페이지는 무엇인지 등 현재 페이지와 관련된 URI를 표현하는것.

그렇다면 왜 Uniform Interface를 지켜야할까. -> 독립적인 진화

독립적인 진화는 무엇인가

  • 서버와 클라이언트가 각각 독립적으로 진화한다.
  • 서버의 기능이 변경되어도 클라이언트를 수정할 필요가 없다.
  • REST를 만들게 된 계기: WEB을 망치지 않고 어떻게 HTTP를 발전시킬 수 있을까

웹은 REST를 굉장히 잘 지키고 있다. 그 결과 위처럼 동작할 수 있다.

몇몇 모바일 앱은 변경사항이 있으면 업데이트를 해야만 앱을 실행할 수 있다. -> REST를 잘 지키지 못했다.

왜 이정도로 긴 시간이 걸리는가 -> 하위 호환성을 깨뜨리면 안되기 때문.

API가 꼭 REST API이어야만 하는건가

시스템 전체를 통제할 수 있다: 내가 클라이언트와 서버를 모두 통제할 수 있다.
진화에 관심이 없다: 시스템을 수정할때마다 하위호환성이 되지 않고 업데이트를 계속 해야함.

왜 API는 REST가 잘 안되나


큰 차이는 웹은 사람이 보고, API는 기계가 본다.
HTML은 Self-descriptive와 HATEOAS를 만족한다. 하지만 JSON은 만족하지 않는다.

Self-desciptive를 만족하면 왜 REST한가: 서버나 클라이언트가 변경되더라도 오고 가는 메시지는 self-descriptive하므로 언제나 해석이 가능하다.

HATEOAS를 만족하면 왜 REST한가: 해당 페이지에서 다음 페이지로 이동하는 링크를 마음대로 서버에서 변경해도 된다. 클라이언트측은 해당 URI만 참고하면 되기 때문.

프로젝트 적용

@Slf4j
@RestController
@RequiredArgsConstructor
@RequestMapping(value = "/v1/members", produces = MediaTypes.HAL_JSON_VALUE)
public class MemberController {

   private final MemberService memberService;

   @SneakyThrows
   @GetMapping
   public ResponseEntity<ApiResponse<MemberProfileGetResponse>> getMemberProfile(@LoginUser SessionUser sessionUser) {
       return ApiResponse.ok(memberService.findMemberProfile(sessionUser.memberId()),
           linkTo(methodOn(MemberController.class).getMemberProfile(sessionUser)).withSelfRel(),
           linkTo(MemberController.class.getMethod("editMemberProfile", List.class, MemberProfileEditRequest.class, SessionUser.class)).withRel("edit member profile")
       );
   }
}

MemberController중 조회 API이다. MediaType을 HAL_JSON_VALUE로 설정했고, link를 설정해주었다.

{
   "code": 200,
   "body": {
       "imageUrl": "http://k.kakaocdn.net/dn/utgdR/btsHicKT45I/ELHXKXPUTvfKZr2qaV2SZ0/img_640x640.jpg",
       "nickname": "김재웅",
       "birthday": null,
       "mbti": null,
       "calendarColor": null
   },
   "links": [
       {
           "rel": "self",
           "href": "http://localhost:8080/v1/members"
       },
       {
           "rel": "edit member profile",
           "href": "http://localhost:8080/v1/members"
       }
   ]
}

위처럼 현재 회원조회 페이지의 link와 회원수정 페이지의 link를 확인할 수 있다.

profile
함께 있고 싶은 사람, 함께 일하고 싶은 개발자

0개의 댓글