Skip to content

Commit 2d0b7b6

Browse files
feat(fe): add zod library for request/response/socket-payload validation (#207)
* feat: add zod library for improved validation * feat: refactor DTOs to use Zod schemas for validation * feat: update validation schemas * chore: auto-fix linting and formatting issues --------- Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
1 parent 3eba9eb commit 2d0b7b6

File tree

10 files changed

+565
-389
lines changed

10 files changed

+565
-389
lines changed

apps/client/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
"react-markdown": "^9.0.1",
2424
"socket.io-client": "^4.8.1",
2525
"tailwind-scrollbar-hide": "^1.1.7",
26+
"zod": "^3.23.8",
2627
"zustand": "^5.0.1"
2728
},
2829
"devDependencies": {
Lines changed: 20 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,20 @@
1-
export interface PostLoginRequestDTO {
2-
email: string;
3-
password: string;
4-
}
5-
6-
export interface PostLoginResponseDTO {
7-
accessToken: string;
8-
userId: number;
9-
}
10-
11-
export interface PostRefreshResponseDTO {
12-
accessToken: string;
13-
userId: number;
14-
}
1+
import { z } from 'zod';
2+
3+
export const PostLoginRequestSchema = z.object({
4+
email: z.string().email(),
5+
password: z.string().min(8).max(20),
6+
});
7+
8+
export const PostLoginResponseSchema = z.object({
9+
accessToken: z.string(),
10+
userId: z.number(),
11+
});
12+
13+
export const PostRefreshResponseSchema = z.object({
14+
accessToken: z.string(),
15+
userId: z.number(),
16+
});
17+
18+
export type PostLoginRequestDTO = z.infer<typeof PostLoginRequestSchema>;
19+
export type PostLoginResponseDTO = z.infer<typeof PostLoginResponseSchema>;
20+
export type PostRefreshResponseDTO = z.infer<typeof PostRefreshResponseSchema>;
Lines changed: 197 additions & 144 deletions
Original file line numberDiff line numberDiff line change
@@ -1,144 +1,197 @@
1-
import { Question } from '@/features/session/qna/qna.type';
2-
3-
export interface GetQuestionsRequestDTO {
4-
sessionId: string;
5-
token?: string;
6-
}
7-
8-
export interface GetQuestionsResponseDTO {
9-
questions: Question[];
10-
isHost: boolean;
11-
expired: boolean;
12-
sessionTitle: string;
13-
}
14-
15-
export interface PostQuestionRequestDTO {
16-
token: string;
17-
sessionId: string;
18-
body: string;
19-
}
20-
21-
export interface PostQuestionResponseDTO {
22-
question: Question;
23-
}
24-
25-
export interface PatchQuestionBodyRequestDTO {
26-
token: string;
27-
sessionId: string;
28-
body: string;
29-
}
30-
31-
export interface PatchQuestionBodyResponseDTO {
32-
question: {
33-
questionId: number;
34-
createUserToken: string;
35-
sessionId: string;
36-
body: string;
37-
closed: boolean;
38-
pinned: boolean;
39-
createdAt: string;
40-
};
41-
}
42-
43-
export interface DeleteQuestionRequestDTO {
44-
sessionId: string;
45-
token: string;
46-
}
47-
48-
export interface PatchQuestionPinnedRequestDTO {
49-
token: string;
50-
sessionId: string;
51-
pinned: boolean;
52-
}
53-
54-
export interface PatchQuestionPinnedResponseDTO {
55-
question: {
56-
questionId: number;
57-
createUserToken: string;
58-
sessionId: string;
59-
body: string;
60-
closed: boolean;
61-
pinned: boolean;
62-
createdAt: string;
63-
};
64-
}
65-
66-
export interface PatchQuestionClosedRequestDTO {
67-
token: string;
68-
sessionId: string;
69-
closed: boolean;
70-
}
71-
72-
export interface PatchQuestionClosedResponseDTO {
73-
question: {
74-
questionId: number;
75-
createUserToken: string;
76-
sessionId: string;
77-
body: string;
78-
closed: boolean;
79-
pinned: boolean;
80-
createdAt: string;
81-
};
82-
}
83-
84-
export interface PostQuestionLikeRequestDTO {
85-
token: string;
86-
sessionId: string;
87-
}
88-
89-
export interface PostQuestionLikeResponseDTO {
90-
liked: boolean;
91-
likesCount: number;
92-
}
93-
94-
export interface PostReplyRequestDTO {
95-
token: string;
96-
sessionId: string;
97-
questionId: number;
98-
body: string;
99-
}
100-
101-
export interface PostReplyResponseDTO {
102-
reply: {
103-
replyId: number;
104-
body: string;
105-
createdAt: string;
106-
isOwner: boolean;
107-
likesCount: number;
108-
liked: boolean;
109-
nickname: string;
110-
isHost: boolean;
111-
};
112-
}
113-
114-
export interface PatchReplyBodyRequestDTO {
115-
token: string;
116-
sessionId: string;
117-
body: string;
118-
}
119-
120-
export interface PatchReplyBodyResponseDTO {
121-
reply: {
122-
replyId: number;
123-
createUserToken: string;
124-
sessionId: string;
125-
questionId: number;
126-
body: string;
127-
createdAt: string;
128-
};
129-
}
130-
131-
export interface DeleteReplyRequestDTO {
132-
sessionId: string;
133-
token: string;
134-
}
135-
136-
export interface PostReplyLikeRequestDTO {
137-
token: string;
138-
sessionId: string;
139-
}
140-
141-
export interface PostReplyLikeResponseDTO {
142-
liked: boolean;
143-
likesCount: number;
144-
}
1+
import { z } from 'zod';
2+
3+
import { QuestionSchema } from '@/features/session/qna/qna.type';
4+
5+
export const GetQuestionsRequestSchema = z.object({
6+
sessionId: z.string(),
7+
token: z.string().optional(),
8+
});
9+
10+
export const GetQuestionsResponseSchema = z.object({
11+
questions: z.array(QuestionSchema),
12+
isHost: z.boolean(),
13+
expired: z.boolean(),
14+
sessionTitle: z.string(),
15+
});
16+
17+
export const PostQuestionRequestSchema = z.object({
18+
token: z.string(),
19+
sessionId: z.string(),
20+
body: z.string().min(1),
21+
});
22+
23+
export const PostQuestionResponseSchema = z.object({
24+
question: QuestionSchema,
25+
});
26+
27+
export const PatchQuestionBodyRequestSchema = z.object({
28+
token: z.string(),
29+
sessionId: z.string(),
30+
body: z.string().min(1),
31+
});
32+
33+
export const PatchQuestionBodyResponseSchema = z.object({
34+
question: z.object({
35+
questionId: z.number(),
36+
createUserToken: z.string(),
37+
sessionId: z.string(),
38+
body: z.string(),
39+
closed: z.boolean(),
40+
pinned: z.boolean(),
41+
createdAt: z.string(),
42+
}),
43+
});
44+
45+
export const DeleteQuestionRequestSchema = z.object({
46+
sessionId: z.string(),
47+
token: z.string(),
48+
});
49+
50+
export const PatchQuestionPinnedRequestSchema = z.object({
51+
token: z.string(),
52+
sessionId: z.string(),
53+
pinned: z.boolean(),
54+
});
55+
56+
export const PatchQuestionPinnedResponseSchema = z.object({
57+
question: z.object({
58+
questionId: z.number(),
59+
createUserToken: z.string(),
60+
sessionId: z.string(),
61+
body: z.string(),
62+
closed: z.boolean(),
63+
pinned: z.boolean(),
64+
createdAt: z.string(),
65+
}),
66+
});
67+
68+
export const PatchQuestionClosedRequestSchema = z.object({
69+
token: z.string(),
70+
sessionId: z.string(),
71+
closed: z.boolean(),
72+
});
73+
74+
export const PatchQuestionClosedResponseSchema = z.object({
75+
question: z.object({
76+
questionId: z.number(),
77+
createUserToken: z.string(),
78+
sessionId: z.string(),
79+
body: z.string(),
80+
closed: z.boolean(),
81+
pinned: z.boolean(),
82+
createdAt: z.string(),
83+
}),
84+
});
85+
86+
export const PostQuestionLikeRequestSchema = z.object({
87+
token: z.string(),
88+
sessionId: z.string(),
89+
});
90+
91+
export const PostQuestionLikeResponseSchema = z.object({
92+
liked: z.boolean(),
93+
likesCount: z.number(),
94+
});
95+
96+
export const PostReplyRequestSchema = z.object({
97+
token: z.string(),
98+
sessionId: z.string(),
99+
questionId: z.number(),
100+
body: z.string().min(1),
101+
});
102+
103+
export const PostReplyResponseSchema = z.object({
104+
reply: z.object({
105+
replyId: z.number(),
106+
body: z.string(),
107+
createdAt: z.string(),
108+
isOwner: z.boolean(),
109+
likesCount: z.number(),
110+
liked: z.boolean(),
111+
nickname: z.string(),
112+
isHost: z.boolean(),
113+
}),
114+
});
115+
116+
export const PatchReplyBodyRequestSchema = z.object({
117+
token: z.string(),
118+
sessionId: z.string(),
119+
body: z.string().min(1),
120+
});
121+
122+
export const PatchReplyBodyResponseSchema = z.object({
123+
reply: z.object({
124+
replyId: z.number(),
125+
createUserToken: z.string(),
126+
sessionId: z.string(),
127+
questionId: z.number(),
128+
body: z.string(),
129+
createdAt: z.string(),
130+
}),
131+
});
132+
133+
export const DeleteReplyRequestSchema = z.object({
134+
sessionId: z.string(),
135+
token: z.string(),
136+
});
137+
138+
export const PostReplyLikeRequestSchema = z.object({
139+
token: z.string(),
140+
sessionId: z.string(),
141+
});
142+
143+
export const PostReplyLikeResponseSchema = z.object({
144+
liked: z.boolean(),
145+
likesCount: z.number(),
146+
});
147+
148+
export type GetQuestionsRequestDTO = z.infer<typeof GetQuestionsRequestSchema>;
149+
export type GetQuestionsResponseDTO = z.infer<
150+
typeof GetQuestionsResponseSchema
151+
>;
152+
export type PostQuestionRequestDTO = z.infer<typeof PostQuestionRequestSchema>;
153+
export type PostQuestionResponseDTO = z.infer<
154+
typeof PostQuestionResponseSchema
155+
>;
156+
export type PatchQuestionBodyRequestDTO = z.infer<
157+
typeof PatchQuestionBodyRequestSchema
158+
>;
159+
export type PatchQuestionBodyResponseDTO = z.infer<
160+
typeof PatchQuestionBodyResponseSchema
161+
>;
162+
export type DeleteQuestionRequestDTO = z.infer<
163+
typeof DeleteQuestionRequestSchema
164+
>;
165+
export type PatchQuestionPinnedRequestDTO = z.infer<
166+
typeof PatchQuestionPinnedRequestSchema
167+
>;
168+
export type PatchQuestionPinnedResponseDTO = z.infer<
169+
typeof PatchQuestionPinnedResponseSchema
170+
>;
171+
export type PatchQuestionClosedRequestDTO = z.infer<
172+
typeof PatchQuestionClosedRequestSchema
173+
>;
174+
export type PatchQuestionClosedResponseDTO = z.infer<
175+
typeof PatchQuestionClosedResponseSchema
176+
>;
177+
export type PostQuestionLikeRequestDTO = z.infer<
178+
typeof PostQuestionLikeRequestSchema
179+
>;
180+
export type PostQuestionLikeResponseDTO = z.infer<
181+
typeof PostQuestionLikeResponseSchema
182+
>;
183+
export type PostReplyRequestDTO = z.infer<typeof PostReplyRequestSchema>;
184+
export type PostReplyResponseDTO = z.infer<typeof PostReplyResponseSchema>;
185+
export type PatchReplyBodyRequestDTO = z.infer<
186+
typeof PatchReplyBodyRequestSchema
187+
>;
188+
export type PatchReplyBodyResponseDTO = z.infer<
189+
typeof PatchReplyBodyResponseSchema
190+
>;
191+
export type DeleteReplyRequestDTO = z.infer<typeof DeleteReplyRequestSchema>;
192+
export type PostReplyLikeRequestDTO = z.infer<
193+
typeof PostReplyLikeRequestSchema
194+
>;
195+
export type PostReplyLikeResponseDTO = z.infer<
196+
typeof PostReplyLikeResponseSchema
197+
>;

0 commit comments

Comments
 (0)