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.
| Adapter | Status | Notes |
|---|---|---|
| TypeORM | Stable | Default adapter, built on SelectQueryBuilder. |
| Drizzle | Stable | Opt-in via DrizzleAdapter, with explicit relations map. |
| Prisma | Roadmap | Planned. Same decorators, swapped engine. |
Quickstart
- 1Install
Add the package to your NestJS app.
pnpm add nestjs-rest-query - 2Register the module
Import DynamicQueryBuilderModule once, in your AppModule.
import { DynamicQueryBuilderModule } from 'nestjs-rest-query'; @Module({ imports: [DynamicQueryBuilderModule.forRoot()], }) export class AppModule {} - 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); }