ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Spring Boot] RESTful API 설계 원칙
    Spring 2024. 12. 2. 09:47

     

    RESTful API는 REST(Representational State Transfer) 아키텍처 스타일을 따르는 API를 말합니다.
    클라이언트와 서버 간의 통신을 단순하고 확장 가능하게 설계하기 위해 RESTful 원칙을 준수해야 합니다.

     

    RESTful API 설계 원칙

        자원(Resource) 중심 설계:
            API는 자원을 명확히 정의하고, URI는 자원의 경로를 나타냅니다.
            URI는 명사형으로 표현하며, 동사 대신 HTTP 메서드를 사용합니다.
            예:
                GET             /users (모든 사용자 조회)
                POST          /users (새 사용자 생성)
                PUT             /users/{id} (특정 사용자 수정)
                DELETE      /users/{id} (특정 사용자 삭제)

        HTTP 메서드의 의미 사용:
            각 HTTP 메서드에 적합한 동작을 매핑합니다.
                GET: 자원 조회.
                POST: 자원 생성.
                PUT: 자원 전체 수정.
                PATCH: 자원의 일부 수정.
                DELETE: 자원 삭제.

        Stateless(무상태성):
            요청 간 상태를 서버에 저장하지 않습니다. 모든 요청은 필요한 정보를 자체적으로 포함해야 합니다.
            예: 인증 정보를 매 요청마다 토큰으로 전달. (JWT)

     

    일관된 응답 구조:

        API의 응답은 일관된 형식(JSON, XML 등)으로 제공해야 합니다.
        성공과 에러 응답에 표준화된 메시지와 상태 코드를 포함합니다.
        예:

    {
        "status": "success",
        "data": {
            "id": 1,
            "name": "John Doe"
        }
    }

     

     

    HATEOAS(Hypermedia as the Engine of Application State):

    응답에 관련된 리소스 링크를 포함하여 클라이언트가 더 많은 작업을 탐색할 수 있도록 합니다.

    예:

    {
        "id": 1,
        "name": "John Doe",
        "_links": {
            "self": "/users/1",
            "orders": "/users/1/orders"
        }
    }

     

    상태 코드 활용:

        HTTP 상태 코드를 사용해 요청 결과를 명확히 나타냅니다.
            200 OK: 요청 성공.
            201 Created: 새 자원이 성공적으로 생성됨.
            400 Bad Request: 클라이언트 요청 오류.
            404 Not Found: 자원을 찾을 수 없음.
            500 Internal Server Error: 서버 오류.


     

    Spring Boot에서 RESTful API 구현

        컨트롤러 설계:
            @RestController와 @RequestMapping을 사용해 API 엔드포인트를 정의합니다.

    @RestController
    @RequestMapping("/users")
    public class UserController {
        @GetMapping("/{id}")
        public ResponseEntity<User> getUserById(@PathVariable Long id) {
            User user = userService.findById(id);
            return ResponseEntity.ok(user);
        }
    }

     

    서비스 레이어:
        비즈니스 로직은 컨트롤러에서 분리해 서비스 레이어에 작성합니다.

    예외 처리:
        @ControllerAdvice와 @ExceptionHandler를 사용하여 공통 예외를 처리합니다.

    @ControllerAdvice
    public class GlobalExceptionHandler {
        @ExceptionHandler(ResourceNotFoundException.class)
        public ResponseEntity<String> handleResourceNotFound(ResourceNotFoundException ex) {
            return ResponseEntity.status(HttpStatus.NOT_FOUND).body(ex.getMessage());
        }
    }

     

    DTO 사용:
        데이터 전송 객체(DTO)를 활용해 요청 및 응답 데이터를 구조화합니다.

    Swagger 통합:
        Swagger를 사용해 API 문서를 자동 생성하여 클라이언트와의 협업을 용이하게 합니다.

     

     

    주의할 점

        URI 설계의 일관성:
            복잡한 URI 대신 단순하고 예측 가능한 구조를 유지합니다.


        보안:
            HTTPS를 사용하고, 민감한 데이터는 JWT 같은 토큰 기반 인증으로 보호합니다.


        페이징과 필터링:
            대량의 데이터 조회 API는 페이징, 정렬, 필터링 기능을 제공해야 합니다.
                예: GET /users?page=1&size=10&sort=name,asc.


     

    HATEOAS를 반드시 구현해야 하는 상황

        API 소비자가 탐색 가능성을 요구하는 경우:
            클라이언트가 서버의 API를 미리 알지 못하는 상태에서 서버가 제공하는 리소스를 동적으로 탐색해야 하는 경우.
            예: 클라이언트가 다양한 연관 리소스를 가져오는 작업을 수행할 때.
            예: 주문 상세 데이터를 요청하면 관련된 상품 링크, 사용자 정보 링크를 함께 제공.

        API 사용이 복잡하고 유연한 탐색이 필요한 경우:
            RESTful API를 통해 사용자가 여러 작업을 연결해서 수행해야 하는 워크플로우가 존재할 때.
            예: 쇼핑몰 API에서 장바구니 -> 결제 -> 주문 이력을 탐색하는 경우.

        다양한 클라이언트가 API를 사용하는 경우:
            다양한 종류의 클라이언트(웹, 모바일 앱 등)가 동일한 API를 사용하면서 탐색 경로를 서버가 제공해야 할 때.

     


     

    HATEOAS를 구현하지 않아도 되는 상황

        API가 단순하고 명확한 경우:
            API의 URI와 작업이 명확히 정의되어 있고 클라이언트가 탐색 경로를 별도로 필요로 하지 않는 경우.
            예: CRUD 중심의 단순한 리소스 기반 API.

        API 소비자가 고정된 워크플로우를 사용하는 경우:
            API를 호출하는 애플리케이션이 사전에 API 명세를 알고 있고, 탐색 경로가 고정되어 있는 경우.
            예: 내부 시스템에서 사용하는 API로, 클라이언트가 URI를 사전에 알고 있다면 굳이 HATEOAS를 구현할 필요가 없음.

        HATEOAS 구현이 오히려 복잡성을 증가시키는 경우:
            HATEOAS를 구현함으로써 API가 불필요하게 복잡해지고, 클라이언트도 이를 처리하기 위해 추가적인 작업이 필요하다면, 단순한 JSON 응답 형식이 더 적합할 수 있음.

     

    결론

    HATEOAS는 RESTful의 핵심 원칙 중 하나이지만, 반드시 모든 API에 구현할 필요는 없습니다. 클라이언트와 서버 간 명확한 요구사항 분석을 통해 HATEOAS를 구현할지 여부를 결정하는 것이 중요합니다. 복잡한 워크플로우나 동적 탐색이 필요한 경우에는 반드시 고려하고, 단순한 CRUD API에서는 불필요한 오버헤드를 피하기 위해 생략하는 것이 효율적입니다.

    댓글

Designed by Tistory.