Skip to content

Conversation

ahmed-n-abdeltwab
Copy link
Contributor

@ahmed-n-abdeltwab ahmed-n-abdeltwab commented Sep 16, 2025

Description:
This PR integrates OpenAPI support into the Rocket.Chat API, migrate of Rocket.Chat API endpoints to the new OpenAPI pattern. The update includes improved API documentation, enhanced type safety, and response validation using AJV.

Key Changes:

  • Implemented the new pattern and added AJV-based JSON schema validation for API.
  • Uses the ExtractRoutesFromAPI utility from the TypeScript definitions to dynamically derive the routes from the endpoint specifications.
  • Enabled Swagger UI integration for this API.
  • Route Methods Chaining for the endpoints.
  • This does not introduce any breaking changes to the endpoint logic.

Issue Reference:
Relates to #34983, part of the ongoing OpenAPI integration effort.

Testing:

  • Verified that the API response schemas are correctly documented in Swagger UI.

  • All tests passed without any breaking changes

    $ yarn testapi -f '[Commands]'
    
    
    [Commands]
      [/commands.get]
        ✔ should return an error when call the endpoint without "command" required parameter
        ✔ should return an error when call the endpoint with an invalid command
        ✔ should return success when parameters are correct
      [/commands.list]
        ✔ should return a list of commands
        ✔ should return a list of commands even requested with count and offset params (196ms)
      [/commands.run]
        ✔ should return an error when call the endpoint without "command" required parameter
        ✔ should return an error when call the endpoint with the param "params" and it is not a string
        ✔ should return an error when call the endpoint without "roomId" required parameter
        ✔ should return an error when call the endpoint with the param "tmid" and it is not a string
        ✔ should return an error when call the endpoint with the invalid "command" param
        ✔ should return an error when call the endpoint with an invalid thread id
        ✔ should return an error when call the endpoint with a valid thread id of wrong channel
        ✔ should return success when parameters are correct (140ms)
      Command archive
        unauthorized cases
          ✔ should return an error when the user is not logged in
          ✔ should return an error when the user has not enough permissions (42ms)
        authorized cases
          ✔ should return a success when the user has enough permissions (77ms)
      Command unarchive
        unauthorized cases
          ✔ should return an error when the user is not logged in
          ✔ should return an error when the user has not enough permissions
        authorized cases
          ✔ should return a success when the user has enough permissions
      Command "invite-all-from"
        ✔ should not add users from group which is not accessible by current user
        ✔ should not add users to a room that is not accessible by the current user
        ✔ should add users from group which is accessible by current user (127ms)
    
    
    22 passing (7s)

Endpoints:

Looking forward to your feedback! 🚀

Summary by CodeRabbit

  • New Features
    • Enhanced /commands.get API with OpenAPI support and schema-validated responses.
    • Standardized validation errors for missing/invalid parameters.
  • Documentation
    • Updated API documentation for /commands.get with clearer request/response definitions.
  • Refactor
    • Modernized the /commands.get route implementation to use typed, schema-based validation while preserving behavior.
  • Tests
    • Adjusted tests to match standardized validation error messages.
  • Chores
    • Bumped patch versions of @rocket.chat/meteor and @rocket.chat/rest-typings.

Copy link
Contributor

dionisio-bot bot commented Sep 16, 2025

Looks like this PR is not ready to merge, because of the following issues:

  • This PR is missing the 'stat: QA assured' label
  • This PR is missing the required milestone or project

Please fix the issues and try again

If you have any trouble, please check the PR guidelines

Copy link

changeset-bot bot commented Sep 16, 2025

🦋 Changeset detected

