Skip to content

feat: express decorators for rest apis and websocket#6818

Merged
sriramveeraghanta merged 4 commits intopreviewfrom
feat/decorators
Mar 26, 2025
Merged

feat: express decorators for rest apis and websocket#6818
sriramveeraghanta merged 4 commits intopreviewfrom
feat/decorators

Conversation

@Palanikannan1437
Copy link
Member

@Palanikannan1437 Palanikannan1437 commented Mar 25, 2025

Description

Summary by CodeRabbit

Summary by CodeRabbit

  • New Features

    • Launched a powerful TypeScript decorator library that streamlines the creation of REST APIs and WebSocket services in Express applications using intuitive route and middleware decorators.
  • Documentation

    • Added comprehensive usage instructions and API references to guide users in integrating and leveraging the new decorator functionalities.
  • Chores

    • Introduced new configuration files for TypeScript and build processes to enhance project structure and development efficiency.
    • Added an ESLint configuration to improve code quality by specifying ignored files and directories.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Mar 25, 2025

Important

Review skipped

Review was skipped due to path filters

⛔ Files ignored due to path filters (1)
  • yarn.lock is excluded by !**/yarn.lock, !**/*.lock

CodeRabbit blocks several paths by default. You can override this behavior by explicitly including those paths in the path filters. For example, including **/dist/** will override the default block on the dist directory, by removing the pattern from both the lists.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Walkthrough

This pull request introduces a new package, @plane/decorators, which adds a set of files for creating and registering REST and WebSocket controllers in an Express application. New configuration files for ESLint, TypeScript, and the build process have been provided, along with source code files that define decorators, controller registration functions, and a base class for WebSocket controllers. Documentation and package metadata are also included.

Changes

File(s) Changes
packages/decorators/{.eslintignore, .eslintrc.js} Added ESLint configuration files: an ignore file to skip directories (e.g., node_modules, build/*, etc.) and a configuration file that extends @plane/eslint-config/library.js with TypeScript support.
packages/decorators/{README.md, package.json} Introduced package documentation and metadata including installation instructions, API reference, dependency details, and scripts for building and linting.
packages/decorators/src/{controller.ts, rest.ts, websocket.ts, websocket-controller.ts, index.ts} Added core source files that implement REST and WebSocket decorators, functions for registering controllers with the Express router, and structured module exports.
packages/decorators/{tsconfig.json, tsup.config.ts} Included TypeScript project and build configuration files defining compiler options, build entry point, module formats, external dependencies, and source map settings.
packages/typescript-config/{node-library.json, package.json} Introduced a new TypeScript configuration file for Node.js libraries and updated the package's file list to include this new configuration.

Sequence Diagram(s)

sequenceDiagram
    participant Router
    participant ControllerInstance
    participant ReflectAPI

    Router->>ControllerInstance: Invoke registerControllers()
    ControllerInstance->>ReflectAPI: Retrieve metadata (base route, HTTP method, etc.)
    ReflectAPI-->>ControllerInstance: Return metadata
    ControllerInstance->>Router: Register route with handler
Loading
sequenceDiagram
    participant Router
    participant WSControllerInstance
    participant ReflectAPI

    Router->>WSControllerInstance: Invoke registerWebSocketControllers()
    WSControllerInstance->>ReflectAPI: Retrieve WebSocket metadata
    ReflectAPI-->>WSControllerInstance: Return metadata
    WSControllerInstance->>Router: Register WebSocket route with handler
Loading

Possibly related PRs

Suggested labels

✨feature, 🌐frontend

Suggested reviewers

  • sriramveeraghanta

Poem

I'm a rabbit, hopping through code so fine,
New decorators and configs make my world align.
Routes and controllers spring to life with cheer,
WebSocket magic and REST so clear.
With linting in place, bugs vanish out of sight—
I nibble on challenges, coding day and night! 🐰
Hop on and celebrate this clever design!


🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai plan to trigger planning for file edits and PR creation.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@Palanikannan1437 Palanikannan1437 force-pushed the feat/decorators branch 3 times, most recently from 2660a11 to f4d8103 Compare March 25, 2025 14:53
@Palanikannan1437 Palanikannan1437 marked this pull request as ready for review March 25, 2025 15:01
Copy link
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: 2

🧹 Nitpick comments (11)
packages/decorators/tsconfig.json (1)

9-9: Remove trailing comma in object literal.

There's a trailing comma after the closing bracket of the "lib" array in the compilerOptions object. While this is valid JSON in some contexts, it's technically not valid in the strictest JSON parsing and might cause issues with some tools.

  "compilerOptions": {
    "jsx": "react",
    "lib": [
      "esnext",
      "dom"
    ],
-  },
+  }
packages/decorators/src/websocket.ts (3)

3-7: Complete the JSDoc comment with return type description.

The JSDoc comment for the WebSocket decorator is incomplete. It lists the route parameter but doesn't describe what the function returns.

 /**
  * WebSocket method decorator
  * @param route
+ * @returns MethodDecorator - A decorator that can be applied to class methods
  */

