Skip to content

Getting Started

This guide shows how to install @querry-kit/nest-fields-query, create field schemas, validate fields query values, and apply projections to response DTOs.

Installation

Install the package from npm:

sh
pnpm add @querry-kit/nest-fields-query

@querry-kit/nest-fields-query uses object helpers from @querry-kit/nest-util. Install it explicitly when your package manager does not install regular dependencies automatically:

sh
pnpm add @querry-kit/nest-fields-query @querry-kit/nest-util

GitHub release tags remain available as a fallback. The main branch contains source only; release tags contain the built dist files required by Node.js.

sh
pnpm add github:querry-kit/nest-fields-query#vX.Y.Z

TypeScript ESM

This package is ESM-first. In TypeScript projects that emit ESM, keep relative local imports explicit with .js extensions.

Create a Field Schema

Use Swagger-decorated DTOs when your response DTOs already describe the public response shape:

ts
import { ApiProperty } from '@nestjs/swagger';
import { buildFieldSchemaFromDto } from '@querry-kit/nest-fields-query';

class ProfileDTO {
  @ApiProperty()
  firstName!: string;
}

class UserDTO {
  @ApiProperty()
  id!: string;

  @ApiProperty({ type: () => ProfileDTO })
  profile!: ProfileDTO;
}

const userSchema = buildFieldSchemaFromDto(UserDTO);

Manual schemas are useful when a route exposes a custom shape:

ts
import { relation } from '@querry-kit/nest-fields-query';

const userSchema = {
  id: true,
  email: true,
  profile: relation({
    firstName: true,
    lastName: true,
  }),
};

Use Fields in Controllers

Parse and validate the raw query value with FieldsQuery before calling the service. Use Fields.include when selected relation fields need to be included in the query result.

ts
import { Controller, Get, Query } from '@nestjs/common';
import { Fields, FieldsProjection, FieldsQuery, buildFieldSchemaFromDto } from '@querry-kit/nest-fields-query';

const userSchema = buildFieldSchemaFromDto(UserDTO);

@Controller('users')
export class UsersController {
  @Get()
  async findMany(
    @Query() query: { include?: unknown },
    @FieldsQuery(UserDTO) fields?: FieldsProjection,
  ) {
    const include = fields ? Fields.include(fields, userSchema, query.include) : query.include;

    const items = await this.usersService.findMany({ ...query, include });
    const dtoItems = items.map(UserDTO.fromModel);

    return Fields.project(dtoItems, fields);
  }
}

@FieldsQuery(DTO) derives its validation schema from Swagger metadata, so selectable DTO properties must be decorated with @ApiProperty or compatible Swagger metadata.

Register the Exception Filter

Register FieldsExceptionFilter globally when invalid fields query parameters should produce a structured HTTP 400 response:

ts
import { FieldsExceptionFilter } from '@querry-kit/nest-fields-query';

app.useGlobalFilters(new FieldsExceptionFilter());

Example API

The repository includes a small books and authors NestJS API under examples/books-api. It follows the same controller flow shown above, including DTO-backed schemas, generated includes, service calls, DTO mapping, and response projection.

GET Request Example

For the books example, a client can request a nested author projection like this:

http
GET /books?fields=id,title,author{name,books{title}}

The same request in a Bruno-style environment usually keeps the base URL in a variable and lists query parameters explicitly:

txt
GET {{host}}/api/v1/books?fields=id,title,author{name,books{title}}

Query Params:
fields: id,title,author{name,books{title}}

When an endpoint validates that selected relations are also present in the incoming include query, use bracket notation for explicit includes:

txt
GET {{host}}/api/v1/books?fields=id,title,author{name,books{title}}&include[author][include][books]=true

Query Params:
fields: id,title,author{name,books{title}}
include[author][include][books]: true

Runtime Expectations

  • FieldsParser accepts strings such as id,email,profile{firstName}.
  • Empty, null, or undefined values return undefined.
  • Invalid syntax throws FieldsBadRequestException.
  • FieldsValidator rejects unknown fields and nested selections on scalar schema nodes.
  • Fields.include preserves existing include configuration and normalizes dotted include keys through @querry-kit/nest-util.
  • Fields.project works with objects, arrays, primitives, null, and undefined.

Minimal Verification

After installation, add a small controller or utility test:

ts
import { Fields, relation } from '@querry-kit/nest-fields-query';

it('projects selected fields', () => {
  const schema = { id: true, profile: relation({ firstName: true }) };
  const projection = Fields.parseAndValidate('id,profile{firstName}', schema);

  expect(Fields.project({ id: '1', profile: { firstName: 'Ada', lastName: 'Lovelace' } }, projection)).toEqual({
    id: '1',
    profile: { firstName: 'Ada' },
  });
});

Released under the MIT License.