SpringBoot RESTful 웹 서비스 만들기

최병현·2026년 2월 23일

spring boot

목록 보기
4/34

이 내용은 Backend(Controller/API Layer)에 해당한다. Frontend(브라우저/React/모바일 앱)는 HTTP로 API를 호출하고, Spring Boot는 Controller에서 요청을 받아 Service/Repository로 넘긴 뒤 DB(JPA)로 데이터를 읽고/저장한다. 응답은 보통 JSON으로 내려가고, 프론트는 그 JSON을 화면에 렌더링한다.


1. 웹 서비스와 REST 개념

웹 서비스는 HTTP 프로토콜을 통해 인터넷 상에서 통신하는 애플리케이션이다. 그 중에서도 최근 가장 많이 쓰는 방식이 RESTful API이다.

REST(Representational State Transfer)는 “표준 프레임워크”가 아니라 로이 필딩이 제시한 제약 조건(원칙)의 집합에 가까운 아키텍처 스타일이다. 특정 언어/플랫폼에 종속되지 않고 다양한 클라이언트(브라우저, 모바일 앱, 다른 서버)와 통신하기 쉽게 만든다.


2. REST 제약 조건(핵심 감각)

  • Stateless(상태 비저장): 서버는 클라이언트 상태를 저장하지 않는다(요청마다 필요한 정보가 들어와야 한다).
  • Client-Server 분리: UI/클라이언트와 서버는 독립적으로 변경 가능하다.
  • Cache 가능: 동일 리소스 반복 요청이 많아 캐시로 성능을 높일 수 있다.
  • Uniform Interface(일관된 인터페이스): 어떤 클라이언트가 요청해도 규칙/응답 형태가 일관되어야 한다.
  • Layered System: 중간 계층(Proxy, Gateway 등)을 끼워도 전체 구조가 유지되어야 한다.
  • Code-On-Demand(선택): 필요 시 실행 코드까지 내려줄 수 있다(대부분은 선택 사항).

특히 REST에서 실무적으로 가장 체감되는 포인트는 URI 설계 + HTTP 메서드 + JSON 응답 규격이 일관되게 유지되는 것이다.


3. REST의 “일관된 인터페이스”를 구성하는 요소

  • 리소스 식별: 리소스는 URI로 고유하게 식별된다 (ex: /cars, /cars/1).
  • 표현(Representation): 서버는 보통 JSON/XML로 리소스 “표현”을 돌려준다.
  • Self-Descriptive Message: 요청/응답은 처리에 필요한 정보를 포함해야 한다.
  • HATEOAS: 응답에 관련 링크가 포함될 수 있다(다음 행동으로 이동 가능한 링크 제공).

4. Spring Boot에서 REST API는 어디서 처리되나?

Spring Boot에서 HTTP 요청은 Controller가 처리한다. 따라서 domain 패키지와 동일 레벨에 controller 패키지를 만들고, 그 안에 CarController를 만들어 엔드포인트를 노출한다.

Controller는 “요청을 받는 창구”이고, DB 접근은 Repository(JPA)가 담당한다. 즉, Controller가 Repository를 호출해 데이터를 가져와 반환하면, Spring이 객체(List<Car>)를 JSON으로 변환해준다.


5. CarController로 직접 REST API 만들기

아래 코드는 Controller/API Layer에서 GET /cars 요청을 처리하는 예시다. 핵심은 @RestController 덕분에 Java 객체가 JSON으로 자동 변환된다는 점이다.

package com.korit12.cardatabase.controller;

import com.korit12.cardatabase.domain.Car;
import com.korit12.cardatabase.domain.CarRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

@RestController
@RequiredArgsConstructor
public class CarController {

    private final CarRepository carRepository;

    @GetMapping("/cars")
    public List<Car> getCars() {
        return carRepository.findAll();
    }
}

여기서 데이터 흐름은 다음과 같다.

  • Frontend가 GET /cars 요청
  • CarController.getCars() 호출
  • carRepository.findAll()로 DB 조회
  • List<Car> 반환 → JSON으로 변환되어 응답

6. Spring Data REST로 “날먹” REST API 만들기

Spring Data REST는 Repository만으로 REST API를 자동으로 노출해주는 방식이다. 또한 기본적으로 HATEOAS 형태의 응답도 지원한다.

6-1. 의존성 추가

// build.gradle
implementation 'org.springframework.boot:spring-boot-starter-data-rest'

6-2. basePath 설정

Repository 기반 API의 base path를 /api로 고정한다.

