본문 바로가기
Spring/10. rest-api

REST API 예제

by 989898 2025. 3. 14.

📌 1. 기본 CRUD API

 설명

CRUD(Create, Read, Update, Delete)는 REST API의 핵심 기능입니다. 이 예제는 사용자(User) 데이터를 관리하는 간단한 CRUD API를 제공합니다.

주요 메서드 설명

  • GET: 모든 사용자 조회
    • ResponseEntity.ok(users)는 상태 코드 200 OK와 함께 사용자 리스트를 반환합니다.
    • 클라이언트는 모든 사용자 데이터를 JSON 형식으로 받을 수 있습니다.
@GetMapping
public ResponseEntity<List<User>> getAllUsers() {
    List<User> users = new ArrayList<>(userRepository.values());
    return ResponseEntity.ok(users);
}
  • GET: 특정 사용자 조회
    • @PathVariable을 사용하여 URL 경로에서 사용자 ID를 추출합니다.
    • 사용자가 존재하지 않으면 상태 코드 404 Not Found와 함께 에러 메시지를 반환합니다.
@GetMapping("/{id}")
public ResponseEntity<?> getUserById(@PathVariable Long id) {
    User user = userRepository.get(id);
    if (user == null) {
        return ResponseEntity.status(HttpStatus.NOT_FOUND)
                .body("User with ID " + id + " not found");
    }
    return ResponseEntity.ok(user);
}
  • POST: 새 사용자 생성
    • @RequestBody를 사용하여 클라이언트가 보낸 JSON 데이터를 Java 객체(User)로 역직렬화합니다.
    • 새로 생성된 사용자의 ID를 설정하고 저장한 후 상태 코드 201 Created와 함께 반환합니다.
@PostMapping
public ResponseEntity<User> createUser(@RequestBody User user) {
    user.setId(idCounter++);
    userRepository.put(user.getId(), user);
    return ResponseEntity.status(HttpStatus.CREATED).body(user);
}
  •  
  • PUT: 기존 사용자 수정
    • 전체 덮어쓰기를 수행하며, 클라이언트가 보낸 데이터로 기존 데이터를 완전히 대체합니다.
    • 수정된 사용자 데이터를 상태 코드 200 OK와 함께 반환합니다.
@PutMapping("/{id}")
public ResponseEntity<?> updateUser(@PathVariable Long id, @RequestBody User updatedUser) {
    User existingUser = userRepository.get(id);
    if (existingUser == null) {
        return ResponseEntity.status(HttpStatus.NOT_FOUND)
                .body("User with ID " + id + " not found");
    }
    updatedUser.setId(id);
    userRepository.put(id, updatedUser);
    return ResponseEntity.ok(updatedUser);
}
  •  
  • DELETE: 사용자 삭제
    • 삭제 성공 시 상태 코드 204 No Content를 반환하며, 응답 본문은 비어 있습니다.
@DeleteMapping("/{id}")
public ResponseEntity<?> deleteUser(@PathVariable Long id) {
    User existingUser = userRepository.remove(id);
    if (existingUser == null) {
        return ResponseEntity.status(HttpStatus.NOT_FOUND)
                .body("User with ID " + id + " not found");
    }
    return ResponseEntity.noContent().build();
}
  •  

📌 2. Error Handling 및 Custom Response

 설명

이 예제는 요청 처리 중 발생하는 에러를 명확히 전달하기 위해 커스텀 응답(ErrorResponse)을 사용합니다.

주요 메서드 설명

@GetMapping("/{id}")
public ResponseEntity<?> getProductById(@PathVariable Long id) {
    String product = productRepository.get(id);
    if (product == null) {
        ErrorResponse errorResponse = new ErrorResponse(
            "Product with ID " + id + " not found",
            HttpStatus.NOT_FOUND.value()
        );
        return ResponseEntity.status(HttpStatus.NOT_FOUND).body(errorResponse);
    }
    return ResponseEntity.ok(product);
}
 
  • 에러 발생 시 ErrorResponse 객체를 생성하여 클라이언트에게 반환합니다.
  • 상태 코드 404 Not Found와 함께 JSON 형식의 에러 메시지를 전달합니다:
{
    "message": "Product with ID 3 not found",
    "statusCode": 404
}
  •  

