Guide_Building a Hypermedia-Driven RESTful Web Service

Dev.Hammy·2023년 12월 16일
0

Spring Guides

목록 보기
14/46

이 가이드는 Spring을 사용하여 "Hello, World" 하이퍼미디어 기반 REST 웹 서비스를 생성하는 과정을 안내합니다.

하이퍼미디어는 REST의 중요한 측면(aspect)입니다. 이를 통해 클라이언트와 서버를 크게 분리하고 독립적으로 발전할 수 있는 서비스를 구축할 수 있습니다. REST 리소스에 대해 반환된 표현(representation)에는 데이터뿐만 아니라 관련 리소스에 대한 링크도 포함됩니다. 따라서 표현의 디자인은 전체 서비스 디자인에 매우 중요합니다.

하이퍼미디어 링크

하이퍼미디어 링크와 웹 링크는 목적과 사용되는 컨텍스트에 따라 구별됩니다. 하이퍼미디어 링크는 RESTful API에서 서버와 클라이언트 간의 상호작용을 위해 사용되는 반면, 웹 링크는 웹 페이지 간의 이동을 위해 사용됩니다. 하이퍼미디어 링크는 프로그래밍적으로 데이터를 주고 받는 데 사용되고, 웹 링크는 사용자가 웹 페이지를 탐색하는 데 사용됩니다.

  1. 하이퍼미디어 링크:

    • RESTful API에서 사용되며, 데이터 포맷(예: JSON 또는 XML) 안에 존재합니다.
    • 클라이언트와 서버 간의 통신을 위한 링크입니다.
    • 리소스 간의 관계와 상호작용을 설명하고, 다음에 수행할 수 있는 작업을 포함하는 URI를 포함합니다.
    • 예를 들어, JSON 형식의 API 응답에서 특정 키(예: "links") 아래에 링크 정보가 포함됩니다.
  2. 웹 링크:

    • HTML 문서에서 사용됩니다.
    • 일반적으로 <a>(anchor) 태그로 정의되어 웹 페이지 간의 이동을 제공합니다.
    • 웹 브라우저에서 사용자가 클릭하여 다른 웹 페이지로 이동하는 데 사용됩니다.
    • 이 링크들은 주로 사람이 읽고 클릭할 수 있는 형태(텍스트 또는 이미지)로 표시됩니다.

HATEOAS

HATEOAS는 REST 아키텍처 스타일에서 중요한 원칙 중 하나로, Hypermedia를 이용하여 애플리케이션 상태를 관리하는 방법을 정의합니다. 이는 "Hypermedia as the Engine of Application State"의 약자로서, RESTful API에서 클라이언트와 서버 간의 통신과 상태 전이를 위한 규칙을 제공합니다.

기본적으로 HATEOAS는 클라이언트에게 어떤 리소스를 요청할 수 있는 링크들을 동적으로 제공함으로써 RESTful 서비스의 상호작용성을 향상시킵니다. 클라이언트는 리소스의 표현(representation)을 받은 후, 해당 리소스에서 가능한 작업들을 설명하는 하이퍼미디어 링크들을 확인할 수 있습니다. 이를 통해 클라이언트는 서버로부터 받은 리소스 상태에 따라 어떤 작업을 할 수 있는지 동적으로 결정할 수 있습니다.

