Skip to content

Commit 0d4b946

Browse files
Add OpenAPI support for the Rocket.Chat rooms.favorite APIs endpoints by migrating to a modern chained route definition syntax and utilizing shared AJV schemas for validation to enhance API documentation and ensure type safety through response validation.
1 parent b08592e commit 0d4b946

3 files changed

Lines changed: 84 additions & 41 deletions

File tree

.changeset/tricky-boxes-type.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
"@rocket.chat/meteor": patch
3+
"@rocket.chat/rest-typings": patch
4+
---
5+
6+
Add OpenAPI support for the Rocket.Chat rooms.favorite APIs endpoints by migrating to a modern chained route definition syntax and utilizing shared AJV schemas for validation to enhance API documentation and ensure type safety through response validation.

apps/meteor/app/api/server/v1/rooms.ts

Lines changed: 78 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -311,26 +311,6 @@ API.v1.addRoute(
311311
},
312312
);
313313

314-
API.v1.addRoute(
315-
'rooms.favorite',
316-
{ authRequired: true },
317-
{
318-
async post() {
319-
const { favorite } = this.bodyParams;
320-
321-
if (!this.bodyParams.hasOwnProperty('favorite')) {
322-
return API.v1.failure("The 'favorite' param is required");
323-
}
324-
325-
const room = await findRoomByIdOrName({ params: this.bodyParams });
326-
327-
await toggleFavoriteMethod(this.userId, room._id, favorite);
328-
329-
return API.v1.success();
330-
},
331-
},
332-
);
333-
334314
API.v1.addRoute(
335315
'rooms.cleanHistory',
336316
{ authRequired: true, validateParams: isRoomsCleanHistoryProps },
@@ -945,6 +925,16 @@ API.v1.addRoute(
945925
},
946926
);
947927

928+
type RoomsFavorite =
929+
| {
930+
roomId: string;
931+
favorite: boolean;
932+
}
933+
| {
934+
roomName: string;
935+
favorite: boolean;
936+
};
937+
948938
const isRoomGetRolesPropsSchema = {
949939
type: 'object',
950940
properties: {
@@ -953,6 +943,32 @@ const isRoomGetRolesPropsSchema = {
953943
additionalProperties: false,
954944
required: ['rid'],
955945
};
946+
947+
const RoomsFavoriteSchema = {
948+
anyOf: [
949+
{
950+
type: 'object',
951+
properties: {
952+
favorite: { type: 'boolean' },
953+
roomName: { type: 'string' },
954+
},
955+
required: ['roomName', 'favorite'],
956+
additionalProperties: false,
957+
},
958+
{
959+
type: 'object',
960+
properties: {
961+
favorite: { type: 'boolean' },
962+
roomId: { type: 'string' },
963+
},
964+
required: ['roomId', 'favorite'],
965+
additionalProperties: false,
966+
},
967+
],
968+
};
969+
970+
const isRoomsFavoriteProps = ajv.compile<RoomsFavorite>(RoomsFavoriteSchema);
971+
956972
export const roomEndpoints = API.v1
957973
.get(
958974
'rooms.roles',
@@ -1066,9 +1082,8 @@ export const roomEndpoints = API.v1
10661082
total,
10671083
});
10681084
},
1069-
);
1070-
1071-
const roomInviteEndpoints = API.v1.post(
1085+
)
1086+
.post(
10721087
'rooms.invite',
10731088
{
10741089
authRequired: true,
@@ -1089,16 +1104,52 @@ const roomInviteEndpoints = API.v1.post(
10891104
async function action() {
10901105
const { roomId, action } = this.bodyParams;
10911106

1092-
try {
1107+
try {
10931108
await FederationMatrix.handleInvite(roomId, this.userId, action);
10941109
return API.v1.success();
10951110
} catch (error) {
10961111
return API.v1.failure({ error: `Failed to handle invite: ${error instanceof Error ? error.message : String(error)}` });
10971112
}
1098-
},
1099-
);
1113+
1114+
},
1115+
)
1116+
.post(
1117+
'rooms.favorite',
1118+
{
1119+
authRequired: true,
1120+
body: isRoomsFavoriteProps,
1121+
response: {
1122+
200: ajv.compile<void>({
1123+
type: 'object',
1124+
properties: {
1125+
success: {
1126+
type: 'boolean',
1127+
description: 'Indicates if the request was successful.',
1128+
},
1129+
},
1130+
required: ['success'],
1131+
additionalProperties: false,
1132+
}),
1133+
400: validateBadRequestErrorResponse,
1134+
401: validateUnauthorizedErrorResponse,
1135+
},
1136+
},
1137+
async function action() {
1138+
const { favorite } = this.bodyParams;
1139+
1140+
if (!this.bodyParams.hasOwnProperty('favorite')) {
1141+
return API.v1.failure("The 'favorite' param is required");
1142+
}
1143+
1144+
const room = await findRoomByIdOrName({ params: this.bodyParams });
1145+
1146+
await toggleFavoriteMethod(this.userId, room._id, favorite);
1147+
1148+
return API.v1.success();
1149+
},
1150+
);
11001151

1101-
type RoomEndpoints = ExtractRoutesFromAPI<typeof roomEndpoints> & ExtractRoutesFromAPI<typeof roomInviteEndpoints>;
1152+
type RoomEndpoints = ExtractRoutesFromAPI<typeof roomEndpoints>;
11021153

11031154
declare module '@rocket.chat/rest-typings' {
11041155
// eslint-disable-next-line @typescript-eslint/naming-convention, @typescript-eslint/no-empty-interface

packages/rest-typings/src/v1/rooms.ts

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -805,20 +805,6 @@ export type RoomsEndpoints = {
805805
POST: (params: { roomId: string; notifications: Notifications }) => void;
806806
};
807807

808-
'/v1/rooms.favorite': {
809-
POST: (
810-
params:
811-
| {
812-
roomId: string;
813-
favorite: boolean;
814-
}
815-
| {
816-
roomName: string;
817-
favorite: boolean;
818-
},
819-
) => void;
820-
};
821-
822808
'/v1/rooms.nameExists': {
823809
GET: (params: { roomName: string }) => {
824810
exists: boolean;

0 commit comments

Comments
 (0)