Skip to content

Fields

The fields API is split into small classes and controller helpers. Most endpoints should use ResourceQuery or prepareFieldsQuery; use the low-level classes when you need fine-grained control.

Resource Facade

ts
const result = await ResourceQuery.query({
  service: this.usersService,
  query,
  schema: UserDTO,
  ability: req.ability,
  map: (user, ability) => UserDTO.fromModel(user, ability),
});

schema accepts either a manual FieldSchema or a Swagger-decorated DTO class. The helper:

  • parses and validates query.fields.
  • merges endpoint-required includes, client includes, and generated relation includes into a query copy.
  • calls service.query or service.findById.
  • maps models to DTOs, including async mappers.
  • applies Fields.project to the mapped DTO response. Paginated responses can project either item fields (fields=id,title or fields={id,title}) or the response envelope (fields=items{id,title},meta{page,perPage}). An explicit empty selection (fields= or fields={}) returns an empty envelope; items{} can intentionally return empty item objects.

prepareFieldsQuery

ts
const prepared = prepareFieldsQuery(query, UserDTO, {
  baseInclude: {
    organization: true,
  },
});

await usersService.query(prepared.query, ability);
Fields.project(dtoItems, prepared.projection);

prepareFieldsQuery does not mutate the original query object. baseInclude is useful when the endpoint, CASL-aware mapper, or response policy needs relations even when the client omits fields; the client include query parameter extends that include object.

Low-Level Flow

ts
const projection = FieldsParser.parse(query.fields);

if (projection) {
  FieldsValidator.validateProjection(projection, userSchema);
}

const include = projection ? Fields.include(projection, userSchema, query.include) : query.include;
const response = FieldsProjector.project(dtoItems, projection);

Manual Field Schema

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

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

Decorators and Errors

Use ApiResourceQuery() for list endpoints that expose fields, page, perPage, select, include, where, orderBy, and distinct. Use ApiFieldsQuery() for detail or mutation endpoints that only expose response projection. Use @FieldsQuery(DTO) when a controller parameter should receive a validated FieldsProjection.

ts
@Get()
@ApiFieldsQuery()
async find(@FieldsQuery(UserDTO) fields?: FieldsProjection) {}

Register FieldsExceptionFilter globally when invalid fields values should produce structured HTTP 400 responses.

Released under the MIT License.