HATEOAS를 따르는 RESTful 서비스는 다음과 같은 이점을 제공합니다:

  1. 자기 기술적인 API:

    • 예시: RESTful API가 제품 목록을 반환하는데, 각 제품에 대한 상세 정보를 얻기 위한 링크가 포함되어 있습니다. 클라이언트는 이 링크를 통해 어떤 작업을 수행할 수 있는지 이해하고, 각 작업의 결과를 예측할 수 있습니다.
  2. 유연성과 확장성:

    • 예시: 새로운 리소스나 기능이 API에 추가될 때, 클라이언트는 하이퍼미디어 링크를 통해 새로운 작업이나 리소스에 접근할 수 있습니다. 예를 들어, 주문 API에 새로운 상태(취소된 주문)가 추가되더라도, 클라이언트는 해당 상태를 이해하고 상태를 변경할 수 있는 링크를 통해 작업을 수행할 수 있습니다.
  3. 디자인의 단순화:

    • 예시: API 디자인 시, 각 리소스에 대한 하이퍼미디어 링크를 명확하게 정의함으로써 클라이언트와 서버 간의 통신이 명확해집니다. 예를 들어, 주문 리소스에는 주문 상세 정보, 결제 정보, 취소 등의 작업을 위한 링크가 명시적으로 포함될 수 있습니다.
  4. 안정성:

    • 예시: 클라이언트는 하이퍼미디어 링크를 통해 작업을 수행하므로, 서버 측의 변경에 따라 클라이언트가 유연하게 대응할 수 있습니다. 즉, 클라이언트는 리소스에 대한 예상치 못한 상태 변화에 대비할 수 있습니다. 만약 새로운 작업이 추가되거나 변경되더라도, 클라이언트는 링크를 통해 새로운 작업을 찾아내고 수행할 수 있습니다.

Spring MVC와 HATEOAS의 차이

https://velog.io/@dev_hammy/GuideUploading-Files

Spring MVC 코드는 파일 시스템에서의 파일 경로를 URI로 사용하는데, 이는 파일을 식별하고 접근하기 위한 방식입니다. 예를 들어, 클라이언트가 요청하면 서버는 특정 파일에 대한 경로를 URI로 제공하여 해당 파일을 다운로드할 수 있도록 합니다. 이는 파일에 대한 실질적인 위치를 가리키는 것이며, 클라이언트가 이 URI를 사용하여 파일을 다운로드하거나 업로드합니다.

HATEOAS에서의 URI는 조금 다릅니다. 여기서의 URI는 특정 작업을 수행하기 위한 링크로, 리소스 간의 상태 전이를 나타냅니다. 예를 들어, 클라이언트가 서버로부터 받은 응답에 하이퍼미디어 링크가 포함되어 있다면, 이 링크는 다음에 가능한 작업을 가리키는 URI를 포함할 수 있습니다. 이 URI를 클라이언트가 따라가면 해당 작업을 수행하게 됩니다.

중요한 차이는 Spring MVC에서의 URI는 특정 파일이나 위치를 가리키는 것이고, HATEOAS에서의 URI는 클라이언트가 수행할 수 있는 작업을 가리키는 것입니다. Spring MVC의 URI는 파일을 식별하고 접근하는 데 사용되며, HATEOAS의 URI는 API의 상호작용성을 높이기 위해 클라이언트가 다음에 수행할 수 있는 작업을 나타냅니다.

즉, Spring MVC에서의 URI는 서버의 파일이나 리소스를 가리키는 것이고, HATEOAS의 URI는 클라이언트가 다음에 수행할 수 있는 작업을 가리킵니다. 이 두 가지는 목적과 사용되는 컨텍스트에서 차이가 있습니다.

What You Will Build

Spring HATEOAS를 사용하여 하이퍼미디어 기반 REST 서비스를 구축합니다. 이 API 라이브러리는 Spring MVC 컨트롤러를 가리키는 링크를 생성하고 리소스 표현(representation)을 구축하며 지원되는 하이퍼미디어 형식(예: HAL)으로 렌더링되는 방법을 제어하는 데 사용할 수 있습니다. ).

서비스는 http://localhost:8080/greeting에서 HTTP GET 요청을 수락합니다.

리소스 자체를 가리키는 링크인 가능한 가장 간단한 하이퍼미디어 요소가 풍부한 인사말의 JSON 표현으로 응답합니다. 다음 목록은 출력을 보여줍니다.

{
  "content":"Hello, World!",
  "_links":{
    "self":{
      "href":"http://localhost:8080/greeting?name=World"
    }
  }
}

응답(response)은 다음 목록에 표시된 것처럼 쿼리 문자열의 선택적 name 매개 변수를 사용하여 인사말을 사용자 지정할 수 있음을 이미 나타냅니다.

http://localhost:8080/greeting?name=User

