NestJS · TypeORM · Drizzle

Turn REST query strings into safe database queries.

nestjs-rest-query gives NestJS endpoints dynamic filters, sorting, pagination, field selection, and relation loading with a per-endpoint whitelist for TypeORM and Drizzle.

From handwritten query plumbing to a single decorator

Every endpoint declares the fields, sorts, and operators it accepts. The library parses the query string, validates against the whitelist, and runs the query through TypeORM or Drizzle.

Before — handwritten
@Get()
async listCompanies(@Query() query: ListCompaniesQuery) {
  const qb = this.companies.createQueryBuilder('company');

  if (query.name) qb.andWhere('company.name ILIKE :n', { n: `%${query.name}%` });
  if (query.cnpj) qb.andWhere('company.cnpj = :c', { c: query.cnpj });
  if (query.createdFrom) qb.andWhere('company.createdAt >= :f', { f: query.createdFrom });

  if (query.sort === 'name') qb.orderBy('company.name', query.dir ?? 'ASC');
  if (query.sort === 'createdAt') qb.orderBy('company.createdAt', query.dir ?? 'DESC');

  const page = Number(query.page ?? 1);
  const perPage = Math.min(Number(query.perPage ?? 20), 100);
  qb.skip((page - 1) * perPage).take(perPage);

  const [data, total] = await qb.getManyAndCount();
  return { data, page, perPage, total, lastPage: Math.ceil(total / perPage) };
}
After — nestjs-rest-query
@Get()
@ApiDynamicQuery<Company>({
  filters: ['name', 'cnpj', 'createdAt'],
  sorts: ['name', 'createdAt'],
  fields: ['id', 'name', 'cnpj', 'createdAt'],
})
findAll(@Query() query: QueryInput, @QueryRules() rules: RulesConfig) {
  return this.qb.execute(this.companies, query, rules);
}

Adapter compatibility

TypeORM and Drizzle are stable. Prisma is on the roadmap and will use the same decorators and whitelist contract.

AdapterStatusNotes
TypeORMStableDefault adapter, built on SelectQueryBuilder.
DrizzleStableOpt-in via DrizzleAdapter, with explicit relations map.
PrismaRoadmapPlanned. Same decorators, swapped engine.

Quickstart

  1. 1Install

    Add the package to your NestJS app.

    pnpm add nestjs-rest-query
  2. 2Register the module

    Import DynamicQueryBuilderModule once, in your AppModule.

    import { DynamicQueryBuilderModule } from 'nestjs-rest-query';
    
    @Module({
      imports: [DynamicQueryBuilderModule.forRoot()],
    })
    export class AppModule {}
  3. 3Declare the whitelist

    Each endpoint declares which fields, sorts, and includes clients may use.

    @Get()
    @ApiDynamicQuery<Company>({
      filters: ['name', 'cnpj', 'createdAt'],
      sorts: ['name', 'createdAt'],
    })
    findAll(@Query() q: QueryInput, @QueryRules() rules: RulesConfig) {
      return this.qb.execute(this.companies, q, rules);
    }