하효닝
log(hahyun ^ B)
하효닝
전체 방문자
오늘
어제
  • 분류 전체보기 (140)
    • Diary (0)
    • Web (7)
    • Frontend (8)
    • Python (44)
      • Python (1)
      • Algorithm (13)
      • Coding Test (30)
    • Django (3)
      • Django (2)
      • Django Rest (1)
    • Java (14)
      • Java (10)
      • Java Tuning (4)
    • Spring (34)
      • Spring (7)
      • Spring MVC (5)
      • DB 접근기술 (1)
      • JPA (10)
      • Spring Security (3)
      • Rest API (8)
    • Computer Science (26)
      • Operating System (8)
      • Linux (2)
      • Network (2)
      • Database (9)
      • SQL Tuning (5)
    • AWS (2)
    • Git (0)
    • etc (1)

블로그 메뉴

  • 홈
  • 태그
  • 방명록

공지사항

인기 글

태그

최근 댓글

최근 글

티스토리

hELLO · Designed By 정상우.
하효닝

log(hahyun ^ B)

Spring/Rest API

스프링 데이터 REST

2022. 1. 30. 07:41

스프링 데이터 REST

  • 스프링 데이터는 코드에 정의한 인터페이스를 기반으로 Repository를 자동으로 생성하고 필요한 기능을 수행한다.
  • 스프링 데이터 REST는 스프링 데이터의 모듈 중 하나로, 스프링 데이터가 생성하는 Repository의 REST API를 자동으로 생성한다.
  • 따라서, 스프링 데이터 REST를 빌드에 추가하면 정의한 각 리포지토리 인터페이스를 사용하는 API를 얻을 수 있다.

 

의존성 추가

implementation 'org.springframework.boot:spring-boot-starter-data-rest'
  • 빌드에 해당 의존성만 지정해주면 이미 스프링 데이터를 사용 중인 프로젝트에서 REST API를 노출시킬 수 있다.
  • 스프링 데이터 REST가 생성하는 REST 엔드포인트를 사용하려면 @RestController 어노테이션이 지정된 모든 클래스들을 제거해야 한다.

 

기본 경로 설정

  • 스프링 데이터 REST가 생성한 엔드포인트들은 GET, POST, PUT, DELETE 메서드 모두 지원해주므로, 데이터의 추가 삭제 또한 가능하다.
  • 다만, 해당 API의 엔드포인트가 다른 컨트롤러와 충돌하는 것을 막기 위해 기본 경로를 지정해주는 것이 좋다.
  • 스프링 데이터 REST가 자동 생성한 API의 기본 경로는 spring.data.rest.base-path 속성에 설정한다.
// 스프링 데이터 REST 엔드포인트는 /api로 시작
spring:
  data:
    rest:
      base-path: /api

 

 

예) /api/ingredients GET 요청 결과

{
    "_embedded": {
        "ingredients": [
            {
                "name": "Flour Tortilla",
                "type": "WRAP",
                "_links": {
                    "self": {
                        "href": "http://localhost:8080/api/ingredients/FLTO"
                    },
                    "ingredient": {
                        "href": "http://localhost:8080/api/ingredients/FLTO"
                    }
                }
            },
            ...
            {
                "name": "Sour Cream",
                "type": "SAUCE",
                "_links": {
                    "self": {
                        "href": "http://localhost:8080/api/ingredients/SRCR"
                    },
                    "ingredient": {
                        "href": "http://localhost:8080/api/ingredients/SRCR"
                    }
                }
            }
        ]
    },
    "_links": {
        "self": {
            "href": "http://localhost:8080/api/ingredients"
        },
        "profile": {
            "href": "http://localhost:8080/api/profile/ingredients"
        }
    },
    "page": {
        "size": 20,
        "totalElements": 10,
        "totalPages": 1,
        "number": 0
    }
}

 

 

리소스 경로와 관계 이름 조정

  • 스프링 데이터 리포지토리의 엔드포인트를 생성할 때 스프링 데이터 REST는 해당 엔드포인트와 관련된 엔티티 클래스 이름의 복수형을 사용한다.
    • 예) Member -> members, Order -> orders
  • 그러나 기대하는 값과 스프링 데이터 REST가 복수형으로 바꾼 값이 다른 경우가 발생할 수도 있다.
  • 이러한 스프링 데이터 REST의 복수형 관련 문제점은 @RestResource 어노테이션으로 해결할 수 있다.
    • rel 속성에는 원하는 관계 이름을, path 속성에는 원하는 경로를 입력
@Entity
@RestResource(rel = "users", path = "users")
public class Member {
	...
}

 

 

※ 참고: API 기본 경로로 GET 요청을 하면, 노출된 모든 엔드포인트의 링크를 갖는 홈 리소스 내역을 얻을 수 있다.

{
    "_links": {
        "users": {
            "href": "http://localhost:8080/api/users{?page,size,sort}",
            "templated": true
        },
        "orders": {
            "href": "http://localhost:8080/api/orders{?page,size,sort}",
            "templated": true
        },
        "ingredients": {
            "href": "http://localhost:8080/api/ingredients{?page,size,sort}",
            "templated": true
        },
        "tacos": {
            "href": "http://localhost:8080/api/tacos{?page,size,sort}",
            "templated": true
        },
        "profile": {
            "href": "http://localhost:8080/api/profile"
        }
    }
}

 

