Flug-Nest is a template for web application development powered by Sequelize-typescript and NestJs framework, inspired on flugzeug framework. It provides modules, validators, interceptors, pipes, decorators, database migration system, logger, auto-generated swagger documentation and a cli tool to accelerate the development process.
Either through cloning with git or by using Flugnest generator (the recommended way)
npm install -g flugnest-generator
Flugnest-generator is ready to use since is globally installed:
To generate an app run.
flugnest app [name of your app]
To generate a module run in the root of your app.
flugnest module [name of your module]
After create your module do not forget to register it into nest app in file src/app.module.ts
import { BookModule } from './modules/book/book.module';
@Module({
imports: [databaseModule, UserModule, BookModule, AuthModule],
controllers: [AppController],
providers: [AppService],
})
In the root directiry run
# unit tests
$ npm run test
# coverage
$ npm run test:cov
# integration/end to end
$ npm run test:e2e
In the root directiry run
# development
$ npm run start
# watch mode
$ npm run start:dev
By default you can find the swagger docuementation of your app here: http://localhost:3000/swagger or If you prefer view the documentation in a json format you can find it here: http://localhost:3000/swagger-json
Please refer to sequelize-typescript and Sequelize Nest
import {
BelongsTo,
Column,
DataType,
ForeignKey,
Table,
} from 'sequelize-typescript';
import { BaseModel } from '@libraries/BaseModel';
import { ApiHideProperty } from '@nestjs/swagger';
import { User } from 'src/modules/user/entities/user.entity';
@Table({
tableName: 'note',
})
export class Note extends BaseModel<Note> {
@Column({
type: DataType.STRING,
allowNull: true,
})
name: string;
@ForeignKey(() => User)
@Column
userId: number;
@ApiHideProperty() //hide property in openApi definition (swagger)
@BelongsTo(() => User)
user: User;
}
Please refer to Nest validation techniques and Class-validator
import { IsNotEmpty, IsOptional, IsString } from 'class-validator';
export class CreateNoteDto {
@IsNotEmpty() //indicates required for run time validator
@IsString()
name: string; //indicates required for swagger docs
@IsOptional() //indicates optional for run time validator
@IsString()
title?: string; // ? indicates optional for swagger docs
}
Please refer to Nest Controllers
@ApiExtraModels(Note) //add the Entity as a swagger schema
@ApiTags('notes')
@Controller('notes')
export class NoteController {
constructor(private readonly noteService: NoteService) {}
@ApiOperation({ summary: 'Create a Note' })
@ApiCommonResponses() //add swagger common responses
@ApiCreatedResponseData(Note) //Add created swagger response
@AppendUser() //append userId to body
@ValidateJWT() //validate jwt and add ApiBearerAuth swagger definition
@Post()
//validate CreateNoteDto following class validator decorators in CreateNoteDto
create(@Body() createNoteDto: CreateNoteDto) {
return this.noteService.create(createNoteDto);
}
@ApiOperation({ summary: 'Get all Note entries' })
@ApiQueryAttributes()
@ApiQueryWhere()
@ApiQueryInclude()
@ApiQueryPagination()
@ApiOkResponsePaginatedData(Note)
@ApiCommonResponses()
@FilterOwner()
@ValidateJWT()
@Get()
findAll(
@Query('where', ParseWherePipe) where?: WhereOptions,
@Query('offset', ParseOffsetPipe) offset?: number,
@Query('limit', ParseLimitPipe) limit?: number,
@Query('attributes', ParseAttributesPipe)
attributes?: string[],
@Query('order', ParseOrderPipe) order?: OrderItem[],
@Query('include', new ParseIncludePipe(Note))
include?: IncludeOptions[],
) {
return this.noteService.findAll({
where,
attributes,
offset,
limit,
include,
order,
});
}
@ApiOperation({ summary: 'Get Note entry by id' })
@ApiCommonResponses()
@ApiOkResponseData(Note)
@ApiQueryAttributes()
@ApiQueryInclude()
@IsOwner(NoteService)
@ValidateJWT()
@Get(':id')
findOne(
@Param('id', ParseIntPipe) id: number,
@Query('include', new ParseIncludePipe(Note))
include?: IncludeOptions[],
@Query('attributes', ParseAttributesPipe)
attributes?: string[],
) {
return this.noteService.findOne(+id, include, attributes);
}
@ApiOperation({ summary: 'Update Note entry by id' })
@ApiCommonResponses()
@ApiOkResponseData(Note)
@IsOwner(NoteService)
@ValidateJWT()
@Patch(':id')
update(
@Param('id', ParseIntPipe) id: number,
@Body() updateNoteDto: UpdateNoteDto,
) {
return this.noteService.update(+id, updateNoteDto);
}
@ApiOperation({ summary: 'Delete Note entry by id' })
@ApiCommonResponses()
@HttpCode(204)
@IsOwner(NoteService)
@ValidateJWT()
@Delete(':id')
remove(@Param('id', ParseIntPipe) id: number) {
return this.noteService.remove(+id);
}
}
Please refer to Nest OpenApi
Please update your database access credentials on the .env file in the root of the project if needed.
SQLite is configured as a database engine by default, to change the database engine please refer to Sequelize Dialect-Specific to install the required connector library.
docker run --name postgres -p 5432:5432 -e POSTGRES_PASSWORD=postgres -d postgres
npm run makemigration
Please Note: These migrations only create an "up" action, "down" actions need to be created manually if desired.
Feel free to manually modify the generated migration files in src/core/database/migrations
to customize and solve those edge cases when needed.
npm run migrate