@nestjsvn/swagger-sse
Version:
OpenAPI documentation and interactive Swagger UI for NestJS Server-Sent Events endpoints
348 lines (271 loc) • 7.33 kB
Markdown
# CLI Plugin Usage Guide
The `@nestjsvn/swagger-sse` CLI plugin automatically detects methods decorated with `@Sse()` and adds appropriate `@ApiSse()` decorators with inferred event types from Observable return types.
## Installation
```bash
npm install @nestjsvn/swagger-sse
```
## Configuration
### NestJS CLI Integration
Add the plugin to your `nest-cli.json`:
```json
{
"collection": "@nestjs/schematics",
"sourceRoot": "src",
"compilerOptions": {
"deleteOutDir": true,
"plugins": [
"@nestjs/swagger",
{
"name": "@nestjsvn/swagger-sse/plugin",
"options": {
"eventNamingConvention": "kebab-case",
"introspectComments": true,
"autoGenerateOperationId": true
}
}
]
}
}
```
### TypeScript Compiler Integration
For direct TypeScript compiler integration:
```typescript
// webpack.config.js or similar
const { createTransformerFactory } = require('@nestjsvn/swagger-sse/plugin');
module.exports = {
// ... other config
module: {
rules: [
{
test: /\.tsx?$/,
use: [
{
loader: 'ts-loader',
options: {
getCustomTransformers: (program) => ({
before: [createTransformerFactory({
eventNamingConvention: 'kebab-case',
introspectComments: true
})(program)]
})
}
}
]
}
]
}
};
```
## Plugin Options
### `eventNamingConvention`
Controls how TypeScript type names are converted to event names.
- `'kebab-case'` (default): `UserCreatedDto` → `user-created`
- `'camelCase'`: `UserCreatedDto` → `userCreated`
- `'PascalCase'`: `UserCreatedDto` → `UserCreated`
### `introspectComments`
When `true` (default), the plugin extracts metadata from JSDoc comments:
```typescript
/**
* Streams real-time user events
* @summary User event stream
* @description Provides live updates for user-related activities
*/
@Sse('user-events')
streamUserEvents(): Observable<MessageEvent<UserCreatedDto | UserUpdatedDto>> {
// Implementation
}
```
Generates:
```typescript
@ApiSse({
summary: 'User event stream',
description: 'Provides live updates for user-related activities',
events: {
'user-created': UserCreatedDto,
'user-updated': UserUpdatedDto
}
})
```
### `autoGenerateOperationId`
When `true` (default), automatically generates operation IDs:
```typescript
@Sse('stream')
streamEvents(): Observable<MessageEvent<EventDto>> {
// Implementation
}
```
Generates:
```typescript
@ApiSse({
operationId: 'sseStreamEvents',
events: {
'event': EventDto
}
})
```
## Automatic Type Detection
The plugin analyzes Observable return types to extract event types:
### Single Event Type
```typescript
@Sse('notifications')
streamNotifications(): Observable<MessageEvent<NotificationDto>> {
// Plugin generates:
// @ApiSse({
// events: {
// 'notification': NotificationDto
// }
// })
}
```
### Union Types
```typescript
@Sse('events')
streamEvents(): Observable<MessageEvent<UserDto | MessageDto | OrderDto>> {
// Plugin generates:
// @ApiSse({
// events: {
// 'user': UserDto,
// 'message': MessageDto,
// 'order': OrderDto
// }
// })
}
```
### Complex Types
```typescript
type EventTypes =
| { type: 'user-created'; data: UserCreatedDto }
| { type: 'user-updated'; data: UserUpdatedDto }
| { type: 'user-deleted'; data: UserDeletedDto };
@Sse('user-events')
streamUserEvents(): Observable<MessageEvent<EventTypes>> {
// Plugin analyzes the union type and extracts event names
}
```
## Type Name Processing
The plugin automatically removes common suffixes when generating event names:
- `UserCreatedDto` → `user-created`
- `MessageReceivedEvent` → `message-received`
- `OrderData` → `order`
- `NotificationPayload` → `notification`
Removed suffixes: `Dto`, `Event`, `Data`, `Payload`
## Error Handling
The plugin handles various edge cases gracefully:
### Methods Without Return Types
```typescript
@Sse('stream')
streamEvents() {
// Plugin skips transformation - no return type to analyze
}
```
### Non-Observable Return Types
```typescript
@Sse('stream')
streamEvents(): Promise<string> {
// Plugin skips transformation - not an Observable
}
```
### Observable Without MessageEvent
```typescript
@Sse('stream')
streamEvents(): Observable<string> {
// Plugin skips transformation - not MessageEvent
}
```
## Integration with Existing Code
The plugin only transforms methods that:
1. Have the `@Sse()` decorator
2. Do NOT already have the `@ApiSse()` decorator
3. Have an Observable return type
4. Are in files that import from `@nestjs/common`
This ensures it doesn't interfere with manually documented endpoints.
## Debugging
Enable debug logging to see what the plugin is doing:
```typescript
// In your transformer configuration
{
name: "@nestjsvn/swagger-sse/plugin",
options: {
debug: true, // Enable debug logging
eventNamingConvention: "kebab-case"
}
}
```
The plugin will log:
- Which methods it's transforming
- What event types it extracted
- Any errors or warnings during transformation
## Best Practices
### 1. Use Explicit Return Types
```typescript
// Good - explicit return type
@Sse('events')
streamEvents(): Observable<MessageEvent<UserDto>> {
return this.eventService.stream();
}
// Less ideal - inferred return type may not be detected
@Sse('events')
streamEvents() {
return this.eventService.stream();
}
```
### 2. Use Descriptive Type Names
```typescript
// Good - descriptive names
export class UserCreatedDto {
userId: string;
username: string;
}
export class MessageReceivedDto {
messageId: string;
content: string;
}
// Less ideal - generic names
export class EventDto {
type: string;
data: any;
}
```
### 3. Add JSDoc Comments
```typescript
/**
* Streams real-time notifications for the authenticated user
* @summary User notification stream
* @description Provides live updates including messages, alerts, and system notifications
*/
@Sse('notifications')
streamNotifications(): Observable<MessageEvent<NotificationDto>> {
return this.notificationService.streamForUser();
}
```
### 4. Group Related Events
```typescript
// Group related events in union types
type UserEventTypes =
| UserCreatedDto
| UserUpdatedDto
| UserDeletedDto;
@Sse('user-events')
streamUserEvents(): Observable<MessageEvent<UserEventTypes>> {
return this.userService.streamEvents();
}
```
## Troubleshooting
### Plugin Not Running
1. Verify `nest-cli.json` configuration
2. Check that files import from `@nestjs/common`
3. Ensure methods have `@Sse()` decorator
4. Verify TypeScript compilation is working
### Types Not Detected
1. Check return type is `Observable<MessageEvent<T>>`
2. Verify type definitions are available
3. Ensure TypeScript can resolve the types
4. Check for circular dependencies
### Generated Names Incorrect
1. Adjust `eventNamingConvention` option
2. Consider renaming your DTOs
3. Use manual `@ApiSse()` for complex cases
### Build Performance Issues
1. The plugin adds minimal overhead (<10% build time)
2. Consider excluding test files from transformation
3. Use `include`/`exclude` patterns in TypeScript config