Skip to content

chore: Add OpenAPI Support to push.test API#36882

Merged
ggazzo merged 11 commits intoRocketChat:developfrom
ahmed-n-abdeltwab:feat/openapi-push-test
Feb 24, 2026
Merged

chore: Add OpenAPI Support to push.test API#36882
ggazzo merged 11 commits intoRocketChat:developfrom
ahmed-n-abdeltwab:feat/openapi-push-test

Conversation

@ahmed-n-abdeltwab
Copy link
Copy Markdown
Contributor

@ahmed-n-abdeltwab ahmed-n-abdeltwab commented Sep 8, 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 '[Push]'                       
    
    
      [Push]
        POST [/push.token]
          ✔ should fail if not logged in
          ✔ should fail if missing type
          ✔ should fail if missing value
          ✔ should fail if missing appName
          ✔ should fail if type param is unknown
          ✔ should fail if token param is empty
          ✔ should add a token if valid (127ms)
        DELETE [/push.token]
          ✔ should fail if not logged in
          ✔ should fail if missing token key (80ms)
          ✔ should fail if token is empty
          ✔ should fail if token is invalid (45ms)
          ✔ should delete a token if valid
          ✔ should fail if token is already deleted (53ms)
        [/push.test]
          ✔ should fail if not logged in
          ✔ should fail if push is disabled
        [/push.info]
          ✔ should fail if not logged in
          ✔ should succesfully retrieve non default push notification info
          ✔ should succesfully retrieve default push notification info (221ms)
    
    
      18 passing (2s)

Endpoints:

  • Test Push Token

    Test Push Token

Looking forward to your feedback! 🚀

Summary by CodeRabbit

  • Documentation
    • Added OpenAPI support for the push.test API, improving discoverability and docs accuracy.
  • New Features
    • Standardized push.test responses with a defined success schema (tokensCount and success) and clear 400/401 error formats.
    • Added rate limiting (1 req/sec) and explicit permission requirements for push.test.
  • Refactor
    • Migrated push.test to a modern, consistent endpoint definition.
  • Chores
    • Updated API typings and package alignments to support the new endpoint and validation.

COMM-144

@dionisio-bot
Copy link
Copy Markdown
Contributor

dionisio-bot bot commented Sep 8, 2025

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

  • This PR is targeting the wrong base branch. It should target 8.3.0, but it targets 7.11.0

Please fix the issues and try again

If you have any trouble, please check the PR guidelines

@changeset-bot
Copy link
Copy Markdown

changeset-bot bot commented Sep 8, 2025

🦋 Changeset detected

Latest commit: 63a58e6

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

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Sep 10, 2025

Walkthrough

Migrates the push.test endpoint to a chained API.v1.post definition with AJV body/response validators, rate limiting and permissions metadata, re-exports endpoint typings via module augmentation, removes the old static /v1/push.test entry from rest-typings, and adds a patch changeset.

Changes