name 매개변수 값은 World의 기본값을 재정의하고 다음 목록에 표시된 대로 응답에 반영됩니다.

{
  "content":"Hello, User!",
  "_links":{
    "self":{
      "href":"http://localhost:8080/greeting?name=User"
    }
  }
}

Starting with Spring Initializr

Create a Resource Representation Class

이제 프로젝트와 빌드 시스템을 설정했으므로 웹 서비스를 생성할 수 있습니다.

서비스 상호 작용에 대해 생각하여 프로세스를 시작하십시오.

서비스는 선택적으로 쿼리 문자열에 name 매개변수를 사용하여 GET 요청을 처리하기 위해 /greeting에 리소스를 노출합니다. GET 요청은 인사말을 나타내기 위해 본문에 JSON이 포함된 200 OK 응답을 반환해야 합니다.

그 외에도 리소스의 JSON 표현은 _links 속성의 하이퍼미디어 요소 목록으로 강화됩니다. 가장 기본적인 형태는 리소스 자체를 가리키는 링크입니다. 표현은 다음 목록과 유사해야 합니다.

{
  "content":"Hello, World!",
  "_links":{
    "self":{
      "href":"http://localhost:8080/greeting?name=World"
    }
  }
}

contentgreeting의 텍스트 표현입니다. _links 요소에는 링크 목록이 포함되어 있습니다(이 경우 정확히 관계 유형이 rel이고 액세스된 리소스를 가리키는 href 속성이 있는 링크).

greeting 표현을 모델링하려면 리소스 표현(representation) 클래스를 만듭니다. _links 속성은 표현 모델의 기본 속성이므로 Spring HATEOAS는 Link 인스턴스를 추가하고 앞에서 설명한 대로 렌더링되도록 하는 기본 클래스(RepresentationModel이라고 함)와 함께 제공됩니다.

다음 목록(src/main/java/guides/resthateoas/Greeting.java에서)에 표시된 대로 RepresentationModel을 확장하고 콘텐츠에 대한 필드와 접근자와 생성자를 추가하는 기존의 일반 Java 개체를 만듭니다.

package guides.resthateoas;

import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import org.springframework.hateoas.RepresentationModel;

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이 이 POJO의 인스턴스를 생성할 수 있는 방법을 나타냅니다.

  • @JsonProperty: Jackson이 이 생성자 인수를 입력해야 하는 필드를 표시합니다.

이 가이드의 뒷부분에서 볼 수 있듯이 Spring은 Jackson JSON 라이브러리를 사용하여 Greeting 유형의 인스턴스를 JSON으로 자동 마샬링합니다.

다음으로 이러한 인사말을 제공할 리소스 컨트롤러를 만듭니다.

Create REST Controller

RESTful 웹 서비스를 구축하는 Spring의 접근 방식에서 HTTP 요청은 컨트롤러에 의해 처리됩니다. 구성 요소는 @Controller@ResponseBody 주석을 결합한 @RestController 주석으로 식별됩니다. 다음 GreetingController(src/main/java/guides/resthateoas/GreetingController.java)는 Greeting 클래스의 새 인스턴스를 반환하여 /greeting에 대한 GET 요청을 처리합니다.

package guides.resthateoas;


import org.springframework.http.HttpEntity;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

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

@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));

        greeting.add(linkTo(methodOn(GreetingController.class).greeting(name)).withSelfRel());

        return new ResponseEntity<>(greeting, HttpStatus.OK);
    }
}

이 컨트롤러는 간결하고 단순하지만 많은 일이 진행되고 있습니다. 우리는 그것을 단계별로 분해합니다.

@RequestMapping 주석은 /greeting에 대한 HTTP 요청이 greeting() 메소드에 매핑되도록 보장합니다.

위의 예에서는 @RequestMapping이 기본적으로 모든 HTTP 작업을 매핑하기 때문에 GETPUT, POST 등을 지정하지 않습니다. 이 매핑 범위를 좁히려면 @GetMapping("/greeting")을 사용하세요. 이 경우 org.springframework.web.bind.annotation.GetMapping;도 가져오는 것입니다.

@RequestParam은 쿼리 문자열 매개변수 name 값을 greeting() 메서드의 name 매개변수에 바인딩합니다. 이 쿼리 문자열 매개변수는 defaultValue 속성을 사용하기 때문에 암시적으로 필요하지 않습니다(implicitly not required). 요청에 없으면 defaultValueWorld가 사용됩니다.

@RestController 주석이 클래스에 존재하기 때문에 암시적 @ResponseBody 주석이 인사말 메서드에 추가됩니다. 이로 인해 Spring MVC는 반환된 HttpEntity와 해당 페이로드(Greeting)를 응답(response)에 직접 렌더링합니다.

메서드 구현에서 가장 흥미로운 부분은 컨트롤러 메서드를 가리키는 링크를 생성하는 방법과 이를 표현 모델에 추가하는 방법입니다. linkTo(…)methodOn(…)은 모두 컨트롤러에서 메서드 호출을 가짜로 만들 수 있는 ControllerLinkBuilder의 정적 메서드입니다. 반환된 LinkBuilder는 컨트롤러 메서드의 매핑 주석을 검사하여 메서드가 매핑되는 URI를 정확하게 구축합니다.

Spring HATEOAS는 다양한 X-FORWARDED- 헤더를 존중합니다. Spring HATEOAS 서비스를 프록시 뒤에 배치하고 X-FORWARDED-HOST 헤더로 올바르게 구성하면 결과 링크의 형식이 올바르게 지정됩니다.

X-Forwarded 헤더는 일반적으로 클라이언트와 서버 간의 HTTP 프록시나 로드 밸런서와 같은 중간 단계에서 사용되는 헤더입니다. 이 헤더는 원래 요청에 대한 정보를 포함하고 있어, 중간에 위치한 프록시나 로드 밸런서가 요청을 전달할 때 클라이언트와 서버 간의 관계를 유지하고 수정하지 않도록 돕습니다.

여러 가지 X-Forwarded 헤더가 있는데, 주요한 것들은 다음과 같습니다:

  1. X-Forwarded-For: 클라이언트의 실제 IP 주소를 전달하는 데 사용됩니다. 클라이언트가 프록시를 통해 서버에 접근할 때, 클라이언트의 IP를 식별하기 위해 사용됩니다.

  2. X-Forwarded-Proto: 클라이언트와 프록시 간의 프로토콜(예: HTTP 또는 HTTPS)를 전달합니다. 이를 통해 서버는 요청이 보안 연결(HTTPS)을 통해 전달되었는지 확인할 수 있습니다.

  3. X-Forwarded-Host: 클라이언트가 요청한 호스트 이름을 전달합니다. 이는 프록시가 여러 개의 도메인을 처리하는 경우 원래 호스트 이름을 식별하기 위해 사용됩니다.

Spring HATEOAS는 이러한 X-Forwarded 헤더들을 존중하여, 프록시나 로드 밸런서 뒤에 서비스가 배치된 경우 올바른 URL을 생성합니다. 특히, X-Forwarded-Host 헤더를 올바르게 구성하면, Spring HATEOAS는 생성하는 링크들의 형식을 이에 맞게 조정하여 올바른 URI를 제공합니다.


withSelfRel()을 호출하면 Greeting 표현 모델에 추가하는 Link 인스턴스가 생성됩니다.

Test the Service

이제 서비스가 실행되었으므로 http://localhost:8080/greeting을 방문하면 다음 내용이 표시됩니다.

다음 URL을 방문하여 name 쿼리 문자열 매개변수를 제공하십시오: http://localhost:8080/greeting?name=User. Hello, World!에서 content 속성 값이 어떻게 변경되는지 확인하세요. Hello, User! 다음 목록에 표시된 것처럼 self 링크의 href 속성도 해당 변경 사항을 반영(reflect)합니다.

이 변경 사항은 GreetingController@RequestParam 배열이 예상대로 작동함을 보여줍니다. name 매개변수에는 기본값인 World가 지정되었지만 항상 쿼리 문자열을 통해 명시적으로 재정의될 수 있습니다.

0개의 댓글