Latest commit: bb7646b

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 39 packages
Name Type
@rocket.chat/meteor Patch
@rocket.chat/rest-typings Patch
@rocket.chat/api-client Patch
@rocket.chat/core-services Patch
@rocket.chat/ddp-client Patch
@rocket.chat/http-router Patch
@rocket.chat/models Patch
@rocket.chat/ui-contexts Patch
@rocket.chat/web-ui-registration Patch
@rocket.chat/account-service Patch
@rocket.chat/authorization-service Patch
@rocket.chat/ddp-streamer Patch
@rocket.chat/stream-hub-service Patch
@rocket.chat/omnichannel-services Patch
@rocket.chat/presence Patch
rocketchat-services Patch
@rocket.chat/omnichannel-transcript Patch
@rocket.chat/presence-service Patch
@rocket.chat/queue-worker Patch
@rocket.chat/network-broker Patch
@rocket.chat/omni-core-ee Patch
@rocket.chat/livechat Patch
@rocket.chat/mock-providers Patch
@rocket.chat/cron Patch
@rocket.chat/instance-status Patch
@rocket.chat/omni-core Patch
@rocket.chat/uikit-playground Patch
@rocket.chat/fuselage-ui-kit Patch
@rocket.chat/gazzodown Patch
@rocket.chat/ui-avatar Patch
@rocket.chat/ui-client Patch
@rocket.chat/ui-video-conf Patch
@rocket.chat/ui-voip Patch
@rocket.chat/core-typings Patch
@rocket.chat/apps Patch
@rocket.chat/freeswitch Patch
@rocket.chat/model-typings Patch
@rocket.chat/license Patch
@rocket.chat/pdf-worker Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

Copy link

coderabbitai bot commented Sep 16, 2025

Walkthrough

Refactors GET /v1/commands.get to a typed, AJV-validated route with OpenAPI-capable chained definitions, adds shared schema-based validation and standardized error responses, updates corresponding public typings via ExtractRoutesFromAPI, adjusts an E2E test message expectation, removes the previous static endpoint typing, and adds a changeset bump.

Changes

Cohort / File(s) Summary
API route refactor and typings exposure
apps/meteor/app/api/server/v1/commands.ts
Migrates commands.get to API.v1.get with AJV query validation, explicit 200/400/401 response mappings, async handler using slashCommands, and exports CommandsEndpoints plus module augmentation for @rocket.chat/rest-typings.
REST typings realignment
packages/rest-typings/src/v1/commands.ts
Removes static '/v1/commands.get' endpoint signature; public typings will be sourced from server route extraction.
E2E test update
apps/meteor/tests/end-to-end/api/commands.ts
Updates missing-parameter test to expect JSON Schema message: "must have required property 'command'".
Changeset
.changeset/wet-roses-call.md
Declares patch bumps for @rocket.chat/meteor and @rocket.chat/rest-typings; notes OpenAPI/AJV migration for commands.get.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor Client
  participant API as API v1 (commands.get)
  participant AJV as Validator (AJV)
  participant SC as slashCommands Registry

  Client->>API: GET /v1/commands.get?command=...
  API->>AJV: Validate query { command }
  alt Invalid query
    AJV-->>API: Validation error
    API-->>Client: 400 { success:false, error:"must have required property 'command'" }
  else Valid query
    API->>SC: Lookup command (toLowerCase)
    alt Command not found
      SC-->>API: undefined
      API-->>Client: 400 { success:false, error:"The required \"command\" param is invalid" }
    else Command found
      SC-->>API: { clientOnly, command, description, params, providesPreview }
      API-->>Client: 200 { success:true, command:{ ... } }
    end
  end
  opt Unauthorized
    API-->>Client: 401 { success:false, error: "unauthorized" }
  end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

A twitch of whiskers, schemas align,
I hop through routes with AJV’s sign.
Commands now typed, the paths are clear,
OpenAPI maps what peers can hear.
Tests squeak twice—new words in tow—
Patch bumps nibble, onward we go! 🐇✨

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed The title succinctly and accurately describes the primary change — adding OpenAPI support for the commands.get endpoint — using a conventional commit prefix and readable phrasing; it is specific to the main change in the diff and not overly broad or noisy.
Docstring Coverage ✅ Passed No functions found in the changes. Docstring coverage check skipped.
✨ Finishing touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Tip

