feat: Add OpenAPI Support to oauth-apps.get API (#36598)

Co-authored-by: Matheus Cardoso <matheus@cardo.so>
Co-authored-by: Guilherme Gazzo <guilherme@gazzo.xyz>
This commit is contained in:
Ahmed Nasser 2025-08-08 18:36:37 +03:00 committed by GitHub
parent 68499d4edc
commit 17bca96ecb
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 80 additions and 68 deletions

View File

@ -0,0 +1,7 @@
---
"@rocket.chat/meteor": patch
"@rocket.chat/core-typings": patch
"@rocket.chat/rest-typings": patch
---
Add OpenAPI support for the Rocket.Chat oauth-apps.get 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.

View File

@ -303,6 +303,8 @@ export type TypedThis<TOptions extends TypedOptions, TPath extends string = ''>
bodyParams: TOptions['body'] extends ValidateFunction<infer Body> ? Body : never;
requestIp?: string;
route: string;
response: Response;
};
type PromiseOrValue<T> = T | Promise<T>;

View File

@ -2,7 +2,6 @@ import type { IOAuthApps } from '@rocket.chat/core-typings';
import { OAuthApps } from '@rocket.chat/models';
import {
ajv,
isOauthAppsGetParams,
validateUnauthorizedErrorResponse,
validateBadRequestErrorResponse,
validateForbiddenErrorResponse,
@ -89,6 +88,45 @@ const UpdateOAuthAppParamsSchema = {
const isUpdateOAuthAppParams = ajv.compile<UpdateOAuthAppParams>(UpdateOAuthAppParamsSchema);
type OauthAppsGetParams = { clientId: string } | { appId: string } | { _id: string };
const oauthAppsGetParamsSchema = {
oneOf: [
{
type: 'object',
properties: {
_id: {
type: 'string',
},
},
required: ['_id'],
additionalProperties: false,
},
{
type: 'object',
properties: {
clientId: {
type: 'string',
},
},
required: ['clientId'],
additionalProperties: false,
},
{
type: 'object',
properties: {
appId: {
type: 'string',
},
},
required: ['appId'],
additionalProperties: false,
},
],
};
const isOauthAppsGetParams = ajv.compile<OauthAppsGetParams>(oauthAppsGetParamsSchema);
const oauthAppsEndpoints = API.v1
.get(
'oauth-apps.list',
@ -218,13 +256,31 @@ const oauthAppsEndpoints = API.v1
return API.v1.success(result);
},
);
)
.get(
'oauth-apps.get',
{
authRequired: true,
query: isOauthAppsGetParams,
response: {
400: validateBadRequestErrorResponse,
401: validateUnauthorizedErrorResponse,
200: ajv.compile<{ oauthApp: IOAuthApps }>({
type: 'object',
properties: {
oauthApp: { anyOf: [{ $ref: '#/components/schemas/IOAuthApps' }, { type: 'null' }] },
success: {
type: 'boolean',
enum: [true],
},
},
required: ['oauthApp', 'success'],
additionalProperties: false,
}),
},
},
API.v1.addRoute(
'oauth-apps.get',
{ authRequired: true, validateParams: isOauthAppsGetParams },
{
async get() {
async function action() {
const isOAuthAppsManager = await hasPermissionAsync(this.userId, 'manage-oauth-apps');
const oauthApp = await OAuthApps.findOneAuthAppByIdOrClientId(
@ -244,8 +300,7 @@ API.v1.addRoute(
oauthApp,
});
},
},
);
);
export type OauthAppsEndpoints = ExtractRoutesFromAPI<typeof oauthAppsEndpoints>;

View File

@ -286,8 +286,9 @@ describe('[OAuthApps]', () => {
.expect(400)
.expect((res) => {
expect(res.body).to.have.property('success', false);
expect(res.body).to.have.property('errorType', 'error-invalid-params');
expect(res.body).to.have.property('error');
expect(res.body.error).to.include('must be string').and.include('must match exactly one schema in oneOf [invalid-params]');
expect(res.body.error).to.include('must be string').and.include('must match exactly one schema in oneOf');
});
});
@ -311,8 +312,9 @@ describe('[OAuthApps]', () => {
.expect(400)
.expect((res) => {
expect(res.body).to.have.property('success', false);
expect(res.body).to.have.property('errorType', 'error-invalid-params');
expect(res.body).to.have.property('error');
expect(res.body.error).to.include('must be string').and.include('must match exactly one schema in oneOf [invalid-params]');
expect(res.body.error).to.include('must be string').and.include('must match exactly one schema in oneOf');
});
});
@ -336,8 +338,9 @@ describe('[OAuthApps]', () => {
.expect(400)
.expect((res) => {
expect(res.body).to.have.property('success', false);
expect(res.body).to.have.property('errorType', 'error-invalid-params');
expect(res.body).to.have.property('error');
expect(res.body.error).to.include('must be string').and.include('must match exactly one schema in oneOf [invalid-params]');
expect(res.body.error).to.include('must be string').and.include('must match exactly one schema in oneOf');
});
});

View File

@ -3,7 +3,7 @@ export interface IOAuthApps {
name: string;
active: boolean;
clientId: string;
clientSecret: string;
clientSecret?: string;
redirectUri: string;
_createdAt: Date;
_createdBy: {

View File

@ -33,7 +33,6 @@ import type { MailerEndpoints } from './v1/mailer';
import type { MeEndpoints } from './v1/me';
import type { MiscEndpoints } from './v1/misc';
import type { ModerationEndpoints } from './v1/moderation';
import type { OAuthAppsEndpoint } from './v1/oauthapps';
import type { OmnichannelEndpoints } from './v1/omnichannel';
import type { PresenceEndpoints } from './v1/presence';
import type { PushEndpoints } from './v1/push';
@ -89,7 +88,6 @@ export interface Endpoints
AssetsEndpoints,
EmailInboxEndpoints,
MailerEndpoints,
OAuthAppsEndpoint,
SubscriptionsEndpoints,
AutoTranslateEndpoints,
ImportEndpoints,
@ -231,8 +229,6 @@ export * from './v1/dm/DmHistoryProps';
export * from './v1/integrations';
export * from './v1/licenses';
export * from './v1/omnichannel';
export * from './v1/oauthapps';
export * from './v1/oauthapps/OAuthAppsGetParamsGET';
export * from './helpers/PaginatedRequest';
export * from './helpers/PaginatedResult';
export * from './helpers/ReplacePlaceholders';

View File

@ -1,11 +0,0 @@
import type { IOAuthApps } from '@rocket.chat/core-typings';
import type { OauthAppsGetParams } from './oauthapps/OAuthAppsGetParamsGET';
export type OAuthAppsEndpoint = {
'/v1/oauth-apps.get': {
GET: (params: OauthAppsGetParams) => {
oauthApp: IOAuthApps;
};
};
};

View File

@ -1,40 +0,0 @@
import { ajv } from '../Ajv';
export type OauthAppsGetParams = { clientId: string } | { appId: string } | { _id: string };
const oauthAppsGetParamsSchema = {
oneOf: [
{
type: 'object',
properties: {
_id: {
type: 'string',
},
},
required: ['_id'],
additionalProperties: false,
},
{
type: 'object',
properties: {
clientId: {
type: 'string',
},
},
required: ['clientId'],
additionalProperties: false,
},
{
type: 'object',
properties: {
appId: {
type: 'string',
},
},
required: ['appId'],
additionalProperties: false,
},
],
};
export const isOauthAppsGetParams = ajv.compile<OauthAppsGetParams>(oauthAppsGetParamsSchema);