Skip to content

Commit 465bdbc

Browse files
committed
feat: API 응답 형식 통일 및 닉네임 숫자 제거
1 parent f9a2cb5 commit 465bdbc

File tree

7 files changed

+238
-73
lines changed

7 files changed

+238
-73
lines changed

src/main/java/com/climbup/climbup/auth/controller/TokenController.java

Lines changed: 103 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,15 @@
55
import com.climbup.climbup.auth.service.TokenService;
66
import com.climbup.climbup.auth.util.JwtUtil;
77
import com.climbup.climbup.auth.util.SecurityUtil;
8+
import com.climbup.climbup.common.dto.ApiResult;
89
import com.climbup.climbup.common.exception.CommonBusinessException;
910
import com.climbup.climbup.common.exception.ErrorCode;
1011
import com.climbup.climbup.common.exception.ValidationException;
1112
import io.swagger.v3.oas.annotations.Operation;
13+
import io.swagger.v3.oas.annotations.media.Content;
14+
import io.swagger.v3.oas.annotations.media.ExampleObject;
15+
import io.swagger.v3.oas.annotations.responses.ApiResponse;
16+
import io.swagger.v3.oas.annotations.responses.ApiResponses;
1217
import io.swagger.v3.oas.annotations.tags.Tag;
1318
import lombok.RequiredArgsConstructor;
1419
import lombok.extern.slf4j.Slf4j;
@@ -28,8 +33,68 @@ public class TokenController {
2833
private final JwtUtil jwtUtil;
2934

3035
@Operation(summary = "토큰 재발급", description = "Refresh Token으로 새로운 Access Token을 발급받습니다")
36+
@ApiResponses({
37+
@ApiResponse(
38+
responseCode = "200",
39+
description = "토큰 재발급 성공",
40+
content = @Content(
41+
mediaType = "application/json",
42+
examples = @ExampleObject(
43+
value = """
44+
{
45+
"message": "토큰이 성공적으로 재발급되었습니다.",
46+
"data": {
47+
"accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
48+
"refreshToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
49+
"tokenType": "Bearer",
50+
"accessTokenExpiresIn": 3600,
51+
"refreshTokenExpiresIn": 604800
52+
}
53+
}
54+
"""
55+
)
56+
)
57+
),
58+
@ApiResponse(
59+
responseCode = "400",
60+
description = "잘못된 요청",
61+
content = @Content(
62+
mediaType = "application/json",
63+
examples = {
64+
@ExampleObject(
65+
name = "필수 필드 누락",
66+
value = """
67+
{
68+
"errorCode": "VALIDATION_002",
69+
"message": "필수 필드가 누락되었습니다: refreshToken",
70+
"timestamp": "2024-01-15T10:30:00",
71+
"path": "/api/auth/refresh"
72+
}
73+
"""
74+
)
75+
}
76+
)
77+
),
78+
@ApiResponse(
79+
responseCode = "401",
80+
description = "유효하지 않은 토큰",
81+
content = @Content(
82+
mediaType = "application/json",
83+
examples = @ExampleObject(
84+
value = """
85+
{
86+
"errorCode": "AUTH_003",
87+
"message": "토큰이 유효하지 않습니다.",
88+
"timestamp": "2024-01-15T10:30:00",
89+
"path": "/api/auth/refresh"
90+
}
91+
"""
92+
)
93+
)
94+
)
95+
})
3196
@PostMapping("/refresh")
32-
public ResponseEntity<TokenResponse> refreshToken(@RequestBody Map<String, String> request) {
97+
public ResponseEntity<ApiResult<TokenResponse>> refreshToken(@RequestBody Map<String, String> request) {
3398
String refreshToken = request.get("refreshToken");
3499

35100
if (refreshToken == null || refreshToken.trim().isEmpty()) {
@@ -47,12 +112,46 @@ public ResponseEntity<TokenResponse> refreshToken(@RequestBody Map<String, Strin
47112
TokenResponse tokenResponse = tokenService.refreshTokens(refreshToken);
48113
log.info("토큰 재발급 성공: userId={}", tokenUserId);
49114

50-
return ResponseEntity.ok(tokenResponse);
115+
return ResponseEntity.ok(ApiResult.success("토큰이 성공적으로 재발급되었습니다.", tokenResponse));
51116
}
52117

53118
@Operation(summary = "로그아웃", description = "Refresh Token을 무효화합니다")
119+
@ApiResponses({
120+
@ApiResponse(
121+
responseCode = "200",
122+
description = "로그아웃 성공",
123+
content = @Content(
124+
mediaType = "application/json",
125+
examples = @ExampleObject(
126+
value = """
127+
{
128+
"message": "로그아웃이 완료되었습니다.",
129+
"data": null
130+
}
131+
"""
132+
)
133+
)
134+
),
135+
@ApiResponse(
136+
responseCode = "403",
137+
description = "접근 권한 없음",
138+
content = @Content(
139+
mediaType = "application/json",
140+
examples = @ExampleObject(
141+
value = """
142+
{
143+
"errorCode": "AUTH_002",
144+
"message": "접근이 거부되었습니다.",
145+
"timestamp": "2024-01-15T10:30:00",
146+
"path": "/api/auth/logout"
147+
}
148+
"""
149+
)
150+
)
151+
)
152+
})
54153
@PostMapping("/logout")
55-
public ResponseEntity<Map<String, Object>> logout() {
154+
public ResponseEntity<ApiResult<Void>> logout() {
56155

57156
Long userId = SecurityUtil.getCurrentUserId();
58157

@@ -64,9 +163,6 @@ public ResponseEntity<Map<String, Object>> logout() {
64163
tokenService.revokeRefreshToken(userId);
65164
log.info("사용자 {}의 refresh token 무효화 완료", userId);
66165

67-
return ResponseEntity.ok(Map.of(
68-
"success", true,
69-
"message", "로그아웃이 완료되었습니다."
70-
));
166+
return ResponseEntity.ok(ApiResult.success("로그아웃이 완료되었습니다."));
71167
}
72168
}
Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,26 @@
11
package com.climbup.climbup.auth.dto;
22

3+
import io.swagger.v3.oas.annotations.media.Schema;
34
import lombok.Builder;
45
import lombok.Getter;
56

67
@Getter
78
@Builder
9+
@Schema(description = "토큰 응답 정보")
810
public class TokenResponse {
11+
12+
@Schema(description = "액세스 토큰", example = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...")
913
private String accessToken;
14+
15+
@Schema(description = "리프레시 토큰", example = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...")
1016
private String refreshToken;
17+
18+
@Schema(description = "토큰 타입", example = "Bearer")
1119
private String tokenType;
12-
private String message;
20+
21+
@Schema(description = "액세스 토큰 만료 시간 (초)", example = "3600")
22+
private Long accessTokenExpiresIn;
23+
24+
@Schema(description = "리프레시 토큰 만료 시간 (초)", example = "604800")
25+
private Long refreshTokenExpiresIn;
1326
}

src/main/java/com/climbup/climbup/auth/service/CustomOAuth2UserService.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,8 +67,7 @@ private User createUser(KakaoOAuth2UserInfo userInfo) {
6767

6868
private String generateUniqueNickname() {
6969
for (int i = 0; i < maxRetries; i++) {
70-
String base = RandomNicknameGenerator.generate();
71-
String nickname = base + (ThreadLocalRandom.current().nextInt(900) + 100);
70+
String nickname = RandomNicknameGenerator.generate();
7271
if (!userRepository.existsByNickname(nickname)) {
7372
return nickname;
7473
}

src/main/java/com/climbup/climbup/auth/service/TokenService.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@ public TokenResponse createTokens(Long userId) {
4040
.accessToken(accessToken)
4141
.refreshToken(refreshToken)
4242
.tokenType("Bearer")
43+
.accessTokenExpiresIn(3600L)
44+
.refreshTokenExpiresIn(604800L)
4345
.build();
4446
}
4547

src/main/java/com/climbup/climbup/user/controller/OnboardingController.java

Lines changed: 53 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,21 @@ public class OnboardingController {
3131
security = @SecurityRequirement(name = "bearerAuth")
3232
)
3333
@ApiResponses({
34-
@ApiResponse(responseCode = "200", description = "온보딩 완료 성공"),
34+
@ApiResponse(
35+
responseCode = "200",
36+
description = "온보딩 완료 성공",
37+
content = @Content(
38+
mediaType = "application/json",
39+
examples = @ExampleObject(
40+
value = """
41+
{
42+
"message": "온보딩이 완료되었습니다.",
43+
"data": null
44+
}
45+
"""
46+
)
47+
)
48+
),
3549
@ApiResponse(
3650
responseCode = "400",
3751
description = "이미 온보딩 완료된 사용자",
@@ -51,14 +65,14 @@ public class OnboardingController {
5165
)
5266
})
5367
@PostMapping
54-
public ResponseEntity<ApiResult<OnboardingDto.Response>> completeOnboarding(
68+
public ResponseEntity<ApiResult<Void>> completeOnboarding(
5569
@RequestBody OnboardingDto.CompleteRequest request) {
5670

5771
Long userId = SecurityUtil.getCurrentUserId();
5872

5973
onboardingService.completeOnboarding(userId, request.getGymId(), request.getGymLevelId());
6074

61-
return ResponseEntity.ok(ApiResult.success(new OnboardingDto.Response("온보딩이 완료되었습니다.")));
75+
return ResponseEntity.ok(ApiResult.success("온보딩이 완료되었습니다."));
6276
}
6377

6478
@PreAuthorize("isAuthenticated()")
@@ -67,15 +81,32 @@ public ResponseEntity<ApiResult<OnboardingDto.Response>> completeOnboarding(
6781
description = "사용자의 암장을 설정합니다.",
6882
security = @SecurityRequirement(name = "bearerAuth")
6983
)
84+
@ApiResponses({
85+
@ApiResponse(
86+
responseCode = "200",
87+
description = "암장 설정 성공",
88+
content = @Content(
89+
mediaType = "application/json",
90+
examples = @ExampleObject(
91+
value = """
92+
{
93+
"message": "암장이 설정되었습니다.",
94+
"data": null
95+
}
96+
"""
97+
)
98+
)
99+
)
100+
})
70101
@PostMapping("/gym")
71-
public ResponseEntity<ApiResult<OnboardingDto.Response>> setGym(
102+
public ResponseEntity<ApiResult<Void>> setGym(
72103
@RequestBody OnboardingDto.GymRequest request) {
73104

74105
Long userId = SecurityUtil.getCurrentUserId();
75106

76107
onboardingService.setUserGym(userId, request.getGymId());
77108

78-
return ResponseEntity.ok(ApiResult.success(new OnboardingDto.Response("암장이 설정되었습니다.")));
109+
return ResponseEntity.ok(ApiResult.success("암장이 설정되었습니다."));
79110
}
80111

81112
@PreAuthorize("isAuthenticated()")
@@ -85,7 +116,21 @@ public ResponseEntity<ApiResult<OnboardingDto.Response>> setGym(
85116
security = @SecurityRequirement(name = "bearerAuth")
86117
)
87118
@ApiResponses({
88-
@ApiResponse(responseCode = "200", description = "레벨 설정 성공"),
119+
@ApiResponse(
120+
responseCode = "200",
121+
description = "레벨 설정 성공",
122+
content = @Content(
123+
mediaType = "application/json",
124+
examples = @ExampleObject(
125+
value = """
126+
{
127+
"message": "레벨이 설정되었습니다.",
128+
"data": null
129+
}
130+
"""
131+
)
132+
)
133+
),
89134
@ApiResponse(
90135
responseCode = "400",
91136
description = "암장 미선택 또는 브랜드 불일치",
@@ -119,13 +164,13 @@ public ResponseEntity<ApiResult<OnboardingDto.Response>> setGym(
119164
)
120165
})
121166
@PostMapping("/gym-level")
122-
public ResponseEntity<ApiResult<OnboardingDto.Response>> setLevel(
167+
public ResponseEntity<ApiResult<Void>> setLevel(
123168
@RequestBody OnboardingDto.LevelRequest request) {
124169

125170
Long userId = SecurityUtil.getCurrentUserId();
126171

127172
onboardingService.setUserGymLevel(userId, request.getGymLevelId());
128173

129-
return ResponseEntity.ok(ApiResult.success(new OnboardingDto.Response("레벨이 설정되었습니다.")));
174+
return ResponseEntity.ok(ApiResult.success("레벨이 설정되었습니다."));
130175
}
131176
}

src/main/java/com/climbup/climbup/user/controller/UserController.java

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,12 @@
11
package com.climbup.climbup.user.controller;
22

3-
import com.climbup.climbup.auth.util.JwtUtil;
43
import com.climbup.climbup.auth.util.SecurityUtil;
54
import com.climbup.climbup.common.dto.ApiResult;
65
import com.climbup.climbup.user.docs.UserApiDocs;
76
import com.climbup.climbup.user.docs.UserApiExamples;
87
import com.climbup.climbup.user.dto.response.UserStatusResponse;
98
import com.climbup.climbup.user.service.UserService;
109
import io.swagger.v3.oas.annotations.Operation;
11-
import io.swagger.v3.oas.annotations.Parameter;
1210
import io.swagger.v3.oas.annotations.media.Content;
1311
import io.swagger.v3.oas.annotations.media.ExampleObject;
1412
import io.swagger.v3.oas.annotations.media.Schema;
@@ -86,6 +84,6 @@ public ResponseEntity<ApiResult<UserStatusResponse>> getCurrentUserStatus() {
8684
Long userId = SecurityUtil.getCurrentUserId();
8785

8886
UserStatusResponse userStatus = userService.getUserStatus(userId);
89-
return ResponseEntity.ok(ApiResult.success(userStatus));
87+
return ResponseEntity.ok(ApiResult.success("사용자 상태가 성공적으로 조회되었습니다.", userStatus));
9088
}
9189
}

0 commit comments

Comments
 (0)