Generated Code
APSO generates clean, production-ready code following established patterns and best practices.
Layer Architecture
Generated Components
Entities
TypeORM entities with decorators:
// src/entities/project.entity.ts
import { Entity, Column, PrimaryGeneratedColumn, OneToMany, Index } from 'typeorm';
import { Task } from './task.entity';
@Entity('projects')
export class Project {
@PrimaryGeneratedColumn('uuid')
id: string;
@Column({ length: 200 })
name: string;
@Column({ nullable: true, type: 'text' })
description: string | null;
@Index()
@Column()
organizationId: string;
@OneToMany(() => Task, task => task.project)
tasks: Task[];
@Column({ type: 'timestamp', default: () => 'CURRENT_TIMESTAMP' })
createdAt: Date;
@Column({ type: 'timestamp', default: () => 'CURRENT_TIMESTAMP', onUpdate: 'CURRENT_TIMESTAMP' })
updatedAt: Date;
}Controllers
RESTful API controllers:
// src/modules/projects/projects.controller.ts
import { Controller, Get, Post, Patch, Delete, Body, Param, Query, UseGuards } from '@nestjs/common';
import { ApiTags, ApiOperation, ApiBearerAuth } from '@nestjs/swagger';
import { ProjectsService } from './projects.service';
import { CreateProjectDto, UpdateProjectDto, FindAllQuery } from './dto';
import { AuthGuard } from '../../common/guards/auth.guard';
import { CurrentUser } from '../../common/decorators/current-user.decorator';
@ApiTags('projects')
@ApiBearerAuth()
@Controller('projects')
@UseGuards(AuthGuard)
export class ProjectsController {
constructor(private readonly projectsService: ProjectsService) {}
@Get()
@ApiOperation({ summary: 'List all projects' })
findAll(@Query() query: FindAllQuery, @CurrentUser() user: User) {
return this.projectsService.findAll(query, user);
}
@Get(':id')
@ApiOperation({ summary: 'Get a project by ID' })
findOne(@Param('id') id: string, @CurrentUser() user: User) {
return this.projectsService.findOne(id, user);
}
@Post()
@ApiOperation({ summary: 'Create a project' })
create(@Body() dto: CreateProjectDto, @CurrentUser() user: User) {
return this.projectsService.create(dto, user);
}
@Patch(':id')
@ApiOperation({ summary: 'Update a project' })
update(@Param('id') id: string, @Body() dto: UpdateProjectDto, @CurrentUser() user: User) {
return this.projectsService.update(id, dto, user);
}
@Delete(':id')
@ApiOperation({ summary: 'Delete a project' })
remove(@Param('id') id: string, @CurrentUser() user: User) {
return this.projectsService.remove(id, user);
}
}Services
Business logic with repository pattern:
// src/modules/projects/projects.service.ts
import { Injectable, NotFoundException, ForbiddenException } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { Project } from '../../entities/project.entity';
import { CreateProjectDto, UpdateProjectDto, FindAllQuery } from './dto';
@Injectable()
export class ProjectsService {
constructor(
@InjectRepository(Project)
private readonly repository: Repository<Project>,
) {}
async findAll(query: FindAllQuery, user: User): Promise<Project[]> {
const { limit = 20, offset = 0, sort, include } = query;
const qb = this.repository
.createQueryBuilder('project')
.where('project.organizationId = :orgId', { orgId: user.organizationId });
if (sort) {
const [field, order] = sort.split(':');
qb.orderBy(`project.${field}`, order?.toUpperCase() as 'ASC' | 'DESC');
}
if (include?.includes('tasks')) {
qb.leftJoinAndSelect('project.tasks', 'tasks');
}
return qb.skip(offset).take(limit).getMany();
}
async findOne(id: string, user: User): Promise<Project> {
const project = await this.repository.findOne({
where: { id, organizationId: user.organizationId },
});
if (!project) {
throw new NotFoundException(`Project with ID ${id} not found`);
}
return project;
}
async create(dto: CreateProjectDto, user: User): Promise<Project> {
const project = this.repository.create({
...dto,
organizationId: user.organizationId,
});
return this.repository.save(project);
}
async update(id: string, dto: UpdateProjectDto, user: User): Promise<Project> {
const project = await this.findOne(id, user);
Object.assign(project, dto);
return this.repository.save(project);
}
async remove(id: string, user: User): Promise<void> {
const project = await this.findOne(id, user);
await this.repository.remove(project);
}
}DTOs
Request validation with class-validator:
// src/modules/projects/dto/create-project.dto.ts
import { IsString, IsNotEmpty, MaxLength, IsOptional } from 'class-validator';
import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';
export class CreateProjectDto {
@ApiProperty({ maxLength: 200 })
@IsString()
@IsNotEmpty()
@MaxLength(200)
name: string;
@ApiPropertyOptional()
@IsOptional()
@IsString()
description?: string;
}
// src/modules/projects/dto/update-project.dto.ts
import { PartialType } from '@nestjs/swagger';
import { CreateProjectDto } from './create-project.dto';
export class UpdateProjectDto extends PartialType(CreateProjectDto) {}
// src/modules/projects/dto/find-all-query.dto.ts
import { IsOptional, IsInt, Min, Max, IsString } from 'class-validator';
import { Type } from 'class-transformer';
import { ApiPropertyOptional } from '@nestjs/swagger';
export class FindAllQuery {
@ApiPropertyOptional({ default: 20 })
@IsOptional()
@Type(() => Number)
@IsInt()
@Min(1)
@Max(100)
limit?: number = 20;
@ApiPropertyOptional({ default: 0 })
@IsOptional()
@Type(() => Number)
@IsInt()
@Min(0)
offset?: number = 0;
@ApiPropertyOptional({ example: 'createdAt:desc' })
@IsOptional()
@IsString()
sort?: string;
@ApiPropertyOptional({ example: 'tasks' })
@IsOptional()
@IsString()
include?: string;
}Modules
NestJS module wiring:
// src/modules/projects/projects.module.ts
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { Project } from '../../entities/project.entity';
import { ProjectsController } from './projects.controller';
import { ProjectsService } from './projects.service';
@Module({
imports: [TypeOrmModule.forFeature([Project])],
controllers: [ProjectsController],
providers: [ProjectsService],
exports: [ProjectsService],
})
export class ProjectsModule {}Common Utilities
Guards
// src/common/guards/auth.guard.ts
@Injectable()
export class AuthGuard implements CanActivate {
async canActivate(context: ExecutionContext): Promise<boolean> {
// JWT verification logic
}
}Decorators
// src/common/decorators/current-user.decorator.ts
export const CurrentUser = createParamDecorator(
(data: unknown, ctx: ExecutionContext) => {
const request = ctx.switchToHttp().getRequest();
return request.user;
},
);Filters
// src/common/filters/http-exception.filter.ts
@Catch()
export class HttpExceptionFilter implements ExceptionFilter {
catch(exception: unknown, host: ArgumentsHost) {
// Standardized error response
}
}Generated vs Custom Code
| Location | Generated | Custom |
|---|---|---|
src/entities/ | ✅ | ❌ |
src/modules/{entity}/ | ✅ | ❌ |
src/common/ | ✅ | ❌ |
src/extensions/ | ❌ | ✅ |
src/config/ | Partial | Partial |
Regeneration Safety
Generated files include a header:
/**
* @generated by APSO
* Do not edit this file directly.
* Modifications will be overwritten.
*/Custom code in extensions/ is never overwritten.
Related
Last updated on