Cohort / File(s) Summary
Changeset
.changeset/spicy-drinks-carry.md
Adds a patch changeset updating @rocket.chat/meteor and @rocket.chat/rest-typings, describing OpenAPI support and typed validation for the push.test endpoint.
API route migration and typing
apps/meteor/app/api/server/v1/push.ts
Replaces API.v1.addRoute with API.v1.post chained registration for /push.test; adds AJV body and response schemas, rateLimiterOptions, permissionsRequired, and exports PushEndpoints (derived via ExtractRoutesFromAPI). Preserves logic: checks Push_enable, runs executePushTest, returns { tokensCount, success: true }. Adds module augmentation to expose endpoint in @rocket.chat/rest-typings.
REST typings update
packages/rest-typings/src/v1/push.ts
Removes the static /v1/push.test entry from the exported PushEndpoints type so the endpoint typing is now provided via the server-side module augmentation.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor Client
  participant API as API.v1 /v1/push.test
  participant RL as RateLimiter
  participant Auth as Auth/Permissions
  participant AJV as AJV Validators
  participant Conf as Settings (Push_enable)
  participant Svc as executePushTest

  Client->>API: POST /v1/push.test
  API->>RL: Check rate limit (1 req / 1000ms)
  RL-->>API: Allowed / Throttled
  alt Throttled
    API-->>Client: 429 Too Many Requests
  else Allowed
    API->>Auth: Validate auth + "test-push-notifications"
    Auth-->>API: Authorized / Unauthorized
    alt Unauthorized
      API-->>Client: 401 Unauthorized (validated schema)
    else Authorized
      API->>AJV: Validate body (empty object schema)
      AJV-->>API: Valid / Invalid
      alt Invalid
        API-->>Client: 400 Bad Request (validated schema)
      else Valid
        API->>Conf: Read Push_enable
        Conf-->>API: true / false
        alt Push disabled
          API-->>Client: 400 Bad Request (error)
        else Push enabled
          API->>Svc: executePushTest()
          Svc-->>API: tokensCount:number
          API-->>Client: 200 { tokensCount, success: true } (validated schema)
        end
      end
    end
  end

  rect rgba(200,235,255,0.25)
    note right of API: New: chained route registration, AJV body/response validators, rate limiting, permissions, and OpenAPI typings via augmentation
  end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

I thump and tweak the route today,
AJV carrots keep bad data away,
Chained hops, rate limits neat and fine,
Tokens counted, one hop at a time—
The warren’s docs now brightly shine. 🥕🐇

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changes. Docstring coverage check skipped.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title 'chore: Add OpenAPI Support to push.test API' accurately describes the main change: integrating OpenAPI support for the push.test endpoint with AJV schema validation and migrated endpoint registration.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@codecov
Copy link
Copy Markdown

codecov bot commented Sep 10, 2025

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 63.33%. Comparing base (665d719) to head (4364a13).

Additional details and impacted files

Impacted file tree graph

@@             Coverage Diff             @@
##           develop   #36882      +/-   ##
===========================================
- Coverage    66.60%   63.33%   -3.27%     
===========================================
  Files         3346     2911     -435     
  Lines       114661   107327    -7334     
  Branches     21099    19329    -1770     