페이징과 정렬

  • 홈 리소스의 모든 링크는 선택적 매개변수인 page, size, sort를 제공한다.
  • 컬렉션 리소스를 요청하면 기본적으로 한 페이지당 20개의 항목이 반환되며, page와 size 매개변수를 통해 요청에 포함될 페이지 번호와 페이지 크기를 조정할 수 있다.
  • 예를 들어, 페이지 크기가 5인 두 번째 페이지를 요청하는 경우 아래와 같이 GET 요청을 하면 된다. (페이지 번호는 0번부터 시작)
http://localhost:8080/api/users?size=5&page=1

 

※ 참고: HATEOAS는 처음, 마지막, 다음, 이전 페이지의 링크를 요청 응답에 제공하므로, API의 클라이언트는 현재 페이지가 어딘지 계속 파악하면서 매개변수와 URL을 연관시킬 필요가 없다.

 

  • 또한 sort 매개변수를 지정하면 엔티티의 속성을 기준으로 결과 리스트를 정렬할 수 있다.
  • 예를 들어, 최근 생성된 12개의 주문을 가져오는 경우 아래와 같이 페이징과 정렬 매개변수를 같이 지정할 수 있다.
http://localhost:8080/api/orders?sort=createdAt,desc&page=0&size=12

 

  • 그러나 이러한 매개변수들을 사용해서 리스트를 요청하기 위한 UI 코드가 하드코딩되어야 한다는 문제가 존재한다.
  • 만약 API 요청 URL이 변경된다면 하드코딩으로 인해 클라이언트 코드가 실행되지 않을 수도 있기 때문에, 이러한 문제점을 해결하기 위해 클라이언트가 링크 리스트에서 URL을 찾는 방법을 이용한다.

 

커스텀 엔드포인트 추가

  • 기본적인 CRUD API가 아닌 나에게 필요한 엔드포인트를 생성해야 하는 경우 @RestController 어노테이션이 지정된 빈을 구현해서 스프링 데이터 REST가 자동 생성하는 엔드포인트에 추가할 수 있다.
  • 이때 두 가지 고려사항이 존재한다.
    1. 내가 추가한 엔드포인트 컨트롤러는 스프링 데이터 REST의 기본 경로로 매핑되지 않는다. 
    2. 내가 컨트롤러에 정의한 엔드포인트는 스프링 데이터 REST 엔드포인트에서 반환되는 리소스의 하이퍼링크에 자동으로 포함되지 않는다. 즉, 클라이언트가 관계 이름을 사용해서 커스텀 엔드포인트를 찾을 수 없다.

 

1. 기본 경로 문제 해결

  • 스프링 데이터 REST는 스프링 데이터 REST 엔드포인트에 구성되는 것과 동일한 기본 경로로의 매핑을 지원하는 @RepositoryRestController 어노테이션을 제공한다.
  • @RepositoryRestController가 지정된 컨트롤러의 모든 경로 매핑은 spring.data.rest.base-path 속성의 값이 앞에 붙은 경로를 갖는다.
  • 한 가지 주의할 점은 @RepositoryRestController는 메서드의 반환값을 응답 바디에 자동으로 담아주지 않기 때문에, 해당 메서드에 @ResponseBody 어노테이션을 지정하거나, 해당 메서드에서 응답 데이터를 포함하는 ResponseEntity를 반환해야 한다.

 

2. 커스텀 하이퍼링크 추가하기

  • 스프링 HATEOAS는 리소스 프로세서 빈을 선언하면 스프링 데이터 REST가 자동으로 포함시키는 링크 리스트에 해당 링크를 추가할 수 있는 RepresentationModelProcessor를 제공한다.
  • RepresentationModelProcessor는 API를 통해 리소스가 반환되기 전에 리소스를 조작하는 인터페이스이다.
@Configuration
public class SpringDataRestApiConfig {

    @Bean
    public RepresentationModelProcessor<PagedModel<EntityModel<Member>>> memberProcessor(EntityLinks links) {
        
        return new RepresentationModelProcessor<PagedModel<EntityModel<Member>>>() {
            @Override
            public PagedModel<EntityModel<Member>> process(PagedModel<EntityModel<Member>> model) {
                model.add(
                        links.linkFor(Member.class)
                                .slash("recent")
                                .withRel("recents"));
                return model;
            }
        };
    }
}

 

'Spring > Rest API' 카테고리의 다른 글

비동기 메시지 전송 (JMS, RabbitMQ)  (0) 2022.02.09
REST 서비스 사용  (0) 2022.01.30
REST 엔드포인트 정의  (0) 2022.01.30
RestContoller 요청과 응답 방법  (0) 2022.01.20
REST API 인증 기법  (0) 2022.01.20
    'Spring/Rest API' 카테고리의 다른 글
    • 비동기 메시지 전송 (JMS, RabbitMQ)
    • REST 서비스 사용
    • REST 엔드포인트 정의
    • RestContoller 요청과 응답 방법
    하효닝
    하효닝

    티스토리툴바