@tsh96/nest-typegoose-crud v0.1.1
Description
This package provides several decorators and classes for endpoints generation, model validation, and access control If you are looking for mongoose version, please move to @tsh96/nest-mongoose-crud
Features
- Super easy to install and start using the full-featured controllers and services.
- DB and service agnostic extendable CRUD controllers.
- Reach query parsing with filtering, pagination, and sorting.
- Query, path params and DTOs validation included.
- Overriding or inherit controller methods with ease
- Tiny config
- Swagger documentation
- Code Generator
Install
Create a new nestjs project and install following dependencies.
Yarn (Recommended)
yarn add @tsh96/nest-typegoose-crud class-transformer class-validator @nestjs/swagger @typegoose/typegoose nestjs-typegooseNpm
npm install @tsh96/nest-typegoose-crud class-transformer class-validator @nestjs/swagger @typegoose/typegoose nestjs-typegooseGetting started
Codegen
Codegen is a handy tool to generate code for controller, dto, module, schema and service.
yarn codegen [resource] [path?]For example yarn codegen cat will create a files under src/cat folder and yarn codegen puppy d1/d2 will create a files under src/d1/d2
Manually
Create a typegoose schema
// dog.schema.ts
import { prop } from '@typegoose/typegoose';
import { ApiProperty } from '@nestjs/swagger';
import { IsNumber, IsString } from 'class-validator';
import { Document } from 'mongoose';
export type DogDocument = Dog & Document;
@Schema()
export class Dog {
@prop() // For typegoose
@ApiProperty() // For swagger
@IsString() // For class validator
name: string;
@prop() // For typegoose
@ApiProperty() // For swagger
@IsNumber() // For class validator
age: number;
@prop() // For typegoose
@ApiProperty() // For swagger
@IsString() // For class validator
breed: string;
}Create Dto(s) for services:
//dog.dto.ts
import { ApiProperty } from '@nestjs/swagger';
import { IsNumber, IsString, IsOptional } from 'class-validator';
import { Dog } from './dog.schema';
export class CreateDogDto extends Dog {
@ApiProperty() // For swagger
@IsString() // For class validator
name: string;
@ApiProperty() // For swagger
@IsNumber() // For class validator
age: number;
@ApiProperty() // For swagger
@IsString() // For class validator
breed: string;
}
export class UpdateDogDto {
@ApiProperty({ required: false }) // For swagger
@IsString() // For class validator
@IsOptional() // For class validator
name?: string;
@ApiProperty({ required: false }) // For swagger
@IsNumber() // For class validator
@IsOptional() // For class validator
age?: number;
@ApiProperty({ required: false }) // For swagger
@IsString() // For class validator
@IsOptional() // For class validator
breed?: string;
}Then create a crud service. Must have CrudInjectable decorator and extends CrudService:
//dog.service.ts
import { Model } from 'mongoose';
import { InjectModel } from 'nestjs-typegoose';
import { Dog, DogDocument } from './dog.schema';
import { CreateDogDto, UpdateDogDto } from './dog.dto';
import { CrudInjectable, CrudService } from '@tsh96/nest-typegoose-crud';
@CrudInjectable({
createDto: CreateDogDto,
updateDto: UpdateDogDto,
mongooseModel: Dog,
filterQuery: UpdateDogDto,
})
export class DogsService extends CrudService {
constructor(@InjectModel(Dog) dogModel: Model<DogDocument>) {
super(dogModel);
}
}Create a controller. Must have Crud decorator and extends CrudController::
//dogs.controller.ts
import { ParseArrayPipe, ParseIntPipe } from '@nestjs/common';
import { ApiBearerAuth } from '@nestjs/swagger';
import { AuthResource, Crud, CrudController } from '@tsh96/nest-typegoose-crud';
import { DogsService } from './dogs.service';
@ApiBearerAuth()
@AuthResource('dogs')
@Crud('dogs', { crudService: DogsService, ParseArrayPipe, ParseIntPipe })
export class DogsController extends CrudController<DogsService, any> {
constructor(readonly service: DogsService) {
super(service);
}
}Connect controller and service with a module
//dogs.module.ts
import { Module } from '@nestjs/common';
import { TypegooseModule } from 'nestjs-typegoose';
import { Dog } from './dog.schema';
import { DogsController } from './dogs.controller';
import { DogsService } from './dogs.service';
@Module({
imports: [TypegooseModule.forFeature([Dog])],
controllers: [DogsController],
providers: [DogsService],
})
export class DogsModule {}BINGO!
API endpoints
| Action | One | Bulk |
|---|---|---|
| Create | POST /dogs | POST /dogs/bulk |
| Read | GET /dogs/:dogId | GET /dogs |
| Update | PUT /dogs/:dogId | PUT /dogs requiredParam(filter) |
| Delete | DELETE /dogs/:dogId | DELETE /dogs requiredBody([...ids]) |
Access Control
@AuthResource and @AuthActions decorators are worked together to define permissions for each endpoint.
@AuthResource is used on controllers and @AuthActions is used on actions (methods).
For example
//dogs.controller.ts
import { ParseArrayPipe } from '@nestjs/common';
import { ApiBearerAuth } from '@nestjs/swagger';
import {
AuthResource,
AuthActions,
Crud,
CrudController,
} from 'nest-typegoose-crud';
import { DogsService } from './dog.service';
@ApiBearerAuth() // For Swagger Api
@AuthResource('dog') // For Access Control (Roles Guard)
@Crud('dogs', { crudService: DogsService, ParseArrayPipe }) // For Crud Controller
export class DogsController extends CrudController<DogsService, any> {
constructor(readonly service: DogsService) {
super(service);
}
@Patch('feed')
@AuthActions('Feed')
// @AuthActions('FeedOne', 'FeedMany') it also can be multiple
feed() {
// code here
}
}Some basic actions are included in the crud actions:
| Action | One | Bulk |
|---|---|---|
| Create | CreateOne, CreateMany | CreateMany |
| Read | ReadOne, ReadMany | ReadMany |
| Update | UpdateOne, UpdateMany | UpdateMany |
| Delete | DeleteOne, DeleteMany | DeleteMany |
Override/Inheritance
You can override or inherit controllers as below:
//imports ...
@ApiBearerAuth() // For Swagger Api
@AuthResource('dog') // For Access Control (Roles Guard)
@Crud('dogs', { crudService: DogsService, ParseArrayPipe }) // For Crud Controller
export class DogsController extends CrudController<DogsService, any> {
constructor(readonly service: DogsService) {
super(service);
}
@Post()
@AuthActions('CreateOne')
ApiOkResponse({ type: CreateOneResponse });
createOne(@Body() body: CreateDogDto) {
// code here...
return super(body); //inherit (optional)
}
}Here are the method names for respective action.
| Action | One | Bulk |
|---|---|---|
| Create | createOne | createMany |
| Read | findById | findMany |
| Update | updateById | updateMany |
| Delete | deleteById | deleteMany |
Services also:
//imports ...
@CrudInjectable({
createDto: CreateDogDto,
updateDto: UpdateDogDto,
mongooseModel: Dog,
filterQuery: UpdateDogDto,
}) // For Crud Service
export class DogsService extends CrudService {
constructor(@InjectModel(Dog) dogModel: Model<DogDocument>) {
super(dogModel);
}
feed() {
//code here...
}
}