===========================================
- Hits         76365    67977    -8388     
- Misses       35601    37346    +1745     
+ Partials      2695     2004     -691     
Flag Coverage Δ
e2e 43.01% <ø> (-14.80%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Copy link
Copy Markdown
Contributor

@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 (3)
apps/meteor/app/api/server/v1/push.ts (2)

169-173: Use the route name in error context for consistency.

Minor: align the method field with the endpoint id.

Apply this diff:

-			throw new Meteor.Error('error-push-disabled', 'Push is disabled', {
-				method: 'push_test',
-			});
+			throw new Meteor.Error('error-push-disabled', 'Push is disabled', {
+				method: 'push.test',
+			});

180-185: Potential naming confusion with PushEndpoints.

You now have a local PushEndpoints alias and a PushEndpoints type in @rocket.chat/rest-typings (sans push.test). It compiles due to scope, but can be confusing to readers. Consider renaming the local alias (e.g., PushTestEndpoints) and extending Endpoints from that.

-export type PushEndpoints = ExtractRoutesFromAPI<typeof pushEndpoints>;
+export type PushTestEndpoints = ExtractRoutesFromAPI<typeof pushEndpoints>;

 declare module '@rocket.chat/rest-typings' {
 	// eslint-disable-next-line @typescript-eslint/naming-convention, @typescript-eslint/no-empty-interface
-	interface Endpoints extends PushEndpoints {}
+	interface Endpoints extends PushTestEndpoints {}
 }
.changeset/spicy-drinks-carry.md (1)

6-6: Nit: singular “endpoint”.

This changeset affects a single route (push.test). Tweak grammar for clarity.

-Add OpenAPI support for the Rocket.Chat push.test 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 push.test 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.
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c5ee569 and 6059384.

📒 Files selected for processing (3)
  • .changeset/spicy-drinks-carry.md (1 hunks)
  • apps/meteor/app/api/server/v1/push.ts (4 hunks)
  • packages/rest-typings/src/v1/push.ts (0 hunks)
💤 Files with no reviewable changes (1)
  • packages/rest-typings/src/v1/push.ts
🧰 Additional context used
🧬 Code graph analysis (1)
apps/meteor/app/api/server/v1/push.ts (4)
apps/meteor/app/api/server/api.ts (1)
  • API (42-77)
packages/rest-typings/src/v1/Ajv.ts (3)
  • ajv (23-23)
  • validateBadRequestErrorResponse (46-46)
  • validateUnauthorizedErrorResponse (69-69)
apps/meteor/app/api/server/ApiClass.ts (1)
  • ExtractRoutesFromAPI (71-75)
packages/rest-typings/src/index.ts (1)
  • Endpoints (52-100)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: 📦 Build Packages
  • GitHub Check: CodeQL-Build
🔇 Additional comments (4)
apps/meteor/app/api/server/v1/push.ts (4)

4-4: Good reuse of shared validators.

Nice to see centralized AJV and error schemas being used.


13-13: Type helper import looks correct.

Matches the pattern used elsewhere with ExtractRoutesFromAPI.


175-176: Confirm this.user is always defined under authRequired: true.

If there’s any path where this.user might be undefined, this.user.username could throw. Likely safe, but worth a quick check.


150-166: ```shell
#!/bin/bash
set -euo pipefail

echo "=== Showing apps/meteor/app/api/server/v1/push.ts (up to 320 lines) ==="
if [ -f "apps/meteor/app/api/server/v1/push.ts" ]; then
sed -n '1,320p' apps/meteor/app/api/server/v1/push.ts || true
else
echo "File not found: apps/meteor/app/api/server/v1/push.ts"
fi

echo
echo "=== Searching repo for 403/429 related validators / rest-typings ==="
rg -n -C2 --hidden --no-ignore '\bvalidate(?:Forbidden|ForbiddenError|ForbiddenResponse|TooManyRequests|TooMany|TooManyRequestsError|TooManyRequestsResponse)\b' || true
rg -n -C2 --hidden --no-ignore '\b(forbidden|too[-_ ]many|tooManyRequests|rate[-_ ]limit|rateLimiter|permissionsRequired)\b' || true
rg -n -C2 --hidden --no-ignore 'rest-typings' || true

echo
echo "=== If rest-typings directory exists, list files and search inside ==="
if [ -d "rest-typings" ]; then
echo "rest-typings exists; listing:"
ls -R rest-typings | sed -n '1,200p' || true
rg -n --hidden --no-ignore 'Forbidden|TooMany|TooManyRequests|forbidden|tooMany' rest-typings || true
else
echo "No rest-typings directory at repo root"
fi


</blockquote></details>

</blockquote></details>

</details>

<!-- This is an auto-generated comment by CodeRabbit for review status -->

Copy link
Copy Markdown
Contributor

@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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
apps/meteor/app/api/server/v1/push.ts (1)

140-166: Add 403 and 429 OpenAPI responses; bound tokensCount to non-negative.

  • Document 403 (permission denied) and 429 (rate limited) to match behavior.
  • tokensCount can’t be negative; add minimum: 0.

Apply this diff:

 const pushEndpoints = API.v1.post(
   'push.test',
   {
     authRequired: true,
     rateLimiterOptions: {
       numRequestsAllowed: 1,
       intervalTimeInMS: 1000,
     },
     permissionsRequired: ['test-push-notifications'],
-    body: ajv.compile<undefined>({ type: 'object', additionalProperties: false }),
+    body: ajv.compile<undefined>({ type: 'object', additionalProperties: false }),
     response: {
+      403: validateForbiddenErrorResponse,
+      429: validateTooManyRequestsErrorResponse,
         type: 'object',
         properties: {
-          tokensCount: { type: 'integer' },
+          tokensCount: { type: 'integer', minimum: 0 },
           success: {
             type: 'boolean',
             enum: [true],
           },
         },
         required: ['tokensCount', 'success'],
         additionalProperties: false,
       }),
     },
   },
 )
♻️ Duplicate comments (1)
apps/meteor/app/api/server/v1/push.ts (1)

149-149: Use Record<string, never> for an empty-body schema (fixes generic mismatch).

Schema is an empty object, but the generic is undefined. Align the type for correct inference and stricter typing.

Apply this diff:

-    body: ajv.compile<undefined>({ type: 'object', additionalProperties: false }),
+    body: ajv.compile<Record<string, never>>({ type: 'object', additionalProperties: false }),

Optional: verify clients sending no body (Content-Length: 0) are treated as {} by the router, otherwise this will 400.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6059384 and 57f384c.

📒 Files selected for processing (1)
  • apps/meteor/app/api/server/v1/push.ts (4 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
apps/meteor/app/api/server/v1/push.ts (4)
apps/meteor/app/api/server/api.ts (1)
  • API (42-77)
packages/rest-typings/src/v1/Ajv.ts (3)
  • ajv (23-23)
  • validateBadRequestErrorResponse (46-46)
  • validateUnauthorizedErrorResponse (69-69)
apps/meteor/app/api/server/ApiClass.ts (1)
  • ExtractRoutesFromAPI (71-75)
packages/rest-typings/src/index.ts (1)
  • Endpoints (52-100)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (6)
  • GitHub Check: 🔨 Test Storybook / Test Storybook
  • GitHub Check: 🔎 Code Check / TypeScript
  • GitHub Check: 🔨 Test Unit / Unit Tests
  • GitHub Check: 🔎 Code Check / Code Lint
  • GitHub Check: 📦 Meteor Build - coverage
  • GitHub Check: CodeQL-Build
🔇 Additional comments (3)
apps/meteor/app/api/server/v1/push.ts (3)

13-13: LGTM: type-only import for ExtractRoutesFromAPI is correct.


168-177: LGTM: handler logic is preserved and properly guarded by Push_enable.


4-4: Import 403 validator; 429 validator not exported in rest-typings.

packages/rest-typings exports validateForbiddenErrorResponse but not validateTooManyRequestsErrorResponse — import the 403 validator and either add a 429 validator to packages/rest-typings or confirm the correct export name.

-import { ajv, validateBadRequestErrorResponse, validateUnauthorizedErrorResponse } from '@rocket.chat/rest-typings';
+import {
+	ajv,
+	validateBadRequestErrorResponse,
+	validateUnauthorizedErrorResponse,
+	validateForbiddenErrorResponse,
+} from '@rocket.chat/rest-typings';

@ahmed-n-abdeltwab ahmed-n-abdeltwab marked this pull request as ready for review September 18, 2025 13:30
@ahmed-n-abdeltwab ahmed-n-abdeltwab requested review from a team as code owners September 18, 2025 13:30
@ahmed-n-abdeltwab
Copy link
Copy Markdown
Contributor Author

@cardoso , @ggazzo 👍

@ahmed-n-abdeltwab
Copy link
Copy Markdown
Contributor Author

@ggazzo 👍

@ggazzo ggazzo added this to the 8.3.0 milestone Feb 24, 2026
@ggazzo ggazzo added the stat: QA assured Means it has been tested and approved by a company insider label Feb 24, 2026
@dionisio-bot dionisio-bot bot enabled auto-merge February 24, 2026 12:00
@ggazzo ggazzo disabled auto-merge February 24, 2026 12:01
@ggazzo ggazzo changed the title feat: Add OpenAPI Support to push.test API chore: Add OpenAPI Support to push.test API Feb 24, 2026
@dionisio-bot dionisio-bot bot enabled auto-merge February 24, 2026 12:01
@ggazzo ggazzo merged commit ddc0ed3 into RocketChat:develop Feb 24, 2026
85 of 87 checks passed
@ahmed-n-abdeltwab ahmed-n-abdeltwab deleted the feat/openapi-push-test branch February 24, 2026 12:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

community stat: QA assured Means it has been tested and approved by a company insider

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants