Skip to content

feat: add node decorator processor system for dynamic OpenAPI schema#7

Merged
m2broth merged 2 commits into
masterfrom
feat/add_node_extension
Jul 28, 2025
Merged

feat: add node decorator processor system for dynamic OpenAPI schema#7
m2broth merged 2 commits into
masterfrom
feat/add_node_extension

Conversation

@m2broth
Copy link
Copy Markdown
Collaborator

@m2broth m2broth commented Jul 24, 2025

📋 Overview

This PR introduces a new option in metadata generator that allows custom decorators to dynamically extend OpenAPI schemas during the tsoa code generation process. This enables third-party services, middleware, and custom business logic to inject metadata directly into the generated OpenAPI specifications.

✨ Key Features

  • Custom Decorator Processing: Register custom decorators that can modify OpenAPI method metadata
  • Type-Safe Implementation: Full TypeScript support with proper type checking
  • Flexible Configuration: Easy integration through MetadataGeneratorOptions
  • Extensible Architecture: Clean separation of concerns with processor interfaces

🔧 Implementation Details

Core Components

  1. NodeDecoratorProcessor Interface

    export type NodeDecoratorProcessor = (context: DecoratorProcessorContext) => void;
    
    export interface DecoratorProcessorContext {
      methodObject: Tsoa.Method;
      decoratorArguments: any[];
    }
  2. MetadataGenerator Integration

    • Added customDecoratorProcessors to MetadataGeneratorOptions
    • Processors are executed during method metadata generation
    • Full error handling and validation
  3. MethodGenerator Enhancement

    • New processCustomDecorators method
    • Automatic decorator detection and processing
    • Context injection for processor execution

Usage

1. Create Your Decorator & Processor

// myCustomDecorator.ts
import { NodeDecoratorProcessor } from '@namecheap/tsoa-cli';

export function MyCustomDecorator(value: string): MethodDecorator {
  return (target, propertyKey, descriptor) => descriptor;
}

export const MyCustomProcessor: NodeDecoratorProcessor = ({ methodObject, decoratorArguments }) => {
  if (!methodObject.extensions) methodObject.extensions = [];
  
  methodObject.extensions.push({
    key: 'x-my-custom-extension',
    value: { customValue: decoratorArguments[0] }
  });
};

2. Register in Your Service

// your-service.ts
import { MetadataGenerator } from '@namecheap/tsoa-cli';
import { MyCustomProcessor } from './myCustomDecorator';

const metadata = new MetadataGenerator(
  'src/controllers/**/*.ts',
  {},
  [],
  undefined,
  {
    customDecoratorProcessors: {
      'MyCustomDecorator': MyCustomProcessor
    }
  }
);

3. Use in Controllers

// userController.ts
import { Route, Get, Controller } from '@namecheap/tsoa-runtime';
import { MyCustomDecorator } from './myCustomDecorator';

@Route('api')
export class UserController extends Controller {
  @Get('users')
  @MyCustomDecorator('custom-value')
  public async getUsers(): Promise<User[]> {
    return this.userService.getUsers();
  }
}

4. Generated OpenAPI Output

paths:
  /api/users:
    get:
      x-my-custom-extension:
        customValue: "custom-value"

@b1ff
Copy link
Copy Markdown

b1ff commented Jul 24, 2025

@wRLSS @m2broth it looks like we need to add github actions here

@m2broth
Copy link
Copy Markdown
Collaborator Author

m2broth commented Jul 24, 2025

@wRLSS @m2broth it looks like we need to add github actions here

@wRLSS Could you check Settings -> Actions -> General and Settings -> Branches for brunch protection rules and workflows are enabled for this repository

@m2broth m2broth marked this pull request as draft July 25, 2025 08:57
…extensions

This commit introduces a new node decorator processor system that allows
dynamic extension of OpenAPI schemas through custom decorators. The system
enables third-party services to inject custom metadata into generated
OpenAPI specifications.
@m2broth m2broth force-pushed the feat/add_node_extension branch from 26d8ca9 to d66bd9f Compare July 25, 2025 09:30
@m2broth m2broth marked this pull request as ready for review July 25, 2025 09:32
@m2broth
Copy link
Copy Markdown
Collaborator Author

m2broth commented Jul 25, 2025

@wRLSS @m2broth it looks like we need to add github actions here

I've resolved running gh actions in the repository and fixed running tests

};
processor(context);
} catch (error) {
throw new GenerateMetadataError(`Error in custom decorator processor for '${decoratorName}'`);
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

when this error is thrown it would be hard to debug given that original one is going to be missign

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

current GenerateMetadataError class isn't supposed to work with original Error object. I added node object as a second GenerateMetadataError constructor argument

};
}

export const RateLimitByUserIdProcessor: NodeDecoratorProcessor = (context: DecoratorProcessorContext) => {
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

does it mean that consumers must be adding separate decorators for documentation?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

No, this is just as example. The device gets current decorators by provided name and then applies any modification to the openapi method metadata

@m2broth m2broth merged commit 0a79144 into master Jul 28, 2025
1 check passed
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.

4 participants