Skip to content

Commit 18167af

Browse files
committed
feat(code): implemented reusable schemas for API responses and errors
ISSUES CLOSED: #506
1 parent 5bbabfd commit 18167af

19 files changed

+489
-124
lines changed

apps/knowii/pages/api/v1/communities/create.ts

+118-24
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,26 @@ import { createServerSupabaseClient } from '@supabase/auth-helpers-nextjs';
22
import { NextApiRequest, NextApiResponse } from 'next';
33
import { generateErrorMessage } from 'zod-error';
44
import {
5-
errorClientNotAuthenticated,
6-
errorInternalServerError,
7-
hasErrorMessage,
5+
Communities,
6+
CreateCommunityInput,
87
createCommunityRequestSchema,
98
CreateCommunityResponse,
9+
errorClientNotAuthenticated,
10+
errorCommunityNameNotAvailable,
11+
errorCommunitySlugNotAvailable,
1012
errorInputValidation,
13+
errorInternalServerError,
1114
generateSlug,
12-
CreateCommunityInput,
1315
getLogger,
16+
hasErrorMessage,
1417
} from '@knowii/common';
15-
import { daoFnCreateCommunity, errorMessageOptions, getInternalUserIdFromSupabaseSession } from '@knowii/server';
18+
import {
19+
daoFnCreateCommunity,
20+
daoFnIsCommunityNameAvailable,
21+
daoFnIsCommunitySlugAvailable,
22+
errorMessageOptions,
23+
getInternalUserIdFromSupabaseSession,
24+
} from '@knowii/server';
1625
import { PrismaClient } from '@prisma/client';
1726

1827
export default async function handler(req: NextApiRequest, res: NextApiResponse<CreateCommunityResponse>) {
@@ -33,9 +42,19 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse<
3342
} = await supabaseClient.auth.getSession();
3443

