_links

2024. 12. 11. 12:19Spring Framework/Spring HATEOAS

📌 _links란?

_linksRESTful API에서 하이퍼미디어(HATEOAS)를 지원하기 위해 사용되는 JSON 필드로,
클라이언트가 API 응답을 통해 동적으로 리소스를 탐색할 수 있도록 도와줍니다.
Spring HATEOAS에서는 RepresentationModel을 활용해 _links 필드를 자동으로 생성할 수 있습니다.

🎯 1. _links의 개념

🔹 REST API에서 리소스 간 탐색을 가능하게 함
🔹 HATEOAS(Hypermedia as the Engine of Application State)의 핵심 요소
🔹 각 리소스가 어떤 동작을 수행할 수 있는지 명확하게 제공
🔹 클라이언트가 URL을 직접 구성하지 않고도 API를 동적으로 탐색 가능

📌 2. _links의 역할과 구조

예제 API 응답 (_links 포함)

{
  "id": 1,
  "licenseId": "456",
  "description": "Software Product",
  "organizationId": "123",
  "productName": "Ostock",
  "licenseType": "full",
  "_links": {
    "self": {
      "href": "http://localhost:8080/v1/organization/123/license/456"
    },
    "update": {
      "href": "http://localhost:8080/v1/organization/123/license/456"
    },
    "delete": {
      "href": "http://localhost:8080/v1/organization/123/license/456"
    },
    "organization": {
      "href": "http://localhost:8080/v1/organization/123"
    },
    "all-licenses": {
      "href": "http://localhost:8080/v1/organization/123/licenses"
    }
  }
}

_links 안에 여러 개의 링크가 포함됨
self 링크: 현재 리소스를 참조
update 링크: 해당 리소스를 업데이트할 수 있는 경로
delete 링크: 해당 리소스를 삭제할 수 있는 경로
organization 링크: 해당 라이선스가 속한 조직 정보 제공
all-licenses 링크: 조직에 속한 모든 라이선스를 조회하는 경로

🏗 3. Spring HATEOAS에서 _links 자동 생성

Spring Boot와 Spring HATEOAS를 사용하면 _links 필드를 자동으로 생성할 수 있습니다.

📌 Step 1: Spring HATEOAS 의존성 추가

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-hateoas</artifactId>
</dependency>

spring-boot-starter-hateoas를 추가하면 _links를 자동으로 생성할 수 있는 기능 제공

📌 Step 2: HATEOAS를 지원하는 모델 정의

import org.springframework.hateoas.RepresentationModel;
import lombok.Getter;
import lombok.Setter;

@Getter
@Setter
public class License extends RepresentationModel<License> {  // ✅ RepresentationModel 상속
    private int id;
    private String licenseId;
    private String description;
    private String organizationId;
    private String productName;
    private String licenseType;
}

RepresentationModel<T>을 상속하면 해당 객체에 HATEOAS 링크 추가 가능

📌 Step 3: 컨트롤러에서 _links 추가

import org.springframework.hateoas.EntityModel;
import org.springframework.hateoas.Link;
import org.springframework.hateoas.server.mvc.WebMvcLinkBuilder;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping(value = "v1/organization/{organizationId}/license")
public class LicenseController {

    @GetMapping(value = "/{licenseId}")
    public ResponseEntity<EntityModel<License>> getLicense(
            @PathVariable("organizationId") String organizationId,
            @PathVariable("licenseId") String licenseId) {

        License license = new License();
        license.setId(1);
        license.setLicenseId(licenseId);
        license.setOrganizationId(organizationId);
        license.setDescription("Software Product");
        license.setProductName("Ostock");
        license.setLicenseType("full");

        // ✅ Self 링크 추가
        Link selfLink = WebMvcLinkBuilder.linkTo(
                WebMvcLinkBuilder.methodOn(LicenseController.class)
                        .getLicense(organizationId, licenseId))
                .withSelfRel();

        // ✅ 업데이트 링크 추가
        Link updateLink = WebMvcLinkBuilder.linkTo(
                WebMvcLinkBuilder.methodOn(LicenseController.class)
                        .updateLicense(organizationId, license))
                .withRel("update");

        // ✅ 삭제 링크 추가
        Link deleteLink = WebMvcLinkBuilder.linkTo(
                WebMvcLinkBuilder.methodOn(LicenseController.class)
                        .deleteLicense(organizationId, licenseId))
                .withRel("delete");

        // ✅ 조직 링크 추가
        Link orgLink = WebMvcLinkBuilder.linkTo(
                WebMvcLinkBuilder.methodOn(OrganizationController.class)
                        .getOrganization(organizationId))
                .withRel("organization");

        // ✅ 모든 라이선스 조회 링크 추가
        Link allLicensesLink = WebMvcLinkBuilder.linkTo(
                WebMvcLinkBuilder.methodOn(LicenseController.class)
                        .getAllLicenses(organizationId))
                .withRel("all-licenses");

        return ResponseEntity.ok(EntityModel.of(license, selfLink, updateLink, deleteLink, orgLink, allLicensesLink));
    }
}

HATEOAS 링크 추가하는 과정

  1. selfLink → 현재 리소스를 가리키는 self 링크 생성
  2. updateLink → 해당 리소스를 업데이트하는 링크 생성
  3. deleteLink → 해당 리소스를 삭제하는 링크 생성
  4. orgLink → 조직 정보를 조회하는 링크 생성
  5. allLicensesLink → 조직의 모든 라이선스를 조회하는 링크 생성

⚙️ 4. _links의 다양한 활용 예제

1) Self 링크만 포함

"_links": {
    "self": {
        "href": "http://localhost:8080/v1/organization/123/license/456"
    }
}

🔹 현재 리소스(license 456)를 다시 조회하는 경로 제공

2) CRUD 연산을 지원하는 링크

"_links": {
    "self": {
        "href": "http://localhost:8080/v1/organization/123/license/456"
    },
    "update": {
        "href": "http://localhost:8080/v1/organization/123/license/456"
    },
    "delete": {
        "href": "http://localhost:8080/v1/organization/123/license/456"
    }
}

🔹 클라이언트가 API 응답을 보고 직접 경로를 구성하지 않아도 동작 가능
🔹 업데이트와 삭제를 위한 API 링크 제공

3) 관련 리소스를 탐색하는 링크

"_links": {
    "self": {
        "href": "http://localhost:8080/v1/organization/123/license/456"
    },
    "organization": {
        "href": "http://localhost:8080/v1/organization/123"
    },
    "all-licenses": {
        "href": "http://localhost:8080/v1/organization/123/licenses"
    }
}

🔹 해당 라이선스가 속한 조직을 조회할 수 있는 organization 링크 추가
🔹 조직 내 모든 라이선스를 조회하는 all-licenses 링크 추가

🎉 5. 결론

_links는 REST API에서 하이퍼미디어(HATEOAS)를 적용하여 클라이언트가 동적으로 API를 탐색할 수 있도록 지원
✅ Spring HATEOAS를 활용하면 _links를 쉽게 추가하고 유지보수성을 높일 수 있음
Self 링크뿐만 아니라, 관련 리소스 및 CRUD 연산을 위한 링크도 함께 제공하면 API 사용성이 극대화됨 🚀

'Spring Framework > Spring HATEOAS' 카테고리의 다른 글

HATEOAS(Hypermedia as the Engine of Application State)  (0) 2025.03.03
WebMvcLinkBuilder  (0) 2024.12.11
self 링크  (0) 2024.12.09
EntityModel  (0) 2024.12.09
RepresentationModel  (0) 2024.12.09