RESTful한_개발하기 - upswp/THXSTORE GitHub Wiki

RESTful

THXSTORE의 Backend 개발을 진행하면서 RESTful한 개발을 진행하기 위해서 노력했습니다.

RESTful한 REST API스러운 개발을 진행하기 위해서 노력한 이유는, 개발자라면 응당 REST API를 개발한 로이 필딩이 정의한 REST를 따르기 위한 노력이었습니다.

참고한 세미나는 이응준개발자님께서 2017년 네이버가 주관한 Deview라는 개발자 컨퍼런스에서 "그런 REST API로 괜찮은가"라는 발표 영상을 참고하여 진행했습니다.

주 안점은 로이 필딩이 정의한 REST 의 대부분의 정의에 있어서는 지켜지고 있지만

  • Self-Describtive Message
  • HATEOAS

이 두가지가 지켜지고 있지 않다는 점에서 논하는 세미나였습니다.

저희 THXSTORE 프로젝트에서는 취업전선에 나가기 전, 프로젝트를 통해서 로이 필딩이 정의한 REST를 직접 몸소 개발하며 그 의미를 고찰하고 탐색하기 위한 프로젝트로 Backend에서 RESTful한 개발을 진행하기 위해 노력했습니다.


정의

API

  • Application Programming Interface

REST

  • REpresentational State Transfer
    • 인터넷 상의 시스템 간의 상호 운용성을 제공하는 방법 중 하나로 시스템 각각의 독립적인 진화를 보장하기 위한 방법

REST API

  • REST 아키텍처 스타일을 따르는 API

REST 아키텍처 스타일

  • Client-Server
  • Stateless
  • Cache
  • Uniform Interface
  • Layered System
  • Code-On-Demand(optional)

Uniform Interface

● Identification of resources

● manipulation of resources through represenations

● self-descrive messages

● hypermisa as the engine of appliaction state (HATEOAS)

사실상 가장 잘 안지켜지고 있는 부분은 바로 밑에 두가지입니다.


Self-descriptive message

  • 메시지 스스로 메시지에 대한 설명이 가능해야 합니다.
  • 서버가 변해서 메시지가 변해도 클라이언트는 그 메시지를 보고 해석이 가능해야 합니다.
  • 확장 가능한 커뮤니케이션

HATEOAS

  • 하이퍼미디어(링크)를 통해 애플리케이션 상태 변화가 가능해야 합니다.
  • 링크 정보를 동적으로 바꿀 수 있습니다.

Self-descriptive message 해결 방법

  • 미디어 타입을 정의하고 IANA에 등록하고 그 미디어 타입을 리소스 리턴할 때 Content-Type으로 사용합니다.
  • Profile 링크 헤더를 추가합니다.
    • 브라우저들이 아직 스팩 지원을 잘 하지 않는 부분이 있습니다.
    • 그렇기 때문에 HAL의 링크 데이터에 profile 링크를 추가합니다.

HATEOAS 해결방법

  • 데이터 링크 제공합니다.
    • 링크를 HAL을 이용하여 제공합니다.
  • 링크 헤더나 Location을 제공합니다.

AuthController.java

    @PostMapping
    @PreAuthorize("isAnonymous()")
    public ResponseEntity registerMember(@Valid @RequestBody SignUpRequest signUpRequest) {
        Member newMember = authService.registerMember(signUpRequest);

        WebMvcLinkBuilder selfLinkBuilder = linkTo(AuthController.class).slash(newMember.getId());
        URI createUri = selfLinkBuilder.toUri();
        MemberResource memberResource = new MemberResource(newMember);
        if (signUpRequest.getSocial() == null) {
            memberResource.add(linkTo(AuthController.class).withRel("signUp-LOCAL"));
            memberResource.add(Link.of("/api/docs/index.html#resources-signUp-LOCAL").withRel("profile"));
        } else {
            memberResource.add(linkTo(AuthController.class).withRel("signUp-SOCIAL"));
            memberResource.add(Link.of("/api/docs/index.html#resources-signUp-SOCIAL").withRel("profile"));
        }
        return ResponseEntity.created(createUri).body(memberResource);
    }

MemberResource.java

package com.ssafy.thxstore.controller.member.Resource;


import com.ssafy.thxstore.controller.member.AuthController;
import com.ssafy.thxstore.member.domain.Member;
import org.springframework.hateoas.EntityModel;
import org.springframework.hateoas.Link;

import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.linkTo;


public class MemberResource extends EntityModel<Member> {
    public MemberResource(Member member, Link... links) {
        super(member, links);
        add(linkTo(AuthController.class).slash(member.getId()).withSelfRel());
    }
}

위와 같이 해당 부분에 있어서 링크 정보를 전달해주는 Resource파일과 정보를 제공해주는 역할을 Controller에서 진행을 하고 있습니다. 이 부분은 백기선님 강의의 스프링 기반 REST API 개발을 참고하여 개발을 진행했습니다.

위와 같이 링크 정보를 제공하고, Test code를 통해서 테스트의 내용들과 함께 RESTDocs를 이용하여 링크 정보가 전달이 됩니다.


HTTP Method로 소통하는 방식과 하이퍼미디어 컨트롤에 대한 고찰

HTTP Status Code를 이용하여 그동안에 개발을 진행했습니다. URL + HTTP Method 조합으로 리소스를 구분하는것에서 물론 업그레이드 된 부분으로 가장 보편적인 방법으로 그동안 개발을 진행했습니다.

발생한 에러의 종류를 커뮤니케이션 하기위해 상태코드 (Status code)를 사용하는것, 그리고 안전하게 오퍼레인션과 안전하지 않은 오퍼레이션 간의 강한 분리를 제공하는것이 핵심입니다.

기존의 방식에는 성공여부를 알려주고 페이지 이동은 클라이언트에서 해결하는 방식입니다.

HATEOAS(Hypertext As The Engine Of Application) 링크를 따라가는 방식과 유사한 방식으로 이뤄지는데 클라이언트가 다른 자원에 대한 링크를 통해 서버와 (잠재적으로 상태 변이를 초래하는)상호작용을 한다. 즉, 특정 API를 요청한 후 다음 단계로 작업을 위한 리소스의 URI를 알려주는 것입니다. 이 단계를 적용하면 클라이언트에 영향을 미치지 않으면서 서버를 변경하는 것이 가능합니다.

THXSTORE는 클라이언트를 개발하는 사람들이 특정 메소드로부터 올 수 있는 결과 동작을 예측하는 것이 가능하도록 구현하기 위해 HATEOAS를 사용하여 개발했습니다. API가 변경되더라도 키가 바뀌지 않는한 URI로 주어진 링크(link)만 유지하면 되므로 별도의 대응이 요구되지 않게 됩니다. 또한 클라이언트가 제공되는 API의 변화에 즉각적으로 대응하지 않아도 되는 편리함을 제공하기 위해 HATEOAS를 이용한 개발을 진행했습니다.

⚠️ **GitHub.com Fallback** ⚠️