본문 바로가기

개발 이야기/Spring

[Spring] REST API란 ?

1. REST API란?

REST API는 웹 서비스 간의 통신을 위한 아키텍처 스타일입니다.
REST(Representational State Transfer)의 원칙을 따르며 리소스를 중심으로 설계됩니다.

1-1. REST(Representational State Transfer)의 개념

  • REST 아키텍처의 주요 원칙
    • 클라이언트-서버 구조: 관심사의 분리를 통해 확장성을 개선합니다.
    • 무상태성: 각 요청은 독립적이며, 서버는 클라이언트의 상태를 저장하지 않습니다.
    • 캐시 가능성: 응답은 캐시 가능 여부를 명시해야 합니다.
    • 계층화 시스템: 클라이언트는 서버와 직접 연결되었는지 중간 서버와 연결되었는지 알 수 없습니다.
    • 인터페이스 일관성: 일관된 인터페이스로 전체 시스템 아키텍처를 단순화합니다.

2. REST API의 구성요소

  • 자원 : URI로 표현됩니다.
  • 행위 : HTTP 메서드(GET, POST, PUT, DELETE 등)로 표현됩니다.
  • 표현 : 주로 JSON 형식으로 데이터를 주고받습니다.
  • HTTP 상태 코드: 요청의 처리 결과를 나타냅니다.

3. Spring에서 REST API 구현하기

3.1 기본 설정

@RestController
@RequestMapping("/api")
public class UserController {
	// 컨트롤러 내용
}


3.2 주요 어노테이션

Spring에서 REST API 구현 시 사용되는 주요 어노테이션들입니다.

  • @RestController: RESTful 웹 서비스의 컨트롤러를 나타냅니다.
  • @RequestMapping: 요청 URL을 특정 메서드에 매핑합니다.
  • @GetMapping, @PostMapping, @PutMapping, @DeleteMapping: 각각 GET, POST, PUT, DELETE HTTP 메서드에 대한 요청을 처리합니다.
  • @PathVariable: URL 경로에 변수를 넣어 사용할 때 사용합니다.
  • @RequestBody: HTTP 요청 본문을 자바 객체로 변환합니다.
  • @ResponseEntity: HTTP 응답의 전체 내용을 제어할 수 있게 해줍니다.
더보기

RESTful은 웹 서비스 설계를 위한 아키텍처 스타일인 REST 원칙을 완벽히 준수하는 시스템을 의미합니다

 

3.3 HTTP 메서드별 구현 예시

  • GET 요청 처리

  역할: 서버에서 데이터를 조회합니다.
 응답: 성공 시 200 OK 상태 코드와 함께 사용자 데이터 (JSON/XML)

@GetMapping("/users/{id}")
public ResponseEntity<User> getUser(@PathVariable Long id) {
    User user = userService.findById(id);
    return ResponseEntity.ok(user);
}
  • POST 요청 처리

  역할: 새로운 리소스를 생성합니다.
 응답: 생성 완료 시 201 Created 상태 코드와 생성된 사용자 정보 반환

@PostMapping("/users")
public ResponseEntity<User> createUser(@RequestBody UserDto userDto) {
    User savedUser = userService.save(userDto);
    return ResponseEntity.status(HttpStatus.CREATED).body(savedUser);
}
  • PUT 요청 처리

 역할: 기존 리소스를 전체 수정합니다.
 응답: 성공 시 200 OK 상태 코드와 수정된 사용자 데이터 반환

@PutMapping("/users/{id}")
public ResponseEntity<User> updateUser(@PathVariable Long id, @RequestBody UserDto userDto) {
    User updatedUser = userService.update(id, userDto);
    return ResponseEntity.ok(updatedUser);
}
  • DELETE 요청 처리

  역할: 특정 리소스를 삭제합니다.
 응답: 성공 시 204 No Content (반환할 데이터 없음)

@DeleteMapping("/users/{id}")
public ResponseEntity<Void> deleteUser(@PathVariable Long id) {
    userService.delete(id);
    return ResponseEntity.noContent().build();
}


4. REST API 응답 처리

4.1 ResponseEntity 활용

ResponseEntity를 사용하면 HTTP 응답의 상태 코드, 헤더, 본문을 세밀하게 제어할 수 있습니다.

@GetMapping("/users")
public ResponseEntity<List<User>> getAllUsers() {
    List<User> users = userService.findAll();
    return ResponseEntity
    .ok()
    .header("Custom-Header", "value")
    .body(users);
}


4.2 예외 처리

예외 처리는 @ExceptionHandler를 사용하여 구현할 수 있습니다.
아래 방법을 통해 특정 예외에 대해 일관된 응답을 제공할 수 있습니다.

@ExceptionHandler(UserNotFoundException.class)
public ResponseEntity<ErrorResponse> handleUserNotFoundException(UserNotFoundException e) {
    ErrorResponse error = new ErrorResponse(HttpStatus.NOT_FOUND.value(), e.getMessage());
    return ResponseEntity.status(HttpStatus.NOT_FOUND).body(error);
}


5. API 문서화

  • Swagger/OpenAPI 활용
    • API 문서화는 개발자들이 API를 쉽게 이해하고 사용할 수 있게 해줍니다. Swagger는 이를 위한 강력한 도구입니다.
@Configuration
public class OpenAPIConfig {
    @Bean
    public OpenAPI customOpenAPI() {
        return new OpenAPI()
                .info(new Info()
                        .title("Your API Title")
                        .version("1.0")
                        .description("Your API Description"));
    }
}

이 설정으로 Swagger UI를 통해 API 문서를 자동으로 생성하고 테스트할 수 있습니다.

 

6. REST API 테스트 

테스트는 API의 신뢰성을 보장하는 중요한 단계입니다.

6.1 단위 테스트

이 테스트는 특정 사용자 조회 API의 동작을 검증합니다.

@WebMvcTest(UserController.class)
class UserControllerTest {
    @Autowired
    private MockMvc mockMvc;
    @Test
    void getUserTest() throws Exception {
        mockMvc.perform(get("/api/users/1"))
        .andExpect(status().isOk())
        .andExpect(jsonPath("$.name").value("John"));
    }
}


6.2 통합 테스트

이 통합 테스트는 실제 애플리케이션 컨텍스트에서 사용자 생성 API를 테스트합니다.

@SpringBootTest
class UserApiIntegrationTest {
    @Autowired
    private TestRestTemplate restTemplate;
    @Test
    void createUserTest() {
        UserDto userDto = new UserDto("John", "john@example.com");
        ResponseEntity<User> response = restTemplate.postForEntity("/api/users", userDto, User.class);
        assertEquals(HttpStatus.CREATED, response.getStatusCode());
    }
}

 

 7. 보안 처리

REST API의 보안은 매우 중요합니다. Spring Security를 사용하여 인증과 권한 부여를 구현할 수 있습니다. JWT를 이용한 토큰 기반 인증도 사용됩니다.

  • Spring Security와 JWT를 활용한 인증/인가 구현
  • CORS 설정으로 크로스 오리진 요청 제어


8. API 버전 관리

API 버전 관리는 기존 클라이언트에 영향을 주지 않고 API를 발전시킬 수 있게 해줍니다. URI, 헤더, 파라미터 등을 통해 버전을 관리할 수 있습니다.

  • URI 버전 관리: /api/v1/users
  • 헤더 버전 관리: Accept: application/vnd.company.app-v1+json


9. 성능 최적화

캐싱, 페이징, N+1 문제 해결 등을 통해 API의 성능을 최적화할 수 있습니다. 특히 대량의 데이터를 다룰 때 이러한 최적화는 필수적입니다.

  • 캐싱 전략: @Cacheable 어노테이션 활용
  • 페이징 처리: Spring Data JPA의 Pageable 인터페이스 사용
  • N+1 문제 해결: 적절한 fetch 전략과 쿼리 최적화


10. 모범 사례

REST API 설계 시 다음과 같은 모범 사례를 따르는 것이 좋습니다.

  • URI 설계: 명확하고 직관적인 URI 설계
  • HTTP 상태 코드: 적절한 상태 코드 사용 (200 OK, 201 Created, 204 No Content 등)
  • 에러 처리: 일관된 에러 응답 형식 사용
  • API 문서화: 충분한 API 문서화