8-17: Add route parameter validation.

The WebSocket decorator doesn't validate the route parameter. Adding validation would help catch potential issues early and provide better error messages.

 export function WebSocket(route: string): MethodDecorator {
+  if (!route || typeof route !== 'string') {
+    throw new Error('WebSocket decorator requires a valid route string');
+  }
+
   return function (
     target: object,
     propertyKey: string | symbol,
     descriptor: PropertyDescriptor,
   ) {
     Reflect.defineMetadata("method", "ws", target, propertyKey);
     Reflect.defineMetadata("route", route, target, propertyKey);
   };
 }

14-15: Consider using constants for metadata keys.

Using string literals directly for metadata keys could lead to inconsistencies if the same keys are used elsewhere. Consider defining constants for these keys.

+const METHOD_METADATA_KEY = "method";
+const ROUTE_METADATA_KEY = "route";
+const WS_METHOD_TYPE = "ws";

 export function WebSocket(route: string): MethodDecorator {
   return function (
     target: object,
     propertyKey: string | symbol,
     descriptor: PropertyDescriptor,
   ) {
-    Reflect.defineMetadata("method", "ws", target, propertyKey);
-    Reflect.defineMetadata("route", route, target, propertyKey);
+    Reflect.defineMetadata(METHOD_METADATA_KEY, WS_METHOD_TYPE, target, propertyKey);
+    Reflect.defineMetadata(ROUTE_METADATA_KEY, route, target, propertyKey);
   };
 }
packages/decorators/README.md (1)

1-100: README provides good documentation but needs clarification on setup requirements.

The documentation is well-structured with clear examples of both REST and WebSocket controller usage. However, there are some areas that could be improved:

  1. The "No build step required" feature (line 11) may be misleading since TypeScript files still need transpilation.

  2. The WebSocket example (lines 74-76) uses express-ws without showing how to set it up:

// Register WebSocket routes
const router = require("express-ws")(app).router;
const chatController = new ChatController();
chatController.registerWebSocketRoutes(router);

Consider adding:

  1. Prerequisites section mentioning the need for TypeScript configuration
  2. Complete setup example including express-ws initialization
  3. Instructions for enabling decorator metadata in tsconfig.json
packages/decorators/src/index.ts (1)

13-14: Consider consistent naming convention for namespaces.

The namespace naming is inconsistent:

  • Rest is used for REST decorators
  • WebSocketNS is used for WebSocket decorators (with an "NS" suffix)

For better consistency, consider either:

-export const Rest = RestDecorators;
-export const WebSocketNS = WebSocketDecorators;
+export const RestNS = RestDecorators;
+export const WebSocketNS = WebSocketDecorators;

Or:

