npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

nestjs-crud-mixins

v1.0.0

Published

A mixins-based CRUD library for NestJS RESTful APIs with typeorm.

Readme

NestJS CRUD MIXINS

MIT License

NPM License

Overview

A CRUD Mixins Library for NestJS provides an automated and modular CRUD solution by leveraging abstract controllers and generic services.

it was inspired by Django's viewsets and mixins, this library simplifies the creation of standard CRUD endpoints in a NestJS RESTfull API with typeORM

It eliminates repetitive boilerplate by allowing developers to extend predefined generic controllers and services, automatically handling CRUD operations, validation, DTOS transformations, and filltring

Features

  • Dynamic Endpoints Generation: Automatically creates RESTful CRUD endpoints for entities.

  • DTO Validation: Ensures DTO validation is applied seamlessly with NestJS Validation Pipes.

  • DTO Transformation & Custom Responses: Supports transforming DTOs for responses and allows custom response formats.

  • Dynamic Entity Relationships: Automatically manages entity relationships

  • Customizable Query Filtering & Pagination: Enables filtering and pagination at the controller level for CRUD operations.

  • Method Overriding Support: Allows controllers to override default methods for customization.

  • Flexible Controller Configuration: Allows fine-tuned control over CRUD behavior by extending controllers

Requirements

  • Node.js (>= 18.x recommended)

  • NestJS (>= 11.x)

  • TypeScript (>= 5.x)

  • TypeORM (>= 0.3.x)

Installation

To use the CRUD mixins library, install it as a package within your NestJS project

  npm i --save @nestjs/typeorm typeorm
  npm i nestjs-crud-mixins

Quick start

1. Create your entity class and your dto classes

// user.entity.ts

@Entity('users')
export class UserEntity {
  @PrimaryGeneratedColumn()
  id: number;

  @Column()
  username: string;

  @Column()
  email: string;

  @Column()
  password: string;
}

export class CreateUserDto {
  @IsNotEmpty()
  @MinLength(3)
  username: string;

  @IsEmail()
  email: string;

  @IsNotEmpty()
  password: string;
}


export class UpdateUserDto {
  @IsNotEmpty()
  @MinLength(3)
  username: string;

  @IsEmail()
  email: string;
}

2. configure your typeOrm connection in your app.module.ts

@Module({
  imports: [
    TypeOrmModule.forRoot({
      type: 'postgres',
      host: '127.0.0.1',
      port: 5432,
      username: 'db_user',
      password: 'db_password',
      database: 'db_name',
      entities: [UserEntity],
      synchronize: true,
    }),
    TypeOrmModule.forFeature([UserEntity]),
  ],
  controllers: [AppController],
  providers: [AppService],
})
export class AppModule {}

3. Create your service class

@Injectable()
export class UserService extends MixinsCrudService<UserEntity> {
  constructor(
    @InjectRepository(UserEntity)
    private readonly userRepository: Repository<UserEntity>, // Inject the user repository
  ) {
    super(userRepository, new UserEntity()); // Pass the repository to the base CRUD service
  }
}

4. and finally create the controller class

@Controller('/users') // Define the base route for the controller
@CreateDto(CreateUserDto) // Assign the DTO for creating users
@UpdateDto(UpdateUserDto) // Assign the DTO for updating users
export class UserController extends MixinsCrudController<UserEntity, UserService> {
  constructor(private readonly userService: UserService) {
    super(userService, new UserEntity()); // Pass service and entity instance to the base controller
  }
}

Once the setup is complete, the following RESTful endpoints are automatically generated:

| Method | Endpoint | Description | Request Body | |----------|--------------|------------------------------|----------------------| | GET | /users | Fetch all users | ❌ (None) | | GET | /users/:id | Fetch a specific user by ID | ❌ (None) | | POST | /users | Create a new user | ✅ CreateUserDto | | PATCH| /users/:id | Update an existing user | ✅ UpdateUserDto | | DELETE | /users/:id | Delete a user by ID | ❌ (None) |

Documentation

Relations

To define relationships, use TypeORM decorators like @OneToMany, @ManyToOne, and @ManyToMany. extends the CrudMixinsEntity class then define the entity relation that will be handled dynamicly by the service

@Entity('users')
export class UserEntity extends MixinsCrudEntity {
  @PrimaryGeneratedColumn()
  id: number;

  @Column()
  username: string;

  @OneToOne(() => ProfileEntity, (profile) => profile.user, {
    cascade: true,
    eager: true,
  })
  @JoinColumn()
  profile: ProfileEntity;

  constructor() {
    super();
    // Call the setRelations methode with an array of the entity relations
    this.setRelations(['profile']);
  }

Custom Responses

By default the controllers return the entity object as a response for GET and POST requests however it is possible to customize this response using the @ResponseDtodecorators

// DTO 
export class ResponseUserDto {
  @Expose()  // ensure to add the @Expose controller for the mapping process 
  id: number;

  @Expose()
  username: string;
}

// Controller
@Controller('/users')
@ResponseDto(ResponseUserDto). // Add your ResponseDto at controller level  
@CreateDto(CreateUserDto)
@UpdateDto(UpdateUserDto)
export class AppController extends MixinsCrudController<
  UserEntity,
  AppService
> {
  constructor(private readonly appService: AppService) {
    super(appService, new UserEntity());
  }
}

In case of different Response DTOS for different routes the decorator can be used at methode level

@Controller('/users')
@CreateDto(CreateUserDto)
@UpdateDto(UpdateUserDto)
export class AppController extends MixinsCrudController<
  UserEntity,
  AppService
> {
  constructor(private readonly appService: AppService) {
    super(appService, new UserEntity());
  }
  @Get('active')
  @ResponseDto(ResponseUserDto)
  async getActiveUsers(): Promise<UserEntity[]> {
    // implimentation 
  }
}

It is also possible to customize the response format

@Controller('/users')
@ResponseDto(ResponseUserDto, (data) => ({
  message: 'User List',
  data: data,
}))
@CreateDto(CreateUserDto)
@UpdateDto(UpdateUserDto)
export class AppController extends MixinsCrudController<
  UserEntity,
  AppService
> {
  constructor(private readonly appService: AppService) {
    super(appService, new UserEntity());
  }
}

this returns a response on the format and can handel dynamicly arrays of data

{
    "message": "user retrived",
    "success": "true",
    "data": {
        "username": "username",
        "email": "email"
    }
}

Filtering Queries

it is possible to configure the filtering logic globaly on the controller level using FilterOptions and FilterOptionsBuilder on controller level or in methods

@Controller('/users')
@ResponseDto(ResponseUserDto)
@CreateDto(CreateUserDto)
@UpdateDto(UpdateUserDto)
export class AppController extends MixinsCrudController<
  UserEntity,
  AppService
> {
  // Filtring by id and selection username and id 
  filterOptions = new FilterOptionsBuilder()
    .setOrderBy([{ field: 'id', order: 'DESC' }])
    .setSelectFields(['username', 'id'])
    .build();

  constructor(private readonly appService: AppService) {
    super(appService, new UserEntity());
  }

  @Get('active')
  @ResponseDto(ResponseUserDto)
  async getActiveUsers(): Promise<ResponseUserDto> {
    // filtering active users 
    const filterOptions = new FilterOptionsBuilder()
      .setSearch(['active'], 'true')
      .build();
    return this.appService.findAllEntities(filterOptions);
  }
}

Soft delete

For soft delete add the option includeDeleted to true in the filtering options

filterOptions = new FilterOptionsBuilder()
    .setIncludeDeleted(true)
    .build();

👨‍💻 Author

Mazene ZERGUINE
🚀 GitHub: Mazene-ZERGUINE
📧 Email: [email protected]

Feel free to reach out for any questions, suggestions, or collaborations! 😊

📝 Feedback

If you have any suggestions, feature requests, or issues, please feel free to:

Your feedback is highly appreciated! 🚀

🤝 Contributing

Contributions are welcome and encouraged! 🎉 If you want to improve this project, follow these steps: