Skip to content

Commit 26e9e9f

Browse files
committed
refactor: Hashids 난독화에 따른 Swagger 문서화 전역 자동화 (#55)
1 parent 27b4590 commit 26e9e9f

6 files changed

Lines changed: 81 additions & 10 deletions

File tree

src/main/java/com/sofa/linkiving/domain/chat/controller/ChatApi.java

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010
import com.sofa.linkiving.domain.chat.dto.response.MessagesRes;
1111
import com.sofa.linkiving.domain.member.entity.Member;
1212
import com.sofa.linkiving.global.common.BaseResponse;
13-
import com.sofa.linkiving.global.config.annotation.DecodeHash;
1413

1514
import io.swagger.v3.oas.annotations.Operation;
1615
import io.swagger.v3.oas.annotations.Parameter;
@@ -68,10 +67,8 @@ public interface ChatApi {
6867
BaseResponse<MessagesRes> getMessages(
6968
Member member,
7069
@Parameter(description = "채팅방 ID")
71-
@DecodeHash
7270
Long chatId,
7371
@Parameter(description = "페이징을 위한 마지막 메시지 ID, 첫 조회 시 null")
74-
@DecodeHash
7572
Long lastId,
7673
@Parameter(description = "페이지 크기")
7774
@Min(value = 1, message = "최소 1개 이상 조회해야 합니다.")
@@ -89,7 +86,7 @@ BaseResponse<CreateChatRes> createChat(
8986
);
9087

9188
@Operation(summary = "링크 삭제", description = "해당 링크방과 채팅 기록을 전부 Hard Delete 진행합니다.")
92-
BaseResponse<String> deleteChat(Member member, @DecodeHash Long chatId);
89+
BaseResponse<String> deleteChat(Member member, @Parameter(description = "채팅방 ID") Long chatId);
9390

9491
void sendMessage(AnswerReq req, Member member);
9592

src/main/java/com/sofa/linkiving/domain/chat/controller/FeedbackApi.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,13 @@
66
import com.sofa.linkiving.global.common.BaseResponse;
77

88
import io.swagger.v3.oas.annotations.Operation;
9+
import io.swagger.v3.oas.annotations.Parameter;
910
import io.swagger.v3.oas.annotations.tags.Tag;
1011

1112
@Tag(name = "Feedback", description = "피드백 관리 API")
1213
public interface FeedbackApi {
1314
@Operation(summary = "피드백 추가 및 수정", description = "메세지에 피드백을 추가 및 수정하고 피드백 ID를 반환합니다.")
14-
BaseResponse<UpsertFeedbackRes> upsertFeedback(Long messageId, UpsertFeedbackReq createFeedbackReq,
15+
BaseResponse<UpsertFeedbackRes> upsertFeedback(@Parameter(description = "메세지 ID") Long messageId,
16+
UpsertFeedbackReq createFeedbackReq,
1517
Member member);
1618
}

src/main/java/com/sofa/linkiving/domain/link/controller/LinkApi.java

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@
3838
**CASE A: PROCESSING (처리 중)**
3939
```json
4040
{
41+
"linkId": aB9x2K8R,
42+
"status": "PROCESSING"
4143
"linkId": 1,
4244
"status": "PROCESSING",
4345
"summary": null,
@@ -48,10 +50,10 @@
4850
**CASE B: COMPLETED (요약 완료)**
4951
```json
5052
{
51-
"linkId": 1,
53+
"linkId": aB9x2K8R,
5254
"status": "COMPLETED",
5355
"summary": {
54-
"id": 100,
56+
"id": aB9x2K8S,
5557
"content": "생성된 AI 요약 내용입니다."
5658
},
5759
"errorMessage": null
@@ -60,7 +62,7 @@
6062
**CASE C: FAILED (요약 실패)**
6163
```json
6264
{
63-
"linkId": 1,
65+
"linkId": aB9x2K8R,
6466
"status": "FAILED",
6567
"summary": null,
6668
"errorMessage": "AI 서버 응답이 없습니다."

src/main/java/com/sofa/linkiving/domain/link/dto/response/LinkDuplicateCheckRes.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ public record LinkDuplicateCheckRes(
99
@Schema(description = "URL 중복 여부", example = "true")
1010
boolean exists,
1111

12-
@Schema(description = "중복된 링크 ID (exists가 true일 때만 반환)", example = "123")
12+
@Schema(description = "중복된 링크 ID (exists가 true일 때만 반환)")
1313
@JsonSerialize(using = HashidsSerializer.class)
1414
Long linkId
1515
) {

src/main/java/com/sofa/linkiving/domain/member/dto/response/MemberProfileRes.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111

1212
@Builder
1313
public record MemberProfileRes(
14-
@Schema(description = "회원 ID", example = "1")
14+
@Schema(description = "회원 ID")
1515
@JsonSerialize(using = HashidsSerializer.class)
1616
Long id,
1717
@Schema(description = "유저명", example = "Linkiving User")
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
package com.sofa.linkiving.global.config;
2+
3+
import org.springdoc.core.customizers.ParameterCustomizer;
4+
import org.springdoc.core.customizers.PropertyCustomizer;
5+
import org.springframework.context.annotation.Bean;
6+
import org.springframework.context.annotation.Configuration;
7+
8+
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
9+
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
10+
import com.sofa.linkiving.global.config.annotation.DecodeHash;
11+
12+
import io.swagger.v3.oas.models.media.StringSchema;
13+
14+
@Configuration
15+
public class SwaggerConfig {
16+
17+
@Bean
18+
public ParameterCustomizer hashidParameterCustomizer() {
19+
return (parameterModel, methodParameter) -> {
20+
if (methodParameter.hasParameterAnnotation(DecodeHash.class)) {
21+
parameterModel.setSchema(new StringSchema());
22+
parameterModel.setExample("aB9x2K8R");
23+
String currentDesc = parameterModel.getDescription() != null ? parameterModel.getDescription() : "";
24+
if (!currentDesc.contains("해시")) {
25+
parameterModel.setDescription(currentDesc + " (해시 문자열)");
26+
}
27+
}
28+
return parameterModel;
29+
};
30+
}
31+
32+
@Bean
33+
public PropertyCustomizer hashidPropertyCustomizer() {
34+
return (property, type) -> {
35+
if (type.getCtxAnnotations() == null) {
36+
return property;
37+
}
38+
39+
boolean isHashidField = false;
40+
41+
for (java.lang.annotation.Annotation annotation : type.getCtxAnnotations()) {
42+
43+
if (annotation instanceof JsonSerialize serialize) {
44+
if (serialize.using().getSimpleName().contains("Hashids")) {
45+
isHashidField = true;
46+
break;
47+
}
48+
} else if (annotation instanceof JsonDeserialize deserialize) {
49+
if (deserialize.using().getSimpleName().contains("Hashids")) {
50+
isHashidField = true;
51+
break;
52+
}
53+
}
54+
}
55+
56+
if (isHashidField) {
57+
property.setType("string");
58+
property.setFormat(null);
59+
property.setExample("aB9x2K8R");
60+
61+
String desc = property.getDescription() != null ? property.getDescription() : "";
62+
if (!desc.contains("해시")) {
63+
property.setDescription(desc + " (해시된 문자열)");
64+
}
65+
}
66+
67+
return property;
68+
};
69+
}
70+
}

0 commit comments

Comments
 (0)