-export const Rest = RestDecorators;
-export const WebSocketNS = WebSocketDecorators;
+export const Rest = RestDecorators;
+export const WebSocket = WebSocketDecorators;
packages/decorators/src/controller.ts (2)

18-21: Refine constructor parameter typing.
Currently, new (...args: any[]) uses very broad any typing. This makes the code less self-documenting and can mask potential type mismatch errors. Consider introducing a generic typed constructor signature or a more descriptive interface to improve maintainability.


23-61: Validate consistency between REST and WebSocket registration.
This function explicitly skips "ws" methods. Ensure that all relevant WebSocket routes are registered and tested by the dedicated registerWebSocketControllers function, or consider unifying the approach if you'd prefer to manage both protocols in a single method.

packages/decorators/src/rest.ts (1)

20-93: Consolidate repetitive decorator logic.
The Get, Post, Patch, Put, and Delete decorators use nearly identical logic. Consider introducing a higher-order function that takes the HTTP method as an argument to reduce duplication. This can help you easily add new methods and keep the code consistent.

packages/decorators/src/websocket-controller.ts (2)

43-55: Refine error handling for WebSocket exceptions.
Currently, errors are logged to the console and the connection is closed with code 1011. You might enhance user feedback by implementing a structured error logger or returning more contextual error messages to the client when appropriate.


63-85: Review instantiation of the router in BaseWebSocketController.
You create a fresh Router() instance in the constructor. Confirm whether you intend to attach WebSocket routes to this controller-specific router or a shared application router, to avoid losing track of your WebSocket endpoints.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 41447e5 and ea7ebe6.