// application.properties
spring.data.rest.basePath=/api

이제 브라우저/Postman에서 GET 요청을 보내면, 예: GET http://localhost:8080/api/cars 자동으로 JSON 응답이 나온다.


7. Spring Data REST의 장점과 한계

장점

  • Controller 없이 Repository만으로 CRUD 엔드포인트 자동 생성
  • 단건 조회(/api/cars/1) 같은 것도 자동 제공
  • Owner 같은 엔티티도 자동으로 endpoint 생성
  • HATEOAS 링크 포함 응답 지원

한계

  • 기본 CRUD 규격은 빠르지만 “커스텀 요구사항”이 나오면 Controller/Service 설계가 필요
  • 보안/검증/DTO 변환/복잡한 비즈니스 로직에는 직접 Controller가 더 적합

8. Postman으로 CRUD 호출 감각 잡기

Spring Data REST는 아래 CRUD를 자동 제공한다.

  • GET → Read
  • POST → Create
  • PUT/PATCH → Update
  • DELETE → Delete

8-1. Delete

전체 삭제가 아니라 특정 리소스 삭제면 “리소스 식별자(id)”가 필요하다.

예: DELETE http://localhost:8080/api/vehicles/1

8-2. Create

POST 시점에는 id가 없다. DB에서 저장되면서 id가 생성된다. Content-Type은 application/json이어야 한다.

예: POST http://localhost:8080/api/vehicles

8-3. Update: PUT vs PATCH

  • PUT: 전체 리소스를 교체(전체 key-value 필요)
  • PATCH: 일부만 수정(변경 필드만 전송)

예: PATCH body

{
  "color": "검정"
}

9. 연관관계(Owner 연결)를 REST로 처리하는 방식

Spring Data REST는 연관관계 수정도 엔드포인트로 제공한다. 예를 들어 Car에 Owner를 연결하려면 보통 “연관 필드 URL”에 PUT을 날린다.

예: PUT http://localhost:8080/api/vehicles/4/owner

이때 Content-Type이 text/uri-list이고, body에는 연결할 Owner의 URI를 넣는다.

http://localhost:8080/api/owners/{ownerId}

이 방식은 내부적으로 “FK 연결”을 REST로 표현한 형태라고 보면 된다.


10. 실무 관점에서 생기는 문제: 사용자에게 id가 없다

실제로 UI 사용자 입장에서 “내 차를 수정/삭제하려면 id가 필요”한데, 사용자는 DB의 id를 모르거나 노출하면 안 되는 경우가 많다. 그래서 보통은 다음 중 하나가 필요하다.

  • 검색 기능 제공(brand, registrationNumber 등 비즈니스 키로 검색)
  • UI에서 리스트 조회 시 서버가 id를 포함해 내려주되 화면에는 숨김 처리
  • 아예 외부 노출용 식별자(ex: carCode, uuid)를 따로 둔다

이 문제를 해결하기 위해 Repository에 검색 메서드를 추가하면, Spring Data REST가 /search 엔드포인트를 자동으로 만든다.


11. Spring Data REST 검색(search) 엔드포인트 만들기

Repository에 Query Method를 추가하고, @RepositoryRestResource로 path를 정리한다. 또한 query parameter 이름을 명확히 하려면 @Param을 붙인다.

package com.korit12.cardatabase.domain;

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.repository.query.Param;
import org.springframework.data.rest.core.annotation.RepositoryRestResource;

import java.util.List;

@RepositoryRestResource(path = "vehicles")
public interface CarRepository extends JpaRepository<Car, Long> {

    List<Car> findByBrand(@Param("brand") String brand);

    List<Car> findByColor(@Param("color") String color);
}

이제 아래처럼 호출 가능하다.

  • GET http://localhost:8080/api/vehicles/search/findByBrand?brand=현대
  • GET http://localhost:8080/api/vehicles/search/findByColor?color=검정

12. 핵심 정리

  • REST는 URI로 리소스를 식별하고, HTTP 메서드로 행위를 표현한다.
  • Spring Boot에서 직접 REST를 만들면 Controller에서 endpoint를 정의한다.
  • Spring Data REST는 Repository만으로 CRUD endpoint를 자동 생성한다.
  • 연관관계 연결도 REST 방식으로 처리할 수 있다(text/uri-list + URI).
  • 실무에서는 “id 노출/검색/DTO/검증/보안” 때문에 결국 Controller+Service 설계가 많이 필요하다.
profile
Develop

0개의 댓글