본문 바로가기
쿤즈 프로젝트/To-do List Application

[Spring Boot] To-Do List 애플리케이션: Chap5. API 계층별 구현 (1) 모든 할 일 조회

by Koonz:) 2024. 7. 15.
728x90

앞선 글에서는 API를 만들기 전 프로젝트의 기획과 설계, 그리고 데이터 모델링까지 함께 진행해 보았습니다. 무엇을 만들지를 정하고 데이터를 어떻게 저장할 것인지를 구성했어요.

 

이번 글에서는 To-Do List 애플리케이션의 각 API를 계층별로 구현하는 방법을 다루겠습니다. 우리는 Spring Boot를 사용하여 Restfull API를 만들 것이며, 이를 위해 프로젝트 구조 설정, 계층별 역할 설명, Restfull API의 개요, 주요 API 설계에 대해 자세히 살펴보겠습니다.


프로젝트 구조 설정

Spring Boot 프로젝트를 효과적으로 관리하기 위해서는 프로젝트 구조를 잘 설계하는 것이 중요합니다. 다음은 기본적인 프로젝트 구조입니다.

src/main/java
└── com.koonsland.todo
    ├── controller
    │   └── ToDoItemController.java
    ├── model
    │   └── ToDoItem.java
    ├── repository
    │   └── ToDoItemRepository.java
    ├── service
    │   └── ToDoItemService.java
    └── TodoApplication.java

 

Controller: 클라이언트의 요청을 처리하고 응답을 반환하는 컨트롤러 클래스가 위치합니다. 실제 요청을 받을 수 있는 API 클래스들을 만들 수 있습니다.

Service: 비즈니스 로직을 구현하는 서비스 클래스가 위치합니다. 비즈니스 로직은 데이터를 저장, 조회, 수정, 삭제 기능을 호출하는 로직들을 담는 클래스들입니다.

Repository: 데이터베스와의 상호작용을 처리하는 Repository 인터페이스가 위치합니다.

Model: 데이터베이스 테이블과 매핑되는 엔티티 클래스가 위치합니다.


계층별 역할 설명

각 계층의 역할을 이해하는 것은 애플리케이션을 설계하고 유지보수하는 데 중요합니다.

 

LAYERED
LAYERED
Controller
Controller
Service
Service
Model
Model
Repository
Repository
koonsland.tistory.com
koonsland.tistory.com
Spring Boot Layered
Spring Boot Layered
Database
Database
Text is not SVG - cannot display

Controller 계층

Controller 계층은 클라이언트의 HTTP 요청을 처리하고, 적절한 서비스 계층을 호출하여 응답을 생성합니다. Spring MVC(Model View Controller)의 @RestController 어노테이션을 사용하여 Restfull 웹 서비스를 구현합니다. 주요 기능은 다음과 같습니다.

  • 요청 수신: 사용자(클라이언트)가 보낸 HTTP 요청을 수신합니다.
  • 요청 검증: 요청의 유효성을 검증합니다.
  • 서비스 호출: 요청을 처리하기 위해 Service 계층의 메서드를 호출합니다.
  • 응답 반환: 처리 결과를 사용자에게 응답으로 반환합니다. JSON, HTML, XML 등 다양한 형식의 응답을 제공합니다.
  • 라우팅: URL 경로와 해당 요청을 처리할 메서드를 매핑합니다.

Service 계층

Service 계층은 비즈니스 로직을 구현하는 계층입니다. 데이터베스와의 상호작용을 처리하고, 필요한 데이터 변환 및 검증을 수행합니다. 일반적으로 @Service 어노테이션을 사용하여 서비스 클래스를 정의합니다. 주요 기능은 다음과 같습니다.

  • 비즈니스 로직 처리: 요청에 따른 비즈니스 규칙을 적용하고 데이터를 처리합니다.
  • 데이터 조작: Repository 계층을 통해 데이터를 조회, 저장, 삭제 등의 작업을 합니다.
  • 트랜잭션 관리: 여러 데이터 조작 작업을 하나의 트랜잭션으로 묶어 관리합니다.
  • 서비스 통합: 여러 다른 서비스들과 통합하여 작업을 수행합니다.

Repository 계층

Repository 계층은 데이터베이스에 접근하여 CRUD 작업을 수행하는 계층입니다. Spring Data JPA의 JpaRepository 인터페이스를 상속받아 리포지토리를 정의합니다. 주요 기능은 다음과 같습니다.

  • 데이터 접근: 데이터베이스로부터 데이터를 조회하고, 저장하고, 수정하고, 삭제하는 작업을 수행합니다.
  • 쿼리 작성: 필요한 데이터를 가져오기 위한 쿼리를 작성합니다. (JPQL, SQL 등)
  • 데이터 매핑: 데이터베이스의 데이터를 애플리케이션의 도메인 객체로 변환합니다.

Model 계층

Model 계층은 데이터베이스 테이블과 매핑되는 엔티티 클래스를 정의하는 계층입니다. JPA 어노테이션을 사용하여 엔티티 클래스를 매핑합니다. 주요 기능은 다음과 같습니다.

  • 데이터 구조 정의: 애플리케이션에서 사용되는 데이터 구조를 정의합니다.
  • 데이터 매핑: 데이터베이스의 테이블과 매핑됩니다.
  • 비즈니스 룰 포함: 간단한 비즈니스 룰이나 유효성 검증을 포함할 수 있습니다.

REST API 개요

Restful API는 클라이언트와 서버 간의 상호작용을 위한 인터페이스를 정의합니다. Restful API는 HTTP 메서드를 사용하여 CRUD 작업을 처리하며, 각각의 메서드는 다음과 같은 작업을 수행합니다.

  • GET: 서버로부터 리소스를 조회합니다.
  • POST: 서버에 새로운 리소스를 생성합니다.
  • PUT/PATCH: 서버의 기존 리소스를 수정합니다.
  • DELETE: 서버의 기존 리소를 삭제합니다.

Restful API의 디자인 원칙은 일관성 있고 확장 가능한 인터페이스를 제공합니다. 이를 통해 클라이언트와 서버 간의 통신을 간편하게 처리할 수 있습니다.


모든 할 일 조회 API 구현

이제부터 실제 API를 구현하고 테스트해 보도록 할게요. 가장 먼저 모든 할 일을 조회하는 API를 구현해 보도록 하겠습니다. 이 API는 클라이언트가 저장된 모든 할 일 목록을 조회할 수 있도록 합니다.


프로젝트 구조 설정

먼저 프로젝트 구조는 다음과 같습니다.

src/main/java
└── com.koonsland.todo
    ├── controller
    │   └── ToDoItemController.java
    ├── model
    │   └── ToDoItem.java
    ├── repository
    │   └── ToDoItemRepository.java
    ├── service
    │   └── ToDoItemService.java
    └── TodoApplication.java

ToDoItem 엔티티 클래스

TodoItem 엔티티는 데이터베이스 테이블과 매핑되는 클래스입니다. 이 클래스는 할 일의 각 속성을 정의합니다.

package com.koonsland.todo.model;

import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.PrePersist;
import jakarta.persistence.PreUpdate;
import jakarta.persistence.Table;

import java.time.LocalDateTime;

@Entity
@Table(name = "todo_item")
public class ToDoItem {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id")
    private Long id;

    @Column(name = "title", nullable = false)
    private String title;

    @Column(name= "description", length = 500)
    private String description;

    @Column(name = "created_at", nullable = false, updatable = false)
    private LocalDateTime createdAt;

    @Column(name = "updated_at")
    private LocalDateTime updatedAt;

    @PrePersist
    protected void onCreate() {
        LocalDateTime now = LocalDateTime.now();
        this.createdAt = now;
        this.updatedAt = now;
    }

    @PreUpdate
    protected void onUpdate() {
        this.updatedAt = LocalDateTime.now();
    }

    // Getters
    // Setters 생성 안함 (필요한 비즈니스 메서드만 생성 예정)
    public Long getId() {
        return id;
    }

    public String getTitle() {
        return title;
    }

    public String getDescription() {
        return description;
    }

    public LocalDateTime getCreatedAt() {
        return createdAt;
    }

    public LocalDateTime getUpdatedAt() {
        return updatedAt;
    }
}

 

🧑🏻‍💻 Lombok 롬복
롬복을 사용하면 Getter, Setter를 사용하지 않고 어노테이션만으로 줄일 수 있습니다. 다만 이 프로젝트는 가장 기본적인 내용으로 진행 중이며 롬복을 알기 전에 어떤 메서드들로 구성되고 수정해야 하는지 알기 위해 사용하지 않고 진행합니다.

ToDoItemRepository 인터페이스

ToDoItem 엔티티를 만들어 보았습니다. 엔티티는 데이터와 매핑되는 클래스이지만 실제로 데이터를 넣고 뺄 수 없기 때문에 데이터베이스와 상호작용하는 클래스가 필요하며, 이는 Data JPA를 사용하여 간단하게 만들어서 진행하겠습니다.

package com.koonsland.todo.repository;

import com.koonsland.todo.model.ToDoItem;
import org.springframework.data.jpa.repository.JpaRepository;

public interface ToDoItemRepository extends JpaRepository<ToDoItem, Long> {
}

 

ToDoItemRepository 인터페이스를 만들고 JpaRepository 인터페이스를 상속받아서 사용합니다.

JpaRepository 인터페이스

 

JpaRepository 인터페이스는 제너릭으로 만들어져 있으며 T는 데이터와 매핑되는 엔티티 클래스를 의미하고 ID는 엔티티 클래스의 Id Type을 의미합니다. ToDoItem 클래스에서 @Id 어노테이션을 달아준 필드의 타입이 Long 이므로 ToDoItemRepository를 만들고 JpaRepository를 상속받을 때는 ToDoItem과 Long을 넣어서 상속받아 줍니다.

 

이로써 기본적인 CRUD 메서드는 구현 없이 끝나게 됩니다. 이유는 JpaRepository 인터페이스의 구현체에 이미 기본적인 메서드가 모두 정의가 되어 있기 때문입니다.


TodoItemService 클래스

데이터와 매핑되는 엔티티 클래스, 실제도 데이터베이스와 상호작용하여 CRUD를 하는 Repository 클래스를 만들어 보았습니다. 이제는 실제 비즈니스 로직에 해당하는 서비스 클래스를 구현해 보도록 할게요.

package com.koonsland.todo.service;

import com.koonsland.todo.model.ToDoItem;
import com.koonsland.todo.repository.ToDoItemRepository;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
public class ToDoItemService {

    private final ToDoItemRepository toDoItemRepository;

    public ToDoItemService(ToDoItemRepository toDoItemRepository) {
        this.toDoItemRepository = toDoItemRepository;
    }

    /**
     * 모든 할 일 조회
     */
    public List<ToDoItem> findAll() {
        return toDoItemRepository.findAll();
    }
}

 

서비스를 나타내는 클래스들은 @Service 어노테이션을 붙여줍니다.

 

💡컴포넌트 (Component)
@Controller, @Service, @Repository와 같은 어노테이션은 스프링의 구성 요소를 정의하는 데 사용됩니다. 이는 스프링 컴포넌트 스캔 대상을 의미하며 스프링 컨테이너 빈(Bean)으로 등록됩니다. 이들은 모두 @Component 어노테이션이 포함되어 있습니다. 각각은 역할 분리를 위해 어노테이션으로 구분하며 의존성 주입을 뜻하는 DI(Dependency Injenction) 메커니즘을 통해 다른 빈들과 협력할 수 있습니다.

 

서비스 클래스에서는 ToDoItem 목록들을 전체 조회 하는 기능의 메서드를 만들어 줍니다. 앞서 만들어 두었던 리포지토리를 먼저 생성자를 통해서 주입받고 findAll() 메서드에서 findAll() 메서드를 호출합니다. 이 메서드는 모든 ToDoItem 목록들을 조회하는 기능입니다. 그리고 이 메서드를 호출하면 List <ToDoItem> 타입으로 리턴해줍니다.


ToDoItemController 클래스

ToDoItemController 클래스는 클라이언트의 요청을 처리하고 모든 할 일의 목록을 반환하는 Rest API를 만들어 보도록 하겠습니다.

package com.koonsland.todo.controller;

import com.koonsland.todo.model.ToDoItem;
import com.koonsland.todo.service.ToDoItemService;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

@RestController
@RequestMapping("/api/todos")
public class ToDoItemController {

    private final ToDoItemService toDoItemService;

    public ToDoItemController(ToDoItemService toDoItemService) {
        this.toDoItemService = toDoItemService;
    }

    /**
     * 모든 ToDoItem 조회
     */
    @GetMapping
    public List<ToDoItem> getAllToDoItems() {
        return toDoItemService.findAll();
    }
}

 

컨트롤러 클래스에서는 @RestController 어노테이션을 붙여주고, 어떠한 경로를 통해서 요청을 받을지 @RequestMapping 어노테이션을 통해서 API의 경로를 정해줍니다. 이 프로젝트는 /api/todos라는 경로를 통해서 API의 요청을 받도록 하겠습니다.

 

실제 요청을 받는 메서드는 @GetMapping 어노테이션을 붙은 getAllToDoItems() 메서드이며 @GetMapping 어노테이션의 별도 경로가 없으므로 기본 경로인 /api/todos 경로를 통해서 요청이 들어오면 처리합니다.

 

이제 각 레이어별로 ToDoItem을 전체조회하는 기능 구현은 끝났습니다.


API 테스트

모든 할 일 조회 API를 테스트하기 위해 Postman 앱을 사용할 수 있습니다.

 

웹사이트: https://www.postman.com

 

Postman API Platform | Sign Up for Free

Postman is an API platform for building and using APIs. Postman simplifies each step of the API lifecycle and streamlines collaboration so you can create better APIs—faster.

www.postman.com

 

앱을 설치하고 테스트를 진행해 볼게요.

Postman 할 일 전체 조회 API 데이터 X

 

Postman 앱을 실행하여 API 만들기를 선택하여 할 일 전체 조회 API를 만들어 줍니다.

메서드는 GET이며 주소는 localhost:8080/api/todos로 입력하고 Send 버튼을 누르면 아래 Status: 200 OK와 함께 정상적으로 호출되는 것을 볼 수 있습니다. 데이터를 몇 개 넣어서 다시 한번 호출해 보겠습니다.

Postman 할 일 전체 조회 API 데이터 O

 

H2 콘솔을 이용해서 데이터를 넣고 다시 조회한 결과입니다. 정상적으로 데이터가 조회되는 것을 확인할 수 있습니다.


이번 글에서는 To-Do List 애플리케이션의 모든 할 일을 조회하는 API를 구현하는 방법을 설명했습니다. 프로젝트 구조 설정, Controller, Service, Repository 계층 구현 및 엔티티 정의를 통해 API를 완성했습니다. 또 각각의 레이어의 역할과 실제 구현을 진행하고 완성된 기능을 간단하게 Postman을 통해서 테스트도 해보았습니다.

 

이 글을 통해서 모든 할 일 조회 API를 구현하는 방법을 명확하게 이해할 수 있길 바랍니다. 다음 글에서는 특정 ID의 할 일을 조회하는 API를 구현해 보도록 할게요. 추가적으로 필요하거나 궁금한 사항이 있다면 댓글로 남겨주세요. 도움이 되시길 바랍니다. 감사합니다. 🙇🏻

 

이전 글

2024.06.16 - [쿤즈 프로젝트/To-do List Application] - [Spring Boot] To-Do List 애플리케이션: Chap1. 프로젝트 소개

 

[Spring Boot] To-Do List 애플리케이션: Chap1. 프로젝트 소개

이번 시리즈에서는 Spring Boot 3 버전을 사용해서 간단하게 To-Do List 애플리케이션을 만드는 프로젝트를 진행하려 합니다. 그래서 이 포스팅에서는 애플리케이션을 만드는 방법을 단계별로 소개할

koonsland.tistory.com

2024.06.20 - [쿤즈 프로젝트/To-do List Application] - [Spring Boot] To-Do List 애플리케이션: Chap2. 요구사항 정리

 

[Spring Boot] To-Do List 애플리케이션: Chap2. 요구사항 정리

지난 Chap1에서는 To-Do List 애플리케이션에 대해서 어떤 것을 만들고 어떤 과정으로 프로젝트를 진행하겠다는 계획에 대해서 정리했습니다. 또한 To-Do List 애플리케이션과 같은 기능을 가진 앱들

koonsland.tistory.com

2024.06.26 - [쿤즈 프로젝트/To-do List Application] - [Spring Boot] To-Do List 애플리케이션: Chap3. 기본 프로젝트 설정

2024.06.27 - [쿤즈 프로젝트/To-do List Application] - [Spring Boot] To-Do List 애플리케이션: Chap4. 데이터 모델링

 

댓글