⛔ Files ignored due to path filters (1)
  • yarn.lock is excluded by !**/yarn.lock, !**/*.lock
📒 Files selected for processing (11)
  • packages/decorators/.eslintignore (1 hunks)
  • packages/decorators/.eslintrc.js (1 hunks)
  • packages/decorators/README.md (1 hunks)
  • packages/decorators/package.json (1 hunks)
  • packages/decorators/src/controller.ts (1 hunks)
  • packages/decorators/src/index.ts (1 hunks)
  • packages/decorators/src/rest.ts (1 hunks)
  • packages/decorators/src/websocket-controller.ts (1 hunks)
  • packages/decorators/src/websocket.ts (1 hunks)
  • packages/decorators/tsconfig.json (1 hunks)
  • packages/decorators/tsup.config.ts (1 hunks)
🧰 Additional context used
🧬 Code Definitions (1)
packages/decorators/src/websocket-controller.ts (3)
packages/decorators/src/index.ts (3)
  • registerWebSocketControllers (6-6)
  • Controller (2-2)
  • WebSocket (4-4)
packages/decorators/src/rest.ts (1)
  • Controller (9-13)
packages/decorators/src/websocket.ts (1)
  • WebSocket (8-17)
🪛 Biome (1.9.4)
packages/decorators/src/rest.ts

[error] 10-10: Don't use 'Function' as a type.

Prefer explicitly define the function shape. This type accepts any function-like value, which can be a common source of bugs.

(lint/complexity/noBannedTypes)

🔇 Additional comments (8)
packages/decorators/tsconfig.json (1)

1-18: TypeScript configuration appears appropriate, but verify React dependency.

The TypeScript configuration properly extends from the base configuration and sets up the compiler options. However, it includes React-specific settings ("jsx": "react") which raises a question - is this package intended to be used with React components, or is it strictly for Express decorators as suggested by the PR title?

Please verify if the React JSX setting is necessary for this package. If this package doesn't contain React components but is only for Express decorators, you might consider removing the JSX setting.

packages/decorators/.eslintignore (1)

1-4: LGTM! Standard ESLint ignore patterns.

The ESLint ignore file correctly excludes common directories that shouldn't be linted: node_modules, build artifacts, and distribution files.

packages/decorators/.eslintrc.js (1)

1-9: LGTM! Standard ESLint configuration for TypeScript.

The ESLint configuration is well set up for a TypeScript library. It properly:

  • Marks this as the root ESLint configuration
  • Extends from a shared configuration
  • Uses the TypeScript parser
  • Sets up parser options for TypeScript
packages/decorators/tsup.config.ts (1)

1-12: Build configuration is well-structured and follows best practices.

The tsup configuration is properly set up with:

  • Both ESM and CommonJS output formats for maximum compatibility
  • TypeScript declaration files enabled
  • Source maps included for debugging
  • External dependencies correctly specified
  • Tree-shaking enabled for optimized bundle size
packages/decorators/package.json (1)

1-42: Package configuration follows best practices.

The package.json is well-structured with:

  • Clear package information and description
  • Properly defined entry points for CommonJS, ESM, and TypeScript
  • Appropriate scripts for building and linting
  • Required dependencies clearly specified

The dependencies are handled correctly:

  • reflect-metadata is a direct dependency (needed for decorators)
  • express and ws are properly listed as peer dependencies
  • ws is correctly marked as optional for users who don't need WebSocket functionality
packages/decorators/src/index.ts (1)

1-16: Exports are well-organized with both direct and namespaced options.

The index file properly exports all decorators and utilities, providing flexibility through:

  • Individual exports for direct imports of specific decorators
  • Namespaced exports (Rest, WebSocketNS) for better organization
packages/decorators/src/controller.ts (1)

4-12: Clarify inclusion of "ws" in HttpMethod.
You include "ws" as a possible HTTP method but specifically ignore it later in the code. Verify that this is intended and that you're handling WebSocket routes elsewhere.

packages/decorators/src/rest.ts (1)

100-111: Decorators and middleware chaining look good.
Attaching multiple middleware functions via metadata is an elegant approach. This logic is straightforward and should integrate well with Express’s request handling pipeline.

Comment on lines +35 to +58
if (
typeof handler === "function" &&
typeof (router as any).ws === "function"
) {
(router as any).ws(
`${baseRoute}${route}`,
(ws: WebSocket, req: Request) => {
try {
handler.call(instance, ws, req);
} catch (error) {
console.error(
`WebSocket error in ${Controller.name}.${methodName}`,
error,
);
ws.close(
1011,
error instanceof Error
? error.message
: "Internal server error",
);
}
},
);
}
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Type the WebSocket registration to avoid using (router as any).
It appears you rely on express-ws or a similar library that adds .ws to the router. Consider declaring a compatible type instead of casting to any, to ensure better type safety and autocompletion.

Copy link
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: 0

🧹 Nitpick comments (1)
packages/typescript-config/package.json (1)

9-10: Addition of Node.js Library Configuration File
The addition of "node-library.json" in the "files" array clearly indicates that a new configuration file for Node.js library environments has been introduced. Please verify that the node-library.json file is maintained with consistent standards and documented appropriately for users who reference these configurations.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ea7ebe6 and 6db75fe.

📒 Files selected for processing (5)
  • packages/decorators/package.json (1 hunks)
  • packages/decorators/src/websocket-controller.ts (1 hunks)
  • packages/decorators/tsconfig.json (1 hunks)
  • packages/typescript-config/node-library.json (1 hunks)
  • packages/typescript-config/package.json (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • packages/typescript-config/node-library.json
🚧 Files skipped from review as they are similar to previous changes (2)
  • packages/decorators/package.json
  • packages/decorators/src/websocket-controller.ts
🔇 Additional comments (1)
packages/decorators/tsconfig.json (1)

1-22: Solid TypeScript Configuration for Decorators Package
This new tsconfig.json file is well-structured. It extends from @plane/typescript-config/node-library.json and appropriately enables experimental decorators and metadata emission. The inclusion of compiler options such as "lib": ["ES2020"], clear path mappings, and designated include/exclude arrays ensures consistency and proper module resolution for the decorators package.

Copy link
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: 0

♻️ Duplicate comments (1)
packages/decorators/src/rest.ts (1)

7-16: ⚠️ Potential issue

Fix the 'Function' type usage in the Controller decorator.

The static analysis tool correctly flags the use of Function type on line 13, which can be error-prone. This issue was previously addressed in commit 8a9cdc6 but appears to have been reintroduced.

Replace the general Function type with a more specific constructor signature:

export function Controller(baseRoute: string = ""): ClassDecorator {
-  return function (target: Function) {
+  return function <T extends { new (...args: any[]): {} }>(target: T) {
    Reflect.defineMetadata("baseRoute", baseRoute, target);
  };
}

This change provides better type safety by explicitly defining the function shape.

🧰 Tools
🪛 Biome (1.9.4)

[error] 13-13: Don't use 'Function' as a type.

Prefer explicitly define the function shape. This type accepts any function-like value, which can be a common source of bugs.

(lint/complexity/noBannedTypes)

🧹 Nitpick comments (2)
packages/decorators/src/rest.ts (2)

7-11: Complete the JSDoc comments for better documentation.

The JSDoc comments for the Controller decorator are incomplete - they have @param and @returns tags but no descriptions.

Improve the JSDoc by adding descriptions:

/**
 * Controller decorator
- * @param baseRoute
- * @returns
+ * @param baseRoute - Base route prefix for all methods in the controller
+ * @returns A class decorator that adds route metadata to the controller
 */

45-49: Complete the JSDoc comments for the Middleware decorator.

Similar to the Controller decorator, the JSDoc comments for the Middleware decorator are incomplete.

Improve the documentation:

/**
 * Middleware decorator
- * @param middleware
- * @returns
+ * @param middleware - Express middleware function to be applied to the route handler
+ * @returns A method decorator that adds middleware metadata to the handler method
 */
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6db75fe and 8a9cdc6.

📒 Files selected for processing (1)
  • packages/decorators/src/rest.ts (1 hunks)
🧰 Additional context used
🧬 Code Definitions (1)
packages/decorators/src/rest.ts (1)
packages/decorators/src/index.ts (7)
  • Controller (2-2)
  • Get (3-3)
  • Post (3-3)
  • Put (3-3)
  • Patch (3-3)
  • Delete (3-3)
  • Middleware (2-2)
🪛 Biome (1.9.4)
packages/decorators/src/rest.ts

[error] 13-13: Don't use 'Function' as a type.

Prefer explicitly define the function shape. This type accepts any function-like value, which can be a common source of bugs.

(lint/complexity/noBannedTypes)

🔇 Additional comments (4)
packages/decorators/src/rest.ts (4)

18-36: Good implementation of a factory pattern for HTTP method decorators.

The createHttpMethodDecorator factory function is well implemented, reducing code duplication while maintaining a clean API. The function creates decorators for different HTTP methods with consistent behavior.


38-43: Clean export of HTTP method decorators.

The HTTP method decorators are created using the factory function and exported with clear, concise names that follow REST API conventions.


50-61: Well-implemented Middleware decorator.

The Middleware decorator correctly retrieves existing middlewares, appends new ones, and updates the metadata. This approach allows for multiple middleware functions to be applied to a single handler method.


1-5: Good type definition for HTTP methods.

The RestMethod type definition clearly defines the valid HTTP methods that can be used with the decorators, which helps with type safety.

@sriramveeraghanta sriramveeraghanta merged commit 9937139 into preview Mar 26, 2025
5 of 6 checks passed
@sriramveeraghanta sriramveeraghanta deleted the feat/decorators branch March 26, 2025 14:54
lifeiscontent pushed a commit that referenced this pull request Aug 18, 2025
* feat: express decorators for rest apis and websocket

* fix: added package dependency

* fix: refactor decorators
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.

3 participants