Skip to main content

Overview

The @ParsedRequest decorator is a parameter decorator that injects the parsed CRUD request object into your controller method parameters. It provides access to parsed query parameters, filters, joins, pagination settings, and more.

Signature

export const ParsedRequest = createParamDecorator(
  (_, ctx): ParameterDecorator => {
    return R.getContextRequest(ctx)[PARSED_CRUD_REQUEST_KEY];
  },
);

Returns

CrudRequest
CrudRequest
The parsed CRUD request object
parsed
ParsedRequestParams
Parsed request parameters including:
  • fields - Selected fields
  • paramsFilter - URL parameter filters
  • search - Search conditions
  • filter - Query filters
  • or - OR conditions
  • join - Relation joins
  • sort - Sort configuration
  • limit - Pagination limit
  • offset - Pagination offset
  • page - Current page number
  • cache - Cache settings
options
CrudRequestOptions
Request options including query, routes, and params configuration

Usage

Basic Usage

import { Controller } from '@nestjs/common';
import { Crud, Override, ParsedRequest, CrudRequest } from '@nestjsx/crud';
import { User } from './user.entity';
import { UserService } from './user.service';

@Crud({
  model: { type: User },
})
@Controller('users')
export class UserController {
  constructor(public service: UserService) {}

  @Override()
  async getMany(@ParsedRequest() req: CrudRequest) {
    console.log('Parsed filters:', req.parsed.filter);
    console.log('Pagination:', { limit: req.parsed.limit, offset: req.parsed.offset });
    
    return this.service.getMany(req);
  }
}

Accessing Query Parameters

@Crud({
  model: { type: Post },
})
@Controller('posts')
export class PostController {
  constructor(public service: PostService) {}

  @Override('getManyBase')
  async getPosts(@ParsedRequest() req: CrudRequest) {
    // Access parsed query parameters
    const { filter, sort, limit, page } = req.parsed;
    
    console.log('Filters applied:', filter);
    console.log('Sort order:', sort);
    console.log('Results per page:', limit);
    console.log('Current page:', page);
    
    return this.service.getMany(req);
  }
}

Using with URL Parameters

@Crud({
  model: { type: Comment },
  params: {
    postId: {
      field: 'postId',
      type: 'number',
    },
  },
})
@Controller('posts/:postId/comments')
export class CommentController {
  constructor(public service: CommentService) {}

  @Override()
  async getMany(@ParsedRequest() req: CrudRequest) {
    // Access URL parameters from paramsFilter
    const postId = req.parsed.paramsFilter.find(f => f.field === 'postId')?.value;
    console.log('Getting comments for post:', postId);
    
    return this.service.getMany(req);
  }
}

Inspecting Joins

@Crud({
  model: { type: Order },
  query: {
    join: {
      customer: { eager: true },
      items: { eager: false },
    },
  },
})
@Controller('orders')
export class OrderController {
  constructor(public service: OrderService) {}

  @Override()
  async getOne(@ParsedRequest() req: CrudRequest) {
    // Check which relations are being loaded
    console.log('Joins requested:', req.parsed.join);
    
    const order = await this.service.getOne(req);
    
    // Add custom processing based on loaded relations
    if (req.parsed.join?.some(j => j.field === 'items')) {
      order.totalItems = order.items.length;
    }
    
    return order;
  }
}

Modifying Request Before Processing

@Crud({
  model: { type: Product },
})
@Controller('products')
export class ProductController implements CrudController<Product> {
  constructor(public service: ProductService) {}

  get base(): CrudController<Product> {
    return this;
  }

  @Override()
  async getMany(@ParsedRequest() req: CrudRequest) {
    // Add additional filters programmatically
    if (!req.parsed.filter) {
      req.parsed.filter = [];
    }
    
    req.parsed.filter.push({
      field: 'isActive',
      operator: '$eq',
      value: true,
    });
    
    return this.base.getManyBase(req);
  }
}

Using in Create/Update Operations

@Crud({
  model: { type: Article },
})
@Controller('articles')
export class ArticleController implements CrudController<Article> {
  constructor(public service: ArticleService) {}

  get base(): CrudController<Article> {
    return this;
  }

  @Override()
  async createOne(
    @ParsedRequest() req: CrudRequest,
    @ParsedBody() dto: Article,
    @Request() request
  ) {
    // Access request options
    console.log('Request options:', req.options);
    
    // Add metadata
    dto.authorId = request.user.id;
    dto.createdAt = new Date();
    
    return this.base.createOneBase(req, dto);
  }
}

Complete Integration Test Example

From the source tests:
packages/crud/test/crud.decorator.override.spec.ts:48-56
@Override()
getMany(@ParsedRequest() req: CrudRequest) {
  return { foo: 'bar' };
}

@Override('createManyBase')
createBulk(@ParsedBody() dto: CreateManyDto<TestModel>, @ParsedRequest() req: CrudRequest) {
  return this.base.createManyBase(req, dto);
}

Standalone Usage with Interceptor

import { Get, Controller, UseInterceptors } from '@nestjs/common';
import { CrudRequestInterceptor, ParsedRequest, CrudRequest } from '@nestjsx/crud';

@Controller('custom')
export class CustomController {
  @Get()
  @UseInterceptors(CrudRequestInterceptor)
  async getData(@ParsedRequest() req: CrudRequest) {
    // Use ParsedRequest outside of @Crud decorator
    console.log('Parsed request:', req.parsed);
    return { message: 'Custom endpoint with CRUD request parsing' };
  }
}

Implementation Details

packages/crud/src/decorators/parsed-request.decorator.ts:6-10
export const ParsedRequest = createParamDecorator(
  (_, ctx): ParameterDecorator => {
    return R.getContextRequest(ctx)[PARSED_CRUD_REQUEST_KEY];
  },
);
The decorator is built using NestJS’s createParamDecorator and extracts the parsed request from the execution context.
The @ParsedRequest decorator automatically works with routes generated by @Crud. For custom routes, use @UseInterceptors(CrudRequestInterceptor) to enable request parsing.
The parsed request object is read-only in most scenarios. While you can modify it in your code, changes may not affect the underlying query execution depending on when the service method is called.

Request Structure

Typical parsed request structure:
{
  parsed: {
    fields: ['id', 'name', 'email'],
    paramsFilter: [
      { field: 'id', operator: '$eq', value: 1 }
    ],
    search: {
      $and: [
        { name: { $contL: 'john' } }
      ]
    },
    filter: [
      { field: 'isActive', operator: '$eq', value: true }
    ],
    or: [],
    join: [
      { field: 'profile', select: ['firstName', 'lastName'] }
    ],
    sort: [
      { field: 'createdAt', order: 'DESC' }
    ],
    limit: 10,
    offset: 0,
    page: 1,
    cache: 0
  },
  options: {
    query: { /* query options */ },
    routes: { /* routes options */ },
    params: { /* params options */ }
  }
}

See Also

Build docs developers (and LLMs) love