👮 Agentic pre-merge checks are now available in preview!

Pro plan users can now enable pre-merge checks in their settings to enforce checklists before merging PRs.

  • Built-in checks – Quickly apply ready-made checks to enforce title conventions, require pull request descriptions that follow templates, validate linked issues for compliance, and more.
  • Custom agentic checks – Define your own rules using CodeRabbit’s advanced agentic capabilities to enforce organization-specific policies and workflows. For example, you can instruct CodeRabbit’s agent to verify that API documentation is updated whenever API schema files are modified in a PR. Note: Upto 5 custom checks are currently allowed during the preview period. Pricing for this feature will be announced in a few weeks.

Please see the documentation for more information.

Example:

reviews:
  pre_merge_checks:
    custom_checks:
      - name: "Undocumented Breaking Changes"
        mode: "warning"
        instructions: |
          Pass/fail criteria: All breaking changes to public APIs, CLI flags, environment variables, configuration keys, database schemas, or HTTP/GraphQL endpoints must be documented in the "Breaking Change" section of the PR description and in CHANGELOG.md. Exclude purely internal or private changes (e.g., code not exported from package entry points or explicitly marked as internal).

Please share your feedback with us on this Discord post.


Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (5)
.changeset/wet-roses-call.md (1)

6-6: Clarify scope and cross-reference the tracking issue

Nit: s/"endpoints"/"endpoint"/ if only commands.get is migrated here, and add "Refs #34983" for traceability.

Apply this diff:

-Add OpenAPI support for the Rocket.Chat commands.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.
+Add OpenAPI support for the Rocket.Chat commands.get API endpoint 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. Refs #34983.
apps/meteor/app/api/server/v1/commands.ts (3)

65-65: Type the query params

Cast to CommandsGetParams to align with the validated schema and improve editor tooling.

Apply this diff:

-		const params = this.queryParams;
+		const params = this.queryParams as CommandsGetParams;

67-69: Redundant runtime check; Ajv already enforces this

query: isCommandsGetParams rejects missing/non-string command before action() runs. Drop this branch to avoid conflicting messages with schema errors.

Apply this diff:

-		if (typeof params.command !== 'string') {
-			return API.v1.failure('The query param "command" must be provided.');
-		}

29-31: Naming nit: singular endpoint const

It holds a single GET route; singular reads clearer and matches usage in the exported type alias.

Apply this diff:

-const commandsEndpoints = API.v1.get(
+const commandsGetEndpoint = API.v1.get(

and

-export type CommandsEndpoints = ExtractRoutesFromAPI<typeof commandsEndpoints>;
+export type CommandsEndpoints = ExtractRoutesFromAPI<typeof commandsGetEndpoint>;

Also applies to: 385-386

apps/meteor/tests/end-to-end/api/commands.ts (1)

25-25: Avoid brittle equality on Ajv error text

Ajv message wording can change across versions. Assert key fragment instead.

Apply this diff:

-					expect(res.body.error).to.be.equal(`must have required property 'command'`);
+					expect(res.body.error).to.include(`required property 'command'`);
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Jira integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between a087f72 and bb7646b.

📒 Files selected for processing (4)
  • .changeset/wet-roses-call.md (1 hunks)
  • apps/meteor/app/api/server/v1/commands.ts (2 hunks)
  • apps/meteor/tests/end-to-end/api/commands.ts (1 hunks)
  • packages/rest-typings/src/v1/commands.ts (0 hunks)
💤 Files with no reviewable changes (1)
  • packages/rest-typings/src/v1/commands.ts
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-09-16T22:08:51.490Z
Learnt from: CR
PR: RocketChat/Rocket.Chat#0
File: .cursor/rules/playwright.mdc:0-0
Timestamp: 2025-09-16T22:08:51.490Z
Learning: Applies to apps/meteor/tests/e2e/**/*.spec.ts : Use descriptive test names that clearly communicate expected behavior

Applied to files:

  • apps/meteor/tests/end-to-end/api/commands.ts
🧬 Code graph analysis (1)
apps/meteor/app/api/server/v1/commands.ts (2)
packages/rest-typings/src/v1/Ajv.ts (3)
  • ajv (23-23)
  • validateBadRequestErrorResponse (46-46)
  • validateUnauthorizedErrorResponse (69-69)
packages/rest-typings/src/index.ts (1)
  • Endpoints (52-100)

Comment on lines +37 to +61
200: ajv.compile<{
command: Pick<SlashCommand, 'clientOnly' | 'command' | 'description' | 'params' | 'providesPreview'>;
}>({
type: 'object',
properties: {
command: {
type: 'object',
properties: {
clientOnly: { type: 'boolean' },
command: { type: 'string' },
description: { type: 'string' },
params: { type: 'string' },
providesPreview: { type: 'boolean' },
},
required: ['command', 'providesPreview'],
},
success: {
type: 'boolean',
enum: [true],
},
},
required: ['command', 'success'],
additionalProperties: false,
}),
},
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

200-response validator type omits success: true; tighten types and nested schema

The Ajv generic for 200 currently excludes success, while the schema requires it. This weakens extracted typings. Also consider freezing the nested command shape for cleaner OpenAPI docs.

Apply this diff:

-			200: ajv.compile<{
-				command: Pick<SlashCommand, 'clientOnly' | 'command' | 'description' | 'params' | 'providesPreview'>;
-			}>({
+			200: ajv.compile<{
+				command: Pick<SlashCommand, 'clientOnly' | 'command' | 'description' | 'params' | 'providesPreview'>;
+				success: true;
+			}>({
 				type: 'object',
 				properties: {
 					command: {
 						type: 'object',
 						properties: {
 							clientOnly: { type: 'boolean' },
 							command: { type: 'string' },
 							description: { type: 'string' },
 							params: { type: 'string' },
 							providesPreview: { type: 'boolean' },
 						},
 						required: ['command', 'providesPreview'],
+						additionalProperties: false,
 					},
 					success: {
 						type: 'boolean',
 						enum: [true],
 					},
 				},
 				required: ['command', 'success'],
 				additionalProperties: false,
 			}),
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
200: ajv.compile<{
command: Pick<SlashCommand, 'clientOnly' | 'command' | 'description' | 'params' | 'providesPreview'>;
}>({
type: 'object',
properties: {
command: {
type: 'object',
properties: {
clientOnly: { type: 'boolean' },
command: { type: 'string' },
description: { type: 'string' },
params: { type: 'string' },
providesPreview: { type: 'boolean' },
},
required: ['command', 'providesPreview'],
},
success: {
type: 'boolean',
enum: [true],
},
},
required: ['command', 'success'],
additionalProperties: false,
}),
},
200: ajv.compile<{
command: Pick<SlashCommand, 'clientOnly' | 'command' | 'description' | 'params' | 'providesPreview'>;
success: true;
}>({
type: 'object',
properties: {
command: {
type: 'object',
properties: {
clientOnly: { type: 'boolean' },
command: { type: 'string' },
description: { type: 'string' },
params: { type: 'string' },
providesPreview: { type: 'boolean' },
},
required: ['command', 'providesPreview'],
additionalProperties: false,
},
success: {
type: 'boolean',
enum: [true],
},
},
required: ['command', 'success'],
additionalProperties: false,
}),
🤖 Prompt for AI Agents
In apps/meteor/app/api/server/v1/commands.ts around lines 37 to 61, the Ajv
generic for the 200 response omits the required success property and the nested
command type is not frozen; update the generic to include success: true (e.g.,
include success: true in the generic type) so the TypeScript type matches the
schema, and tighten/freeze the nested command shape (make the command property
readonly/explicitly typed or use a frozen/const-style typed structure) so the
nested command shape is exact for OpenAPI generation; ensure required fields
align between the generic and the schema and keep additionalProperties: false.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant