Project Structure
This guide explains the organization of a generated NestJS project and where to add your custom code.
Directory Layout
my-api/
βββ src/
β βββ entities/ # Generated: TypeORM entities
β βββ modules/ # Generated: NestJS modules
β βββ extensions/ # Your code: Custom additions
β βββ common/ # Generated: Shared utilities
β βββ config/ # Configuration files
β βββ migrations/ # Database migrations
β βββ app.module.ts # Root module
β βββ main.ts # Application entry point
βββ test/ # Test files
βββ .apsorc # APSO schema definition
βββ package.jsonGenerated Code
Entities (src/entities/)
TypeORM entity definitions:
// src/entities/project.entity.ts
import { Entity, Column, PrimaryGeneratedColumn, OneToMany } from 'typeorm';
import { Task } from './task.entity';
@Entity('projects')
export class Project {
@PrimaryGeneratedColumn('uuid')
id: string;
@Column()
name: string;
@Column({ nullable: true })
description: string;
@Column()
organizationId: string;
@OneToMany(() => Task, task => task.project)
tasks: Task[];
@Column({ type: 'timestamp', default: () => 'CURRENT_TIMESTAMP' })
createdAt: Date;
@Column({ type: 'timestamp', default: () => 'CURRENT_TIMESTAMP' })
updatedAt: Date;
}Modules (src/modules/)
Each entity gets its own module:
src/modules/projects/
βββ projects.module.ts # Module definition
βββ projects.controller.ts # HTTP endpoints
βββ projects.service.ts # Business logic
βββ dto/
βββ create-project.dto.ts
βββ update-project.dto.tsController Example
// src/modules/projects/projects.controller.ts
@Controller('projects')
@UseGuards(AuthGuard)
export class ProjectsController {
constructor(private readonly projectsService: ProjectsService) {}
@Get()
@ApiOperation({ summary: 'Get all projects' })
findAll(
@Query() query: FindAllQuery,
@CurrentUser() user: User,
) {
return this.projectsService.findAll(query, user);
}
@Post()
@ApiOperation({ summary: 'Create a project' })
create(
@Body() dto: CreateProjectDto,
@CurrentUser() user: User,
) {
return this.projectsService.create(dto, user);
}
}Service Example
// src/modules/projects/projects.service.ts
@Injectable()
export class ProjectsService {
constructor(
@InjectRepository(Project)
private readonly repository: Repository<Project>,
) {}
async findAll(query: FindAllQuery, user: User) {
return this.repository.find({
where: { organizationId: user.organizationId },
take: query.limit,
skip: query.offset,
});
}
async create(dto: CreateProjectDto, user: User) {
const project = this.repository.create({
...dto,
organizationId: user.organizationId,
});
return this.repository.save(project);
}
}Common (src/common/)
Shared utilities and decorators:
src/common/
βββ decorators/
β βββ current-user.decorator.ts
β βββ organization.decorator.ts
βββ guards/
β βββ auth.guard.ts
β βββ organization.guard.ts
βββ interceptors/
β βββ transform.interceptor.ts
βββ filters/
βββ http-exception.filter.tsExtension Points
Extensions Directory (src/extensions/)
Add your custom code here. It wonβt be overwritten during regeneration.
src/extensions/
βββ controllers/ # Custom endpoints
β βββ reports.controller.ts
βββ services/ # Custom services
β βββ email.service.ts
βββ modules/ # Complete modules
β βββ analytics/
βββ index.ts # ExportsAdding Custom Endpoints
// src/extensions/controllers/reports.controller.ts
import { Controller, Get, UseGuards } from '@nestjs/common';
import { AuthGuard } from '../../common/guards/auth.guard';
@Controller('reports')
@UseGuards(AuthGuard)
export class ReportsController {
@Get('summary')
async getSummary() {
// Your custom logic
return { total: 100, active: 75 };
}
}Register in extensions module:
// src/extensions/index.ts
import { Module } from '@nestjs/common';
import { ReportsController } from './controllers/reports.controller';
@Module({
controllers: [ReportsController],
providers: [],
})
export class ExtensionsModule {}Configuration Files
Root Module
// src/app.module.ts
@Module({
imports: [
ConfigModule.forRoot(),
TypeOrmModule.forRoot(databaseConfig),
ProjectsModule,
TasksModule,
ExtensionsModule, // Your custom module
],
})
export class AppModule {}Main Entry Point
// src/main.ts
async function bootstrap() {
const app = await NestFactory.create(AppModule);
app.setGlobalPrefix('api/v1');
app.enableCors();
const config = new DocumentBuilder()
.setTitle('My API')
.setVersion('1.0')
.addBearerAuth()
.build();
const document = SwaggerModule.createDocument(app, config);
SwaggerModule.setup('api/docs', app, document);
await app.listen(process.env.PORT || 3001);
}
bootstrap();File Naming Conventions
| Type | Pattern | Example |
|---|---|---|
| Entity | {name}.entity.ts | project.entity.ts |
| Module | {name}.module.ts | projects.module.ts |
| Controller | {name}.controller.ts | projects.controller.ts |
| Service | {name}.service.ts | projects.service.ts |
| DTO | {action}-{name}.dto.ts | create-project.dto.ts |
| Guard | {name}.guard.ts | auth.guard.ts |
| Decorator | {name}.decorator.ts | current-user.decorator.ts |
Related
Last updated on