3544
if (!session) {
36-
return res.status(401).json({
37-
error: errorClientNotAuthenticated.code,
38-
errorDetails: errorClientNotAuthenticated.description,
45+
return res.status(errorClientNotAuthenticated.statusCode).json({
46+
errors: {
47+
type: errorClientNotAuthenticated.type,
48+
title: errorClientNotAuthenticated.code,
49+
titleKey: errorClientNotAuthenticated.key,
50+
errorDetails: [
51+
{
52+
detail: errorClientNotAuthenticated.description,
53+
detailKey: errorClientNotAuthenticated.key,
54+
status: errorClientNotAuthenticated.statusCode,
55+
},
56+
],
57+
},
3958
});
4059
}
4160

@@ -45,10 +64,19 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse<
4564
const errorMessage = generateErrorMessage(requestValidationResult.error.issues, errorMessageOptions);
4665
logger.warn(`${errorInputValidation.description}. Error(s) detected: %s`, errorMessage);
4766

48-
res.status(400).json({
49-
error: errorInputValidation.code,
50-
errorDescription: errorInputValidation.description,
51-
errorDetails: errorMessage,
67+
res.status(errorInputValidation.statusCode).json({
68+
errors: {
69+
type: errorInputValidation.type,
70+
title: errorInputValidation.code,
71+
titleKey: errorInputValidation.key,
72+
errorDetails: [
73+
{
74+
detail: errorInputValidation.description,
75+
detailKey: errorInputValidation.key,
76+
status: errorInputValidation.statusCode,
77+
},
78+
],
79+
},
5280
});
5381
return;
5482
}
@@ -66,35 +94,101 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse<
6694
slug,
6795
};
6896

69-
logger.info('Proceeding with the creation: %o', creationPayload);
70-
7197
try {
7298
const prismaClient = new PrismaClient();
7399

74-
const createdCommunity = await daoFnCreateCommunity(creationPayload, prismaClient);
100+
logger.info('Verifying if the community name is available');
101+
const isCommunityNameAvailable = await daoFnIsCommunityNameAvailable(creationPayload.name, prismaClient);
102+
103+
if (!isCommunityNameAvailable) {
104+
logger.info('The community name is not available');
105+
return res.status(errorCommunityNameNotAvailable.statusCode).json({
106+
errors: {
107+
type: errorCommunityNameNotAvailable.type,
108+
title: errorCommunityNameNotAvailable.code,
109+
titleKey: errorCommunityNameNotAvailable.key,
110+
errorDetails: [
111+
{
112+
detail: errorCommunityNameNotAvailable.description,
113+
detailKey: errorCommunityNameNotAvailable.key,
114+
status: errorCommunityNameNotAvailable.statusCode,
115+
},
116+
],
117+
},
118+
});
119+
}
120+
121+
logger.info('Verifying if the community slug is available');
122+
const isCommunitySlugAvailable = await daoFnIsCommunitySlugAvailable(creationPayload.slug, prismaClient);
123+
124+
if (!isCommunitySlugAvailable) {
125+
logger.info('The community slug is not available');
126+
return res.status(errorCommunitySlugNotAvailable.statusCode).json({
127+
errors: {
128+
type: errorCommunitySlugNotAvailable.type,
129+
title: errorCommunitySlugNotAvailable.code,
130+
titleKey: errorCommunitySlugNotAvailable.key,
131+
errorDetails: [
132+
{
133+
detail: errorCommunitySlugNotAvailable.description,
134+
detailKey: errorCommunitySlugNotAvailable.key,
135+
status: errorCommunitySlugNotAvailable.statusCode,
136+
},
137+
],
138+
},
139+
});
140+
}
141+
142+
logger.info('Proceeding with the creation: %o', creationPayload);
143+
144+
const createdCommunity = <Communities>await daoFnCreateCommunity(creationPayload, prismaClient);
75145

76146
logger.info('Created community: %o', createdCommunity);
77147

78148
const responseBody: CreateCommunityResponse = {
79-
data: createdCommunity,
149+
data: {
150+
name: createdCommunity.name,
151+
description: createdCommunity.description,
152+
slug: createdCommunity.slug,
153+
},
80154
};
81155

82156
return res.status(200).json(responseBody);
83157
} catch (err: unknown) {
84158
if (hasErrorMessage(err)) {
85-
logger.warn('Error while creating a new community: %', err.message);
86-
87-
return res.status(500).json({
88-
error: errorInternalServerError.code,
89-
errorDescription: errorInternalServerError.description,
159+
logger.warn('Error while creating a new community: %o', err.message);
160+
161+
return res.status(errorInternalServerError.statusCode).json({
162+
errors: {
163+
type: errorInternalServerError.type,
164+
title: errorInternalServerError.code,
165+
titleKey: errorInternalServerError.key,
166+
errorDetails: [
167+
{
168+
detail: errorInternalServerError.description,
169+
detailKey: errorInternalServerError.key,
170+
status: errorInternalServerError.statusCode,
171+
},
172+
],
173+
},
90174
});
91175
}
92176

93177
logger.warn('Error while creating a new community: %o', err);
94178

95-
res.status(500).json({
96-
error: errorInternalServerError.code,
97-
errorDescription: errorInternalServerError.description,
179+
res.status(errorInternalServerError.statusCode).json({
180+
errors: {
181+
type: errorInternalServerError.type,
182+
title: errorInternalServerError.code,
183+
titleKey: errorInternalServerError.key,
184+
errorDetails: [
185+
{
186+
detail: errorInternalServerError.description,
187+
detailKey: errorInternalServerError.key,
188+
status: errorInternalServerError.statusCode,
189+
},
190+
],
191+
},
98192
});
99193
}
100194
}

apps/knowii/pages/api/v1/communities/is-community-name-available.ts

+55-14
Original file line numberDiff line numberDiff line change
@@ -32,9 +32,19 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse<
3232
} = await supabaseClient.auth.getSession();
3333

3434
if (!session) {
35-
return res.status(401).json({
36-
error: errorClientNotAuthenticated.code,
37-
errorDescription: errorClientNotAuthenticated.description,
35+
return res.status(errorClientNotAuthenticated.statusCode).json({
36+
errors: {
37+
type: errorClientNotAuthenticated.type,
38+
title: errorClientNotAuthenticated.code,
39+
titleKey: errorClientNotAuthenticated.key,
40+
errorDetails: [
41+
{
42+
detail: errorClientNotAuthenticated.description,
43+
detailKey: errorClientNotAuthenticated.key,
44+
status: errorClientNotAuthenticated.statusCode,
45+
},
46+
],
47+
},
3848
});
3949
}
4050

@@ -44,10 +54,19 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse<
4454
const errorMessage = generateErrorMessage(requestValidationResult.error.issues, errorMessageOptions);
4555
logger.warn(`${errorInputValidation.description}. Error(s) detected: %s`, errorMessage);
4656

47-
res.status(400).json({
48-
error: errorInputValidation.code,
49-
errorDescription: errorInputValidation.description,
50-
errorDetails: errorMessage,
57+
res.status(errorInputValidation.statusCode).json({
58+
errors: {
59+
type: errorInputValidation.type,
60+
title: errorInputValidation.code,
61+
titleKey: errorInputValidation.key,
62+
errorDetails: [
63+
{
64+
detail: errorInputValidation.description,
65+
detailKey: errorInputValidation.key,
66+
status: errorInputValidation.statusCode,
67+
},
68+
],
69+
},
5170
});
5271
return;
5372
}
@@ -65,24 +84,46 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse<
6584
logger.info('Community name is %s', isNameAvailable ? 'available' : 'not available');
6685

6786
const responseBody: IsCommunityNameAvailableResponse = {
68-
isNameAvailable,
87+
data: {
88+
isNameAvailable,
89+
},
6990
};
7091

7192
return res.status(200).json(responseBody);
7293
} catch (err: unknown) {
7394
if (hasErrorMessage(err)) {
7495
logger.warn('Error while checking for community name availability: %s', err.message);
75-
res.status(500).json({
76-
error: errorInternalServerError.code,
77-
errorDescription: errorInternalServerError.description,
96+
res.status(errorInternalServerError.statusCode).json({
97+
errors: {
98+
type: errorInternalServerError.type,
99+
title: errorInternalServerError.code,
100+
titleKey: errorInternalServerError.key,
101+
errorDetails: [
102+
{
103+
detail: errorInternalServerError.description,
104+
detailKey: errorInternalServerError.key,
105+
status: errorInternalServerError.statusCode,
106+
},
107+
],
108+
},
78109
});
79110
return;
80111
}
81112

82113
logger.warn('Error while checking for community name availability: %o', err);
83-
res.status(500).json({
84-
error: errorInternalServerError.code,
85-
errorDescription: errorInternalServerError.description,
114+
res.status(errorInternalServerError.statusCode).json({
115+
errors: {
116+
type: errorInternalServerError.type,
117+
title: errorInternalServerError.code,
118+
titleKey: errorInternalServerError.key,
119+
errorDetails: [
120+
{
121+
detail: errorInternalServerError.description,
122+
detailKey: errorInternalServerError.key,
123+
status: errorInternalServerError.statusCode,
124+
},
125+
],
126+
},
86127
});
87128
}
88129
}

apps/knowii/pages/api/v1/communities/is-community-slug-available.ts

+55-14
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,19 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse<
3131
} = await supabaseClient.auth.getSession();
3232

3333
if (!session) {
34-
return res.status(401).json({
35-
error: errorClientNotAuthenticated.code,
36-
errorDescription: errorClientNotAuthenticated.description,
34+
return res.status(errorClientNotAuthenticated.statusCode).json({
35+
errors: {
36+
type: errorClientNotAuthenticated.type,
37+
title: errorClientNotAuthenticated.code,
38+
titleKey: errorClientNotAuthenticated.key,
39+
errorDetails: [
40+
{
41+
detail: errorClientNotAuthenticated.description,
42+
detailKey: errorClientNotAuthenticated.key,
43+
status: errorClientNotAuthenticated.statusCode,
44+
},
45+
],
46+
},
3747
});
3848
}
3949

@@ -43,10 +53,19 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse<
4353
const errorMessage = generateErrorMessage(requestValidationResult.error.issues, errorMessageOptions);
4454
logger.warn(`${errorInputValidation.description}. Error(s) detected: %s`, errorMessage);
4555

46-
res.status(400).json({
47-
error: errorInputValidation.code,
48-
errorDescription: errorInputValidation.description,
49-
errorDetails: errorMessage,
56+
res.status(errorInputValidation.statusCode).json({
57+
errors: {
58+
type: errorInputValidation.type,
59+
title: errorInputValidation.code,
60+
titleKey: errorInputValidation.key,
61+
errorDetails: [
62+
{
63+
detail: errorInputValidation.description,
64+
detailKey: errorInputValidation.key,
65+
status: errorInputValidation.statusCode,
66+
},
67+
],
68+
},
5069
});
5170
return;
5271
}
@@ -63,24 +82,46 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse<
6382
logger.info('Community slug is %s', isSlugAvailable ? 'available' : 'not available');
6483

6584
const responseBody: IsCommunitySlugAvailableResponse = {
66-
isSlugAvailable,
85+
data: {
86+
isSlugAvailable,
87+
},
6788
};
6889

6990
return res.status(200).json(responseBody);
7091
} catch (err: unknown) {
7192
if (hasErrorMessage(err)) {
7293
logger.warn('Error while checking for community slug availability: %', err.message);
73-
res.status(500).json({
74-
error: errorInternalServerError.code,
75-
errorDescription: errorInternalServerError.description,
94+
res.status(errorInternalServerError.statusCode).json({
95+
errors: {
96+
type: errorInternalServerError.type,
97+
title: errorInternalServerError.code,
98+
titleKey: errorInternalServerError.key,
99+
errorDetails: [
100+
{
101+
detail: errorInternalServerError.description,
102+
detailKey: errorInternalServerError.key,
103+
status: errorInternalServerError.statusCode,
104+
},
105+
],
106+
},
76107
});
77108
return;
78109
}
79110

80111
logger.warn('Error while checking for community slug availability: %o', err);
81-
res.status(500).json({
82-
error: errorInternalServerError.code,
83-
errorDescription: errorInternalServerError.description,
112+
res.status(errorInternalServerError.statusCode).json({
113+
errors: {
114+
type: errorInternalServerError.type,
115+
title: errorInternalServerError.code,
116+
titleKey: errorInternalServerError.key,
117+
errorDetails: [
118+
{
119+
detail: errorInternalServerError.description,
120+
detailKey: errorInternalServerError.key,
121+
status: errorInternalServerError.statusCode,
122+
},
123+
],
124+
},
84125
});
85126
}
86127
}

0 commit comments

Comments
 (0)