이 가이드는 Spring을 사용하여 "Hello, World" 하이퍼미디어 기반 REST 웹 서비스를 생성하는 과정을 안내합니다.
하이퍼미디어는 REST의 중요한 측면(aspect)입니다. 이를 통해 클라이언트와 서버를 크게 분리하고 독립적으로 발전할 수 있는 서비스를 구축할 수 있습니다. REST 리소스에 대해 반환된 표현(representation)에는 데이터뿐만 아니라 관련 리소스에 대한 링크도 포함됩니다. 따라서 표현의 디자인은 전체 서비스 디자인에 매우 중요합니다.
하이퍼미디어 링크와 웹 링크는 목적과 사용되는 컨텍스트에 따라 구별됩니다. 하이퍼미디어 링크는 RESTful API에서 서버와 클라이언트 간의 상호작용을 위해 사용되는 반면, 웹 링크는 웹 페이지 간의 이동을 위해 사용됩니다. 하이퍼미디어 링크는 프로그래밍적으로 데이터를 주고 받는 데 사용되고, 웹 링크는 사용자가 웹 페이지를 탐색하는 데 사용됩니다.
하이퍼미디어 링크:
웹 링크:
<a>
(anchor) 태그로 정의되어 웹 페이지 간의 이동을 제공합니다.HATEOAS는 REST 아키텍처 스타일에서 중요한 원칙 중 하나로, Hypermedia를 이용하여 애플리케이션 상태를 관리하는 방법을 정의합니다. 이는 "Hypermedia as the Engine of Application State"의 약자로서, RESTful API에서 클라이언트와 서버 간의 통신과 상태 전이를 위한 규칙을 제공합니다.
기본적으로 HATEOAS는 클라이언트에게 어떤 리소스를 요청할 수 있는 링크들을 동적으로 제공함으로써 RESTful 서비스의 상호작용성을 향상시킵니다. 클라이언트는 리소스의 표현(representation)을 받은 후, 해당 리소스에서 가능한 작업들을 설명하는 하이퍼미디어 링크들을 확인할 수 있습니다. 이를 통해 클라이언트는 서버로부터 받은 리소스 상태에 따라 어떤 작업을 할 수 있는지 동적으로 결정할 수 있습니다.
HATEOAS를 따르는 RESTful 서비스는 다음과 같은 이점을 제공합니다:
자기 기술적인 API:
유연성과 확장성:
디자인의 단순화:
안정성:
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는 클라이언트가 다음에 수행할 수 있는 작업을 가리킵니다. 이 두 가지는 목적과 사용되는 컨텍스트에서 차이가 있습니다.
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"
}
}
}
이제 프로젝트와 빌드 시스템을 설정했으므로 웹 서비스를 생성할 수 있습니다.
서비스 상호 작용에 대해 생각하여 프로세스를 시작하십시오.
서비스는 선택적으로 쿼리 문자열에 name
매개변수를 사용하여 GET 요청을 처리하기 위해 /greeting
에 리소스를 노출합니다. GET 요청은 인사말을 나타내기 위해 본문에 JSON이 포함된 200 OK
응답을 반환해야 합니다.
그 외에도 리소스의 JSON 표현은 _links
속성의 하이퍼미디어 요소 목록으로 강화됩니다. 가장 기본적인 형태는 리소스 자체를 가리키는 링크입니다. 표현은 다음 목록과 유사해야 합니다.
{
"content":"Hello, World!",
"_links":{
"self":{
"href":"http://localhost:8080/greeting?name=World"
}
}
}
content
은 greeting
의 텍스트 표현입니다. _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으로 자동 마샬링합니다.
다음으로 이러한 인사말을 제공할 리소스 컨트롤러를 만듭니다.
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 작업을 매핑하기 때문에GET
과PUT
,POST
등을 지정하지 않습니다. 이 매핑 범위를 좁히려면@GetMapping("/greeting")
을 사용하세요. 이 경우org.springframework.web.bind.annotation.GetMapping;
도 가져오는 것입니다.
@RequestParam
은 쿼리 문자열 매개변수 name
값을 greeting()
메서드의 name
매개변수에 바인딩합니다. 이 쿼리 문자열 매개변수는 defaultValue
속성을 사용하기 때문에 암시적으로 필요하지 않습니다(implicitly not required
). 요청에 없으면 defaultValue
인 World
가 사용됩니다.
@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
헤더가 있는데, 주요한 것들은 다음과 같습니다:
X-Forwarded-For: 클라이언트의 실제 IP 주소를 전달하는 데 사용됩니다. 클라이언트가 프록시를 통해 서버에 접근할 때, 클라이언트의 IP를 식별하기 위해 사용됩니다.
X-Forwarded-Proto: 클라이언트와 프록시 간의 프로토콜(예: HTTP 또는 HTTPS)를 전달합니다. 이를 통해 서버는 요청이 보안 연결(HTTPS)을 통해 전달되었는지 확인할 수 있습니다.
X-Forwarded-Host: 클라이언트가 요청한 호스트 이름을 전달합니다. 이는 프록시가 여러 개의 도메인을 처리하는 경우 원래 호스트 이름을 식별하기 위해 사용됩니다.
Spring HATEOAS는 이러한 X-Forwarded
헤더들을 존중하여, 프록시나 로드 밸런서 뒤에 서비스가 배치된 경우 올바른 URL을 생성합니다. 특히, X-Forwarded-Host
헤더를 올바르게 구성하면, Spring HATEOAS는 생성하는 링크들의 형식을 이에 맞게 조정하여 올바른 URI를 제공합니다.
withSelfRel()
을 호출하면 Greeting
표현 모델에 추가하는 Link
인스턴스가 생성됩니다.
이제 서비스가 실행되었으므로 http://localhost:8080/greeting
을 방문하면 다음 내용이 표시됩니다.
다음 URL을 방문하여 name
쿼리 문자열 매개변수를 제공하십시오: http://localhost:8080/greeting?name=User
. Hello, World!
에서 content
속성 값이 어떻게 변경되는지 확인하세요. Hello, User!
다음 목록에 표시된 것처럼 self
링크의 href
속성도 해당 변경 사항을 반영(reflect)합니다.
이 변경 사항은 GreetingController
의 @RequestParam
배열이 예상대로 작동함을 보여줍니다. name
매개변수에는 기본값인 World
가 지정되었지만 항상 쿼리 문자열을 통해 명시적으로 재정의될 수 있습니다.