API/실습

76. [JAVA] API 문서 문제 : JDBC -> JPA 진행 (1)

천재단미 2025. 1. 14. 17:28
728x90
반응형

 

 

문제

 

API 명세서

1. 음식점 API

 

1.1. 음식점 목록 조회

 

다양한 조건으로 음식점 목록을 검색하고 조회할 수 있는 API입니다.

  • URL: /api/v1/restaurants
  • Method: GET
  • 설명:
    • 페이징 처리된 음식점 목록을 반환합니다.
    • 카테고리 필터링과 키워드 검색을 지원합니다.
    • 음식점의 평균 평점과 리뷰 수를 포함합니다.
    • 최신 등록순으로 정렬됩니다.
  • Query Parameters:
page: 페이지 번호 (기본값: 1)
size: 페이지 크기 (기본값: 10)
category: 카테고리 필터 (선택) - 한식, 중식, 일식, 양식 등
keyword: 검색어 - 이름, 주소 검색 (선택, 최소 2글자 이상)

  • Response:
{
    "content": [
        {
            "id": 1,
            "name": "맛있는 식당",
            "category": "한식",
            "address": "서울시 강남구",
            "phone": "02-1234-5678",
            "description": "전통 한식집",
            "avgRating": 4.5,
            "reviewCount": 100,
            "createdAt": "2024-12-27T10:00:00"
        }
    ],
    "pageable": {
        "page": 1,
        "size": 10,
        "totalElements": 100,
        "totalPages": 10
    }
}

1.2. 음식점 상세 조회

특정 음식점의 상세 정보와 메뉴 목록을 조회하는 API입니다.

  • URL: /api/v1/restaurants/{id}
  • Method: GET
  • 설명:
    • 음식점의 기본 정보를 제공합니다.
    • 해당 음식점의 전체 메뉴 목록을 함께 반환합니다.
    • 평균 평점과 총 리뷰 수를 포함합니다.
    • 각 메뉴별 리뷰 수도 함께 제공됩니다.
    • 존재하지 않는 음식점 ID인 경우 404 에러를 반환합니다.
  • Response:
{
		"restaurant": {
		    "id": 1,
		    "name": "맛있는 식당",
		    "category": "한식",
		    "address": "서울시 강남구",
		    "phone": "02-1234-5678",
		    "description": "전통 한식집",
		    "avgRating": 4.5,
		    "reviewCount": 100,
		    "createdAt": "2024-12-27T10:00:00",
	  },
    "menus": [
        {
            "id": 1,
            "name": "김치찌개",
            "price": 8000,
            "description": "돼지고기 김치찌개",
            "category": "찌개",
            "reviewCount": 50
        }
    ]
}

2. 메뉴 API

2.1. 음식점별 메뉴 목록 조회

특정 음식점의 메뉴 목록을 조회하는 API입니다.

  • URL: /api/v1/restaurants/{restaurantId}/menus
  • Method: GET
  • 설명:
    • 특정 음식점의 전체 메뉴를 페이징 처리하여 제공합니다.
    • 카테고리별 필터링을 지원합니다.
    • 각 메뉴의 리뷰 수를 포함합니다.
    • 메뉴는 카테고리별, 가격순으로 정렬 가능합니다.
    • 존재하지 않는 음식점 ID인 경우 404 에러를 반환합니다.
  • Query Parameters:
page: 페이지 번호 (기본값: 1)
size: 페이지 크기 (기본값: 10)
category: 메뉴 카테고리 필터 (선택)
sort: 정렬 기준 (price_asc, price_desc, name_asc)

  • Response:
{
    "content": [
        {
            "id": 1,
            "name": "김치찌개",
            "price": 8000,
            "description": "돼지고기 김치찌개",
            "category": "찌개",
            "reviewCount": 50,
            "createdAt": "2024-12-27T10:00:00"
        }
    ],
    "pageable": {
        "page": 1,
        "size": 10,
        "totalElements": 50,
        "totalPages": 5
    }
}

3. 리뷰 API

3.1. 리뷰 작성

새로운 리뷰를 작성하는 API입니다.

  • URL: /api/v1/reviews
  • Method: POST
  • 설명:
    • 인증된 사용자만 리뷰를 작성할 수 있습니다.
    • 동일한 메뉴에 대해 한 사용자는 하나의 리뷰만 작성 가능합니다.
    • 리뷰 작성 시 해당 음식점의 평균 평점이 자동으로 갱신됩니다.
    • 음식점과 메뉴의 리뷰 카운트가 자동으로 증가합니다.
  • Request Header:
Authorization: Bearer {accessToken}

  • Request Body:
{
    "restaurantId": 1,
    "menuId": 1,
    "rating": 5,
    "content": "정말 맛있었습니다!"
}

  • Validation:
    • rating: 1-5 사이의 정수만 가능
    • content: 최소 10자 이상 작성
    • restaurantId: 유효한 음식점 ID
    • menuId: 해당 음식점의 유효한 메뉴 ID
  • Response:
  • 성공 201 문제있을경우 400

3.2. 리뷰 수정

기존 리뷰를 수정하는 API입니다.

  • URL: /api/v1/reviews/{id}
  • Method: PUT
  • 설명:
    • 리뷰 작성자만 수정이 가능합니다.
    • 리뷰 수정 시 음식점의 평균 평점이 자동으로 갱신됩니다.
    • 리뷰 내용과 평점만 수정 가능합니다.
    • 존재하지 않는 리뷰 ID인 경우 404 에러를 반환합니다.
  • Request Header:
Authorization: Bearer {accessToken}

  • Request Body:
{
    "rating": 4,
    "content": "맛있었지만 조금 짰어요"
}

  • Response:
  • 성공 200 문제있을경우 400

4. 사용자 API

4.1. 회원가입

새로운 사용자를 등록하는 API입니다.

  • URL: /api/v1/users/signup
  • Method: POST
  • 설명:
    • 새로운 사용자를 시스템에 등록합니다.
    • 이메일 중복 확인을 수행합니다.
    • 비밀번호는 암호화하여 저장됩니다.
    • 기본 사용자 권한(USER)으로 생성됩니다.
  • Request Body:
{
    "email": "user@example.com",
    "password": "password123",
    "nickname": "사용자닉네임"
}

  • Validation:
    • email: 유효한 이메일 형식 (@포함)
    • password: 최소 8자 이상, 영문/숫자/특수문자 조합
    • nickname: 2-20자 이내, 한글/영문/숫자 허용
  • Response:
    • 201

4.2. 로그인

사용자 인증을 위한 로그인 API입니다.

  • URL: /api/v1/users/login
  • Method: POST
  • 설명:
    • 이메일과 비밀번호로 사용자를 인증합니다.
    • 인증 성공 시 JWT 토큰을 발급합니다.
    • Access Token의 유효기간은 1시간입니다.
  • Request Body:
{
    "email": "user@example.com",
    "password": "password123"
}

  • Response:
{
    "token": "eyJhbGciOiJIUzI1NiJ9..."
}

 

공통 사항

 

1. 에러 처리

주요 에러 상황:

  • 400 Bad Request: 잘못된 요청 파라미터
  • 401 Unauthorized: 인증 실패 또는 토큰 만료
  • 403 Forbidden: 권한 없음
  • 404 Not Found: 리소스를 찾을 수 없음
  • 409 Conflict: 데이터 충돌 (예: 이메일 중복)
  • 500 Internal Server Error: 서버 오류

2. 페이징 처리

페이징이 적용된 모든 API는 다음 정보를 포함합니다:

  • page: 현재 페이지 번호 (1부터 시작)
  • size: 페이지당 항목 수
  • totalElements: 전체 데이터 수
  • totalPages: 전체 페이지 수

3. 인증

  • Bearer 토큰 방식의 JWT 인증을 사용합니다.
  • 인증이 필요한 API의 경우 반드시 Authorization 헤더에 토큰을 포함해야 합니다.

4. API 버전 관리

  • URI의 /api/v1 prefix로 API 버전을 관리합니다.
  • 향후 하위 호환성이 깨지는 변경사항이 있을 경우 버전이 변경될 수 있습니다.

 

풀이

 

4.1. 회원가입

새로운 사용자를 등록하는 API입니다.

  • URL: /api/v1/users/signup
  • Method: POST
  • 설명:
    • 새로운 사용자를 시스템에 등록합니다.
    • 이메일 중복 확인을 수행합니다.
    • 비밀번호는 암호화하여 저장됩니다.
    • 기본 사용자 권한(USER)으로 생성됩니다.

Postman

 

  • Request Body:

 

 

intelliJ

 

entity패키지생성 -  Use 클래스 생성 

 

@Data
@Entity
@Table(name = "user")
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    public Long id;

    @Column(length = 100, unique = true)
    public String email;
    @Column(length = 256)
    public String password;
    @Column(length = 100)
    public String nickname;
    @Column(length = 100)
    public String role;
    @Column
    public Instant createdAt;
    @PrePersist
    public void prePersist() {
        createdAt = Instant.now();
    }
}

 

 

 

@어노테이션 설명 

클래스 레벨

 

@Entity

  • 설명: 해당 클래스가 JPA 엔티티임을 선언합니다. JPA는 이 클래스를 데이터베이스의 테이블로 매핑합니다.
  • 적용 대상: 클래스
  • 예시: User 클래스는 데이터베이스의 user 테이블과 연결됩니다.

@Table

  • 설명: 데이터베이스 테이블의 이름을 명시적으로 지정합니다. 지정하지 않으면 클래스 이름을 테이블 이름으로 사용합니다.
  • 속성:
    • name: 테이블 이름을 지정.
  • 예시: @Table(name = "user")는 이 클래스가 user 테이블과 매핑된다는 것을 명시합니다.

필드 레벨

 

@Id

  • 설명: 해당 필드를 엔티티의 기본 키(primary key)로 지정합니다.
  • 적용 대상: 필드 또는 메서드.
  • 예시: id 필드는 데이터베이스의 기본 키로 사용됩니다.

@GeneratedValue

  • 설명: 기본 키 값 생성 전략을 지정합니다.
  • 속성:
    • strategy: 기본 키 생성 전략을 지정.
      • GenerationType.IDENTITY: 데이터베이스에 의해 자동으로 생성됩니다 (예: MySQL의 AUTO_INCREMENT).
  • 예시: @Id @GeneratedValue(strategy = GenerationType.IDENTITY)는 기본 키를 데이터베이스에서 자동으로 생성하도록 설정합니다.

@Column

  • 설명: 데이터베이스 테이블의 열(column)을 매핑합니다.
  • 속성:
    • length: 문자열의 최대 길이를 지정.
    • unique: 고유 값 제약 조건 설정.
  • 예시:
    • @Column(length = 100, unique = true)는 email 열의 길이를 100으로 제한하고 고유 값 제약 조건을 추가합니다.
    • @Column(length = 256)은 password 열의 최대 길이를 256으로 지정합니다.

메서드 레벨

 

@PrePersist

  • 설명: 엔티티가 저장되기 전에 실행되는 메서드에 적용됩니다.
  • 용도: 자동으로 생성/저장되는 데이터 초기화에 사용됩니다.
  • 예시: prePersist() 메서드는 엔티티가 데이터베이스에 저장되기 전에 createdAt 필드에 현재 시간을 설정합니다.

Lombok 어노테이션

 

@Data

  • 설명: Lombok에서 제공하는 어노테이션으로, 여러 필수 메서드를 자동으로 생성합니다.
  • 자동 생성되는 메서드:
    • Getter/Setter: 모든 필드에 대해 getter와 setter를 생성.
    • toString(): 객체 정보를 문자열로 반환하는 메서드.
    • hashCode() & equals(): 객체 비교에 사용하는 메서드.
    • RequiredArgsConstructor: final이나 @NonNull 필드에 대한 생성자.
  • 적용 대상: 클래스.
  • 예시: @Data는 User 클래스에 대해 필수 메서드들을 자동 생성합니다.

코드의 동작 과정

  1. 엔티티 생성: User 객체 생성.
  2. 데이터 저장: JPA가 @PrePersist가 붙은 메서드를 호출하여 createdAt을 설정.
  3. 테이블 매핑: @Entity와 @Table에 따라 데이터가 user 테이블에 저장.

 

controller 패키지 생성 - UserController 클래스 생성 

 

    @PostMapping("/api/v1/users/signup")
    signUp(@RequestBody UserRequest userRequest) {
   
            userService.signUp(userRequest);
    
        }
    }

 

 

      signUp(UserRequest userRequest) {
        // 이미 회원가입 했는지 확인
        if (userRepository.existsByEmail(userRequest.email)) {
            throw new RuntimeException();
        }
        // 비번을 암호화
        userRequest.password = passwordEncoder.encode(userRequest.password);

    }

 

 

repository패키지 -  RestauantRepository클래스 생성 

 

@Repository
public interface UserRepository extends JpaRepository<User, Long> {

    public Boolean existsByEmail(String email);

}

 

 

  • Request Body:
{
    "email": "user@example.com",
    "password": "password123",
    "nickname": "사용자닉네임"
}

  • Validation:
    • email: 유효한 이메일 형식 (@포함)
    • password: 최소 8자 이상, 영문/숫자/특수문자 조합
    • nickname: 2-20자 이내, 한글/영문/숫자 허용
 

DTO 클래스 생성 팁 

AI 를 활용하여 간단하게 dto 클래스를 생성할 수 있습니다. 

 

아래 예시의 경우 chatGPT를 이용하여 생성한 dto 클래스 입니다. 

 

예시) 

public class UserRequest {

    @Email(message = "Invalid email format")
    @NotBlank(message = "Email is required")
    private String email;

    @NotBlank(message = "Password is required")
    @Size(min = 8, message = "Password must be at least 8 characters")
    @Pattern(regexp = "^(?=.*[A-Za-z])(?=.*\\d)(?=.*[!@#$%^&*(),.?\":{}|<>])[A-Za-z\\d!@#$%^&*(),.?\":{}|<>]{8,}$",
             message = "Password must contain at least one letter, one number, and one special character")
    private String password;

    @NotBlank(message = "Nickname is required")
    @Size(min = 2, max = 20, message = "Nickname must be between 2 and 20 characters")
    @Pattern(regexp = "^[a-zA-Z0-9가-힣]{2,20}$", message = "Nickname can only contain letters, numbers, and Korean characters")
    private String nickname;

 

dto 패키지 생성 - UserRequest 클래스 생성 

 

 

@Data
@NoArgsConstructor
@AllArgsConstructor
public class UserRequest {

    @Email
    public String email;

    @Pattern(regexp = "^(?=.*[a-zA-Z])(?=.*\\\\d)(?=.*[@$!%*?&])[A-Za-z\\\\d@$!%*?&]{8,}$")
    public String password;

    @Size(min = 2, max = 20)
    @Pattern(regexp = "^[a-zA-Z0-9가-힣]+$")
    public String nickname;
}

 

  • Response:
    • 201
    public void signUp(UserRequest userRequest) {
        // 이미 회원가입 했는지 확인
        if (userRepository.existsByEmail(userRequest.email)) {
            throw new RuntimeException();
        }
        // 비번을 암호화
        userRequest.password = passwordEncoder.encode(userRequest.password);

        // DB에 저장.
        // DTO 를 entity로 만들어준다.
        User user = new User();
        user.email = userRequest.email;
        user.password = userRequest.password;
        user.nickname = userRequest.nickname;
        user.role = "USER";
        userRepository.save(user);

    }

 

    @PostMapping("/api/v1/users/signup")
    public ResponseEntity<Object> signUp(@RequestBody UserRequest userRequest) {
        try {
            userService.signUp(userRequest);
            return ResponseEntity.status(201).build();
        } catch (Exception e) {
            return ResponseEntity.status(400).build();
        }
    }

 

 

Postman

 

4.2. 로그인

사용자 인증을 위한 로그인 API입니다.

  • URL: /api/v1/users/login
  • Method: POST
  • 설명:
    • 이메일과 비밀번호로 사용자를 인증합니다.
    • 인증 성공 시 JWT 토큰을 발급합니다.
    • Access Token의 유효기간은 1시간입니다.

Postman

 

{
    "email": "user@example.com",
    "password": "password123"
}

 

intelliJ

    @PostMapping("/api/v1/users/signup")
     signUp(@RequestBody UserRequest userRequest) {
        
            userService.signUp(userRequest);
    

 

 

 

   login(UserRequest userRequest) {

        // 1. 이메일로 유저가 있는지 확인한다.
        if (!userRepository.existsByEmail(userRequest.email)) {
            throw new RuntimeException();
        }
        // 2. 테이블에 이 이메일로 유저가 있어야 한다. 유저데이터를 가져온다
        User user = userRepository.findByEmail(userRequest.email);
        // 3. DB 에서 가져온 비밀번호와 입력된 비밀번호가 같은지 확인한다.
        if (!passwordEncoder.matches(userRequest.password, user.password)) {
            throw new RuntimeException();
        }
        // 3. 토큰을 생성한다.
        String token = jwtConfig.createToken(user.id);
   

 

 

 

  • Response:
{
    "token": "eyJhbGciOiJIUzI1NiJ9..."
}

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

728x90
반응형
home top bottom
}