Skip to content

Commit f040b27

Browse files
ahmed-n-abdeltwabcardosoggazzo
authored
feat: Add OpenAPI Support to oauth-apps.create API (#36507)
Co-authored-by: Matheus Cardoso <matheus@cardo.so> Co-authored-by: Guilherme Gazzo <guilherme@gazzo.xyz>
1 parent 7d94976 commit f040b27

File tree

7 files changed

+107
-42
lines changed

7 files changed

+107
-42
lines changed

.changeset/clean-flies-glow.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 oauth-apps.create API 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/oauthapps.ts

Lines changed: 98 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
1+
import type { IOAuthApps } from '@rocket.chat/core-typings';
12
import { OAuthApps } from '@rocket.chat/models';
2-
import { isUpdateOAuthAppParams, isOauthAppsGetParams, isOauthAppsAddParams, isDeleteOAuthAppParams } from '@rocket.chat/rest-typings';
3+
import { ajv, isUpdateOAuthAppParams, isOauthAppsGetParams, isDeleteOAuthAppParams } from '@rocket.chat/rest-typings';
34

45
import { hasPermissionAsync } from '../../../authorization/server/functions/hasPermission';
56
import { apiDeprecationLogger } from '../../../lib/server/lib/deprecationWarningLogger';
67
import { addOAuthApp } from '../../../oauth2-server-config/server/admin/functions/addOAuthApp';
78
import { deleteOAuthApp } from '../../../oauth2-server-config/server/admin/methods/deleteOAuthApp';
89
import { updateOAuthApp } from '../../../oauth2-server-config/server/admin/methods/updateOAuthApp';
10+
import type { ExtractRoutesFromAPI } from '../ApiClass';
911
import { API } from '../api';
1012

1113
API.v1.addRoute(
@@ -83,18 +85,106 @@ API.v1.addRoute(
8385
},
8486
);
8587

86-
API.v1.addRoute(
88+
export type OauthAppsAddParams = {
89+
name: string;
90+
active: boolean;
91+
redirectUri: string;
92+
};
93+
94+
const OauthAppsAddParamsSchema = {
95+
type: 'object',
96+
properties: {
97+
name: {
98+
type: 'string',
99+
},
100+
active: {
101+
type: 'boolean',
102+
},
103+
redirectUri: {
104+
type: 'string',
105+
},
106+
},
107+
required: ['name', 'active', 'redirectUri'],
108+
additionalProperties: false,
109+
};
110+
111+
const isOauthAppsAddParams = ajv.compile<OauthAppsAddParams>(OauthAppsAddParamsSchema);
112+
113+
const oauthAppsCreateEndpoints = API.v1.post(
87114
'oauth-apps.create',
88115
{
89116
authRequired: true,
90-
validateParams: isOauthAppsAddParams,
117+
body: isOauthAppsAddParams,
91118
permissionsRequired: ['manage-oauth-apps'],
119+
response: {
120+
400: ajv.compile<{
121+
error?: string;
122+
errorType?: string;
123+
stack?: string;
124+
details?: object;
125+
}>({
126+
type: 'object',
127+
properties: {
128+
success: { type: 'boolean', enum: [false] },
129+
stack: { type: 'string' },
130+
error: { type: 'string' },
131+
errorType: { type: 'string' },
132+
details: { type: 'object' },
133+
},
134+
required: ['success'],
135+
additionalProperties: false,
136+
}),
137+
401: ajv.compile({
138+
type: 'object',
139+
properties: {
140+
success: { type: 'boolean', enum: [false] },
141+
status: { type: 'string' },
142+
message: { type: 'string' },
143+
error: { type: 'string' },
144+
errorType: { type: 'string' },
145+
},
146+
required: ['success'],
147+
additionalProperties: false,
148+
}),
149+
403: ajv.compile({
150+
type: 'object',
151+
properties: {
152+
success: { type: 'boolean', enum: [false] },
153+
status: { type: 'string' },
154+
message: { type: 'string' },
155+
error: { type: 'string' },
156+
errorType: { type: 'string' },
157+
},
158+
required: ['success'],
159+
additionalProperties: false,
160+
}),
161+
200: ajv.compile<{ application: IOAuthApps }>({
162+
type: 'object',
163+
properties: {
164+
application: { $ref: '#/components/schemas/IOAuthApps' },
165+
success: {
166+
type: 'boolean',
167+
enum: [true],
168+
},
169+
},
170+
required: ['application', 'success'],
171+
additionalProperties: false,
172+
}),
173+
},
92174
},
93-
{
94-
async post() {
95-
const application = await addOAuthApp(this.bodyParams, this.userId);
96175

97-
return API.v1.success({ application });
98-
},
176+
async function action() {
177+
const application = await addOAuthApp(this.bodyParams, this.userId);
178+
179+
return API.v1.success({ application });
99180
},
100181
);
182+
183+
type OauthAppsCreateEndpoints = ExtractRoutesFromAPI<typeof oauthAppsCreateEndpoints>;
184+
185+
export type OAuthAppsEndpoints = OauthAppsCreateEndpoints;
186+
187+
declare module '@rocket.chat/rest-typings' {
188+
// eslint-disable-next-line @typescript-eslint/naming-convention, @typescript-eslint/no-empty-interface
189+
interface Endpoints extends OauthAppsCreateEndpoints {}
190+
}

apps/meteor/app/oauth2-server-config/server/admin/functions/addOAuthApp.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
import type { IOAuthApps, IUser } from '@rocket.chat/core-typings';
22
import { OAuthApps, Users } from '@rocket.chat/models';
33
import { Random } from '@rocket.chat/random';
4-
import type { OauthAppsAddParams } from '@rocket.chat/rest-typings';
54
import { Meteor } from 'meteor/meteor';
65

76
import { parseUriList } from './parseUriList';
7+
import type { OauthAppsAddParams } from '../../../../api/server/v1/oauthapps';
88
import { hasPermissionAsync } from '../../../../authorization/server/functions/hasPermission';
99

1010
export async function addOAuthApp(applicationParams: OauthAppsAddParams, uid: IUser['_id'] | undefined): Promise<IOAuthApps> {

packages/core-typings/src/Ajv.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import typia from 'typia';
33
import type { ICustomSound } from './ICustomSound';
44
import type { IInvite } from './IInvite';
55
import type { IMessage } from './IMessage';
6+
import type { IOAuthApps } from './IOAuthApps';
67
import type { ISubscription } from './ISubscription';
78

8-
export const schemas = typia.json.schemas<[ISubscription | IInvite | ICustomSound | IMessage], '3.0'>();
9+
export const schemas = typia.json.schemas<[ISubscription | IInvite | ICustomSound | IMessage | IOAuthApps], '3.0'>();

packages/rest-typings/src/index.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -237,7 +237,6 @@ export * from './v1/omnichannel';
237237
export * from './v1/oauthapps';
238238
export * from './v1/oauthapps/UpdateOAuthAppParamsPOST';
239239
export * from './v1/oauthapps/OAuthAppsGetParamsGET';
240-
export * from './v1/oauthapps/OAuthAppsAddParamsPOST';
241240
export * from './v1/oauthapps/DeleteOAuthAppParamsDELETE';
242241
export * from './helpers/PaginatedRequest';
243242
export * from './helpers/PaginatedResult';

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

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import type { IOAuthApps, IUser } from '@rocket.chat/core-typings';
22

33
import type { DeleteOAuthAppParams } from './oauthapps/DeleteOAuthAppParamsDELETE';
4-
import type { OauthAppsAddParams } from './oauthapps/OAuthAppsAddParamsPOST';
54
import type { OauthAppsGetParams } from './oauthapps/OAuthAppsGetParamsGET';
65
import type { UpdateOAuthAppParams } from './oauthapps/UpdateOAuthAppParamsPOST';
76

@@ -18,10 +17,6 @@ export type OAuthAppsEndpoint = {
1817
};
1918
};
2019

21-
'/v1/oauth-apps.create': {
22-
POST: (params: OauthAppsAddParams) => { application: IOAuthApps };
23-
};
24-
2520
'/v1/oauth-apps.update': {
2621
POST: (params: UpdateOAuthAppParams) => IOAuthApps | null;
2722
};

packages/rest-typings/src/v1/oauthapps/OAuthAppsAddParamsPOST.ts

Lines changed: 0 additions & 26 deletions
This file was deleted.

0 commit comments

Comments
 (0)