Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
450 changes: 445 additions & 5 deletions package-lock.json

Large diffs are not rendered by default.

4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
"@nestjs/core": "^10.3.0",
"@nestjs/platform-express": "^10.3.0",
"@nestjs/schedule": "^6.1.3",
"@nestjs/swagger": "^7.1.16",
"@prisma/client": "^6.19.2",
"bcrypt": "^6.0.0",
"class-transformer": "^0.5.1",
Expand All @@ -42,7 +43,8 @@
"passport-jwt": "^4.0.1",
"pg": "^8.11.3",
"reflect-metadata": "^0.1.13",
"rxjs": "^7.8.1"
"rxjs": "^7.8.1",
"swagger-ui-express": "^5.0.1"
},
"devDependencies": {
"@nestjs/cli": "^10.3.0",
Expand Down
23 changes: 23 additions & 0 deletions src/app.controller.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,40 @@
import { Controller, Get } from '@nestjs/common';
import { ApiVersionEnum } from './versioning/api-version.constants';
import { ApiVersion, DeprecatedEndpoint } from './versioning/api-version.decorator';
import { GetVersion } from './versioning/get-version.decorator';

@Controller()
export class AppController {
@Get()
@ApiVersion([ApiVersionEnum.V1, ApiVersionEnum.V2])
getHello(): string {
return 'Welcome to PropChain API';
}

@Get('health')
@ApiVersion([ApiVersionEnum.V1, ApiVersionEnum.V2])
health(): { status: string; timestamp: string } {
return {
status: 'OK',
timestamp: new Date().toISOString(),
};
}

@Get('version')
@ApiVersion([ApiVersionEnum.V1, ApiVersionEnum.V2])
getVersionInfo(@GetVersion() version: ApiVersionEnum) {
return {
currentVersion: version,
supportedVersions: [ApiVersionEnum.V1, ApiVersionEnum.V2],
defaultVersion: ApiVersionEnum.V2,
};
}

@Get('deprecated-endpoint')
@DeprecatedEndpoint('This endpoint has been deprecated. Please use /api/v2/new-endpoint instead.')
deprecatedEndpoint(): { message: string } {
return {
message: 'This endpoint is deprecated and will be removed in a future version',
};
}
}
4 changes: 4 additions & 0 deletions src/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import { SessionsModule } from './sessions/sessions.module';
import { TrustScoreModule } from './trust-score/trust-score.module';
import { PropertiesModule } from './properties/properties.module';
import { PrismaModule } from './database/prisma.module';
import { VersioningModule } from './versioning/versioning.module';
import { ApiDocumentationModule } from './config/api-documentation.module';
import { AppController } from './app.controller';

@Module({
Expand All @@ -16,6 +18,8 @@ import { AppController } from './app.controller';
envFilePath: ['.env.local', '.env'],
}),
PrismaModule,
VersioningModule,
ApiDocumentationModule,
UsersModule,
AuthModule,
DashboardModule,
Expand Down
227 changes: 227 additions & 0 deletions src/config/api-decorators-example.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,227 @@
/**
* Example Usage of API Documentation Decorators
* Shows how to use the custom API documentation decorators
*/

import { Controller, Get, Post, Body, Param, Put, Delete } from '@nestjs/common';
import { ApiTags } from '@nestjs/swagger';
import {
ApiPublicEndpoint,
ApiProtectedEndpoint,
ApiAdminEndpoint,
ApiPaginatedEndpoint,
ApiWithPathParam,
ApiDeprecatedEndpoint,
ApiVersionedEndpoint,
ApiRateLimited,
ApiSearchEndpoint,
} from './api-decorators';

@ApiTags('Users')
@Controller('users')
export class ExampleUsersControllerDocumentation {
/**
* Example: Public endpoint
*/
@Get('public-info')
@ApiPublicEndpoint(
'Get public user information',
'Retrieve public information about users without authentication',
)
getPublicInfo() {
return { message: 'Public data' };
}

/**
* Example: Protected endpoint with pagination
*/
@Get()
@ApiProtectedEndpoint(
'List all users',
'Retrieve a paginated list of all users. Requires authentication.',
)
@ApiPaginatedEndpoint(
'List users',
'Get paginated list of users with sorting and filtering',
)
findAll() {
return [];
}

/**
* Example: Get by ID with path parameter
*/
@Get(':id')
@ApiProtectedEndpoint(
'Get user by ID',
'Retrieve a specific user by their ID',
)
@ApiWithPathParam('id', 'string')
findOne(@Param('id') id: string) {
return { id, name: 'User Name' };
}

/**
* Example: Admin-only endpoint
*/
@Delete(':id')
@ApiAdminEndpoint(
'Delete user',
'Permanently delete a user from the system. Admin access required.',
)
@ApiWithPathParam('id', 'string')
remove(@Param('id') id: string) {
return { message: `User ${id} deleted` };
}

/**
* Example: Deprecated endpoint
*/
@Get('old-list')
@ApiDeprecatedEndpoint(
'Get users (old)',
'This is an old way to get users',
'GET /users',
)
oldListEndpoint() {
return [];
}

/**
* Example: Versioned endpoint
*/
@Post()
@ApiVersionedEndpoint(
'Create user',
'Create a new user account',
['v1', 'v2'],
)
create(@Body() createUserDto: any) {
return { id: '1', ...createUserDto };
}

/**
* Example: Rate-limited endpoint
*/
@Get(':id/activity')
@ApiProtectedEndpoint(
'Get user activity',
'Retrieve user activity logs',
)
@ApiRateLimited(100, '1 hour')
@ApiWithPathParam('id', 'string')
getUserActivity(@Param('id') id: string) {
return { userId: id, activities: [] };
}

/**
* Example: Search endpoint
*/
@Get('search/by-email')
@ApiSearchEndpoint(
'Search users by email',
'Search for users by email address with filters',
)
searchByEmail() {
return [];
}
}

@ApiTags('Properties')
@Controller('properties')
export class ExamplePropertiesControllerDocumentation {
/**
* Example: Public list endpoint
*/
@Get()
@ApiPublicEndpoint(
'List properties',
'Retrieve a list of public properties',
)
@ApiPaginatedEndpoint(
'List properties',
'Get paginated list of properties',
)
findAll() {
return [];
}

/**
* Example: Protected create endpoint
*/
@Post()
@ApiProtectedEndpoint(
'Create property',
'Create a new property listing',
)
create(@Body() createPropertyDto: any) {
return { id: '1', ...createPropertyDto };
}

/**
* Example: Update endpoint with version support
*/
@Put(':id')
@ApiVersionedEndpoint(
'Update property',
'Update property details',
['v2'],
)
@ApiWithPathParam('id', 'string')
update(
@Param('id') id: string,
@Body() updatePropertyDto: any,
) {
return { id, ...updatePropertyDto };
}
}

/**
* Usage in actual controllers:
*
* @Controller('api/v2/users')
* @ApiTags('Users')
* export class UsersController {
* @Get()
* @ApiProtectedEndpoint(
* 'List all users',
* 'Retrieve a paginated list of all users'
* )
* @ApiPaginatedEndpoint(
* 'List users',
* 'Get paginated list with sorting'
* )
* findAll() {
* return [];
* }
*
* @Get(':id')
* @ApiProtectedEndpoint(
* 'Get user by ID',
* 'Retrieve a specific user'
* )
* @ApiWithPathParam('id', 'string')
* findOne(@Param('id') id: string) {
* return { id };
* }
*
* @Post()
* @ApiProtectedEndpoint(
* 'Create user',
* 'Create a new user'
* )
* create(@Body() createUserDto: CreateUserDto) {
* return { id: '1', ...createUserDto };
* }
*
* @Delete(':id')
* @ApiAdminEndpoint(
* 'Delete user',
* 'Delete a user permanently'
* )
* @ApiWithPathParam('id', 'string')
* remove(@Param('id') id: string) {
* return { message: 'Deleted' };
* }
* }
*/
Loading
Loading