-
Notifications
You must be signed in to change notification settings - Fork 0
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[1 - 3단계 방탈출 사용자 예약] 재즈(함석명) 미션 제출합니다. #4
base: seokmyungham
Are you sure you want to change the base?
Changes from all commits
e9839c2
da08d06
035c771
084c8a8
ddbd79f
fe2d58d
39d5385
ef02237
05bf12d
1c8ca4d
f6ddf1c
d3fea55
0915bd4
1c9957e
af3fa40
ea5a8a6
f65e2a6
b7561fa
cb936aa
bddf8c0
ffe91f3
d9cb606
68562ec
03b2a6d
855c386
9acebf3
950583f
6a45b7d
79c3649
befb697
df1d0d5
74f87ee
3d9a043
d1937cc
e81ab58
5cf59c2
b7af5a2
ff15845
671017c
d4201ba
ea1d1fa
ea4db56
1b981df
509b904
19ae311
c18a929
5a93fc4
2303839
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,263 @@ | ||
# 기능 명세 | ||
|
||
## Admin | ||
|
||
- [X] `localhost:8080/admin` 요청 시 어드민 메인 페이지를 응답한다. | ||
- [X] `/admin/reservation` 요청 시 예약 관리 페이지를 응답한다. | ||
- [X] `/admin/time` 요청 시 시간 관리 페이지를 응답한다. | ||
|
||
## Reservation | ||
|
||
- [X] `/reservations` `GET` 요청 시 예약 목록을 조회하고 API 명세에 맞게 응답을 반환한다. | ||
- [X] `/reservations` `POST` 요청 시 예약을 추가하고 API 명세에 맞게 응답을 반환한다. | ||
- [x] 예약자 명, 테마 아이디, 예약 날짜, 시간 아이디가 비어있으면 예외를 발생시키고 상태코드 400을 반환한다. | ||
- [x] 예약 날짜가 형식에 맞지 않는다면 예외를 발생시키고 상태코드 400을 반환한다. | ||
- [x] 테마 아이디가 자연수가 아니라면 예외를 발생시키고 상태코드 400을 반환한다. | ||
- [x] 예약 시간 아이디가 자연수가 아니라면 예외를 발생시키고 상태코드 400을 반환한다. | ||
- [x] 현재보다 이전 날짜 및 시간이라면 예외를 발생시키고 상태코드 400을 반환한다. | ||
- [x] 예약 시간 아이디가 시간 테이블에 없으면 예외를 발생시키고 상태코드 400을 반환한다. | ||
- [x] 해당 테마에 같은 날짜와 시간의 예약이 존재하면 예외를 발생시키고 상태코드 400을 반환한다. | ||
- [X] `/reservations/{id}` `DELETE` 요청 시 예약을 삭제하고 API 명세에 맞게 응답을 반환한다. | ||
- [x] 존재하지 않는 아이디를 삭제하려고 하면 예외를 발생시키고 상태코드 400을 반환한다. | ||
|
||
## Time | ||
|
||
- [X] `/times` `GET` 요청 시 시간 목록을 조회하고 API 명세에 맞게 응답을 반환한다. | ||
- [X] `/times` `POST` 요청 시 시간을 추가하고 API 명세에 맞게 응답을 반환한다. | ||
- [X] 시작 시간이 null이라면 예외를 발생시키고 상태코드 400을 반환한다. | ||
- [X] 시작 시간이 형식에 맞지 않는다면 예외를 발생시키고 상태코드 400을 반환한다. | ||
- [X] 시작 시간이 중복이라면 예외를 발생시키고 상태코드 400을 반환한다. | ||
- [X] `/times/{id}` `DELETE` 요청 시 시간을 삭제하고 API 명세에 맞게 응답을 반환한다. | ||
- [X] 예약이 존재하는 시간을 삭제하려고 하면 예외를 발생시키고 상태코드 400을 반환한다. | ||
- [X] 존재하지 않는 아이디를 삭제하려고 하면 예외를 발생시키고 상태코드 400을 반환한다. | ||
- [X] `/times/availability?date=${date}&themeId=${themeId}` `GET` 요청 시 시간 목록을 조회하고 API 명세에 맞게 응답을 반환한다. | ||
- [X] 날짜, 테마 아이디가 비어있으면 예외를 발생시키고 상태코드 400을 반환한다. | ||
- [X] 예약 날짜가 형식에 맞지 않는다면 예외를 발생시키고 상태코드 400을 반환한다. | ||
- [X] 테마 아이디가 자연수가 아니라면 예외를 발생시키고 상태코드 400을 반환한다. | ||
|
||
### Theme | ||
|
||
- [x] `/themes` `GET` 요청 시 테마 목록을 조회하고 API 명세에 맞게 응답을 반환한다. | ||
- [x] `/themes` `POST` 요청 시 테마를 추가하고 API 명세에 맞게 응답을 반환한다. | ||
- [x] 테마 이름, 테마 설명, 테마 썸네일이 비어있다면 예외를 발생시키고 상태코드 400을 반환한다. | ||
- [x] `/themes` `DELETE` 요청 시 테마를 삭제하고 API 명세에 맞게 응답을 반환한다. | ||
- [x] 예약이 존재하는 테마를 삭제하려고 하면 예외를 발생시키고 상태코드 400을 반환한다. | ||
- [x] 존재하지 않는 아이디를 삭제하려고 하면 예외를 발생시키고 상태코드 400을 반환한다. | ||
- [X] `/themes/rank` `GET` 요청 시 예약 순서로 인기 테마 결과를 API 명세에 맞게 반환한다. | ||
|
||
# API 명세 | ||
|
||
Comment on lines
+48
to
+49
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 👍👍 |
||
## reservations | ||
|
||
### GET | ||
|
||
```http | ||
GET /reservations HTTP/1.1 | ||
``` | ||
|
||
```http | ||
[ | ||
{ | ||
"id": 1, | ||
"name": "브라운", | ||
"theme": { | ||
"id": 1, | ||
"name": "레벨2 탈출", | ||
"description": "우테코 레벨2를 탈출하는 내용입니다.", | ||
"thumbnail": "https://i.pinimg.com/236x/6e/bc/46/6ebc461a94a49f9ea3b8bbe2204145d4.jpg" | ||
}, | ||
"date": "2023-08-05", | ||
"time": { | ||
"id": 1, | ||
"startAt": "10:00" | ||
} | ||
} | ||
] | ||
``` | ||
|
||
### Post | ||
|
||
```http | ||
POST /reservations HTTP/1.1 | ||
content-type: application/json | ||
{ | ||
"date": "2023-08-05", | ||
"name": "브라운", | ||
"themeId": 1, | ||
"timeId": 1 | ||
} | ||
``` | ||
|
||
```http | ||
HTTP/1.1 201 | ||
Content-Type: application/json | ||
{ | ||
"id": 1, | ||
"name": "브라운", | ||
"theme": { | ||
"id": 1, | ||
"name": "레벨2 탈출", | ||
"description": "우테코 레벨2를 탈출하는 내용입니다.", | ||
"thumbnail": "https://i.pinimg.com/236x/6e/bc/46/6ebc461a94a49f9ea3b8bbe2204145d4.jpg" | ||
}, | ||
"date": "2023-08-05", | ||
"time" : { | ||
"id": 1, | ||
"startAt" : "10:00" | ||
} | ||
} | ||
``` | ||
|
||
### Delete | ||
|
||
```http | ||
DELETE /reservations/1 HTTP/1.1 | ||
``` | ||
|
||
```http | ||
HTTP/1.1 204 | ||
``` | ||
|
||
## times | ||
|
||
### GET | ||
|
||
```http | ||
GET /times HTTP/1.1 | ||
``` | ||
|
||
```http | ||
HTTP/1.1 200 | ||
Content-Type: application/json | ||
[ | ||
{ | ||
"id": 1, | ||
"startAt": "10:00" | ||
} | ||
] | ||
``` | ||
|
||
### GET | ||
|
||
```http | ||
GET /times/availability?date="2024-12-20"&themeId=1 HTTP/1.1 | ||
``` | ||
|
||
```http | ||
HTTP/1.1 200 | ||
Content-Type: application/json | ||
[ | ||
{ | ||
"id": 1, | ||
"startAt": "10:00" | ||
"alreadyBooked": true | ||
} | ||
] | ||
``` | ||
|
||
### Post | ||
|
||
```http | ||
POST /times HTTP/1.1 | ||
content-type: application/json | ||
{ | ||
"startAt": "10:00" | ||
} | ||
``` | ||
|
||
```http | ||
HTTP/1.1 201 | ||
Content-Type: application/json | ||
{ | ||
"id": 1, | ||
"startAt": "10:00" | ||
} | ||
``` | ||
|
||
### Delete | ||
|
||
```http | ||
DELETE /times/1 HTTP/1.1 | ||
``` | ||
|
||
```http | ||
HTTP/1.1 204 | ||
``` | ||
|
||
## theme | ||
|
||
### Get | ||
|
||
```http | ||
GET /themes HTTP/1.1 | ||
``` | ||
|
||
```http | ||
HTTP/1.1 200 | ||
Content-Type: application/json | ||
|
||
[ | ||
{ | ||
"id": 1, | ||
"name": "레벨2 탈출", | ||
"description": "우테코 레벨2를 탈출하는 내용입니다.", | ||
"thumbnail": "https://i.pinimg.com/236x/6e/bc/46/6ebc461a94a49f9ea3b8bbe2204145d4.jpg" | ||
} | ||
] | ||
``` | ||
|
||
### Get | ||
|
||
```http | ||
GET /themes/rank HTTP/1.1 | ||
``` | ||
|
||
```http | ||
HTTP/1.1 200 | ||
Content-Type: application/json | ||
|
||
[ | ||
{ | ||
"id": 1, | ||
"name": "레벨2 탈출", | ||
"description": "우테코 레벨2를 탈출하는 내용입니다.", | ||
"thumbnail": "https://i.pinimg.com/236x/6e/bc/46/6ebc461a94a49f9ea3b8bbe2204145d4.jpg" | ||
} | ||
] | ||
``` | ||
|
||
### Post | ||
|
||
```http | ||
POST /themes HTTP/1.1 | ||
content-type: application/json | ||
|
||
{ | ||
"name": "레벨2 탈출", | ||
"description": "우테코 레벨2를 탈출하는 내용입니다.", | ||
"thumbnail": "https://i.pinimg.com/236x/6e/bc/46/6ebc461a94a49f9ea3b8bbe2204145d4.jpg" | ||
} | ||
``` | ||
|
||
```http | ||
HTTP/1.1 201 | ||
Location: /themes/1 | ||
Content-Type: application/json | ||
|
||
{ | ||
"id": 1, | ||
"name": "레벨2 탈출", | ||
"description": "우테코 레벨2를 탈출하는 내용입니다.", | ||
"thumbnail": "https://i.pinimg.com/236x/6e/bc/46/6ebc461a94a49f9ea3b8bbe2204145d4.jpg" | ||
} | ||
``` | ||
|
||
### Delete | ||
|
||
```http | ||
DELETE /themes/1 HTTP/1.1 | ||
``` | ||
|
||
```http | ||
HTTP/1.1 204 | ||
``` |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
package roomescape.controller; | ||
|
||
import org.springframework.stereotype.Controller; | ||
import org.springframework.web.bind.annotation.GetMapping; | ||
import org.springframework.web.bind.annotation.RequestMapping; | ||
|
||
@Controller | ||
@RequestMapping("/admin") | ||
public class AdminController { | ||
|
||
@GetMapping | ||
public String getIndexPage() { | ||
return "admin/index"; | ||
} | ||
|
||
@GetMapping("/reservation") | ||
public String getReservationPage() { | ||
return "admin/reservation-new"; | ||
} | ||
|
||
@GetMapping("/time") | ||
public String getReservationTimePage() { | ||
return "admin/time"; | ||
} | ||
|
||
@GetMapping("/theme") | ||
public String getThemePage() { | ||
return "admin/theme"; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
package roomescape.controller; | ||
|
||
import org.springframework.stereotype.Controller; | ||
import org.springframework.web.bind.annotation.GetMapping; | ||
|
||
@Controller | ||
public class HomeController { | ||
|
||
@GetMapping("/") | ||
public String getIndexPage() { | ||
return "index"; | ||
} | ||
} | ||
Comment on lines
+6
to
+13
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 시간이 없어 미처 변경하지 못했는데 지금은 UserController로 옮겼어 👍 |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
package roomescape.controller; | ||
|
||
import java.util.List; | ||
import org.springframework.http.HttpStatus; | ||
import org.springframework.web.bind.annotation.DeleteMapping; | ||
import org.springframework.web.bind.annotation.GetMapping; | ||
import org.springframework.web.bind.annotation.PathVariable; | ||
import org.springframework.web.bind.annotation.PostMapping; | ||
import org.springframework.web.bind.annotation.RequestBody; | ||
import org.springframework.web.bind.annotation.RequestMapping; | ||
import org.springframework.web.bind.annotation.ResponseStatus; | ||
import org.springframework.web.bind.annotation.RestController; | ||
import roomescape.service.ReservationService; | ||
import roomescape.service.dto.ReservationRequestDto; | ||
import roomescape.service.dto.ReservationResponseDto; | ||
|
||
@RestController | ||
@RequestMapping("/reservations") | ||
public class ReservationApiController { | ||
|
||
private final ReservationService reservationService; | ||
|
||
public ReservationApiController(ReservationService reservationService) { | ||
this.reservationService = reservationService; | ||
} | ||
|
||
@GetMapping | ||
public List<ReservationResponseDto> findReservations() { | ||
return reservationService.findAllReservations(); | ||
} | ||
|
||
@ResponseStatus(HttpStatus.CREATED) | ||
@PostMapping | ||
public ReservationResponseDto createReservation(@RequestBody ReservationRequestDto requestDto) { | ||
return reservationService.createReservation(requestDto); | ||
} | ||
Comment on lines
+32
to
+36
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 우리가 응답을 커스텀하는 정도는 현재에선 상태 코드뿐인 것 같아. 그런데 ResponseEntity와 비교해서 어떤 장점이 있는지는 잘 모르겠네 🤔 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 난 저번 레벨 미션 리뷰어로부터 리뷰를 받고, 나도 전에는 리비랑 같은 궁금증이 있었는데, 리뷰어로부터 근본적인 답변을 듣지는 못했지만 이제는 나도 ㅋㅋ 컨트롤러 코드에 특히 단순히 void를 반환 한다거나, 상태 코드 200 같은 경우엔 더더욱 사용할 필요가 없다는 생각이야 |
||
|
||
@ResponseStatus(HttpStatus.NO_CONTENT) | ||
@DeleteMapping("/{id}") | ||
public void deleteReservation(@PathVariable long id) { | ||
reservationService.deleteReservation(id); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
package roomescape.controller; | ||
|
||
import org.springframework.stereotype.Controller; | ||
import org.springframework.web.bind.annotation.GetMapping; | ||
import org.springframework.web.bind.annotation.RequestMapping; | ||
|
||
@Controller | ||
@RequestMapping("/reservation") | ||
public class ReservationController { | ||
|
||
@GetMapping | ||
public String getReservationPage() { | ||
return "reservation"; | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
API 명세서 너무 깔끔하게 정리했는데? 👍 👍 👍