📌 3. Pagination API

 설명

페이징은 대량의 데이터를 클라이언트에게 효율적으로 전달하기 위해 사용됩니다. 이 예제는 페이지 번호와 페이지 크기를 받아 데이터를 나누어 반환합니다.

주요 메서드 설명

@GetMapping
public ResponseEntity<?> getItems(
        @RequestParam(defaultValue = "0") int page,
        @RequestParam(defaultValue = "5") int size) {

    int startIndex = page * size;
    int endIndex = Math.min(startIndex + size, items.size());

    if (startIndex >= items.size()) {
        return ResponseEntity.status(HttpStatus.BAD_REQUEST)
                .body("Invalid page number");
    }

    List<String> paginatedItems = items.subList(startIndex, endIndex);

    Map<String, Object> response = new HashMap<>();
    response.put("items", paginatedItems);
    response.put("currentPage", page);
    response.put("pageSize", size);

    return ResponseEntity.ok(response);
}
 
  • @RequestParam으로 페이지 번호(page)와 페이지 크기(size)를 받습니다.
  • 데이터 범위를 계산하여 해당 페이지의 데이터를 반환합니다.
  • 잘못된 페이지 번호가 주어지면 상태 코드 400 Bad Request를 반환합니다.

📌 4. File Upload API

 설명

파일 업로드는 REST API에서 자주 사용되는 기능입니다. 이 예제는 클라이언트가 파일을 업로드하면 성공 메시지와 파일 이름을 반환합니다.

주요 메서드 설명

@PostMapping("/upload")
public ResponseEntity<?> uploadFile(@RequestParam("file") MultipartFile file) {
    if (file.isEmpty()) {
        return ResponseEntity.status(HttpStatus.BAD_REQUEST)
                .body("File is empty");
    }

    String fileName = file.getOriginalFilename();

    Map<String, String> response = new HashMap<>();
    response.put("message", "File uploaded successfully");
    response.put("fileName", fileName);

    return ResponseEntity.ok(response);
}
 
  • @RequestParam으로 파일 데이터를 받습니다.
  • 파일 이름과 성공 메시지를 JSON 형식으로 반환합니다:
{
    "message": "File uploaded successfully",
    "fileName": "example.txt"
}
  •  

📌 5. HATEOAS 적용 API

 설명

HATEOAS(Hypermedia As The Engine Of Application State)는 REST API에서 링크를 통해 클라이언트가 다음 가능한 작업을 탐색할 수 있도록 합니다.

주요 메서드 설명

@GetMapping("/{id}")
public ResponseEntity<?> getCustomerById(@PathVariable Long id) {
    String customer = customerRepository.get(id);

    if (customer == null) {
        return ResponseEntity.status(HttpStatus.NOT_FOUND)
                .body("Customer with ID " + id + " not found");
    }

    Map<String, Object> response = new HashMap<>();
    
    response.put("name", customer);

    Map<String, String> links = new HashMap<>();
    
    links.put("self", "/api/v1/customers/" + id);
    
    links.put("updateCustomer", "/api/v1/customers/" + id + "/update");
    
    response.put("_links", links);

    return ResponseEntity.ok(response);
}
 
  • 응답에 _links 필드를 추가하여 클라이언트가 다음 작업을 탐색할 수 있도록 합니다:
{
    "name": "Alice",
    "_links": {
        "self": "/api/v1/customers/1",
        "updateCustomer": "/api/v1/customers/1/update"
    }
}
  •  

📌 🎯 학습 포인트

  1. 기본 CRUD 작업을 통해 REST API의 구조 이해하기.
  2. 커스텀 에러 응답과 상태 코드 활용하기.
  3. 페이징 처리로 대량 데이터 관리 방법 배우기.
  4. 파일 업로드 API로 멀티파트 데이터 처리 익히기.
  5. HATEOAS로 링크 기반 탐색 기능 구현하기.

이 예제들을 실행하고 Postman 또는 다른 HTTP 클라이언트를 활용해 요청을 보내면서 동작을 확인하면 REST API 설계와 구현에 대한 깊은 이해를 얻을 수 있습니다! 😊