Home > Software engineering >  UsePipes for a service function in NestJs
UsePipes for a service function in NestJs

Time:10-16

Is it possible to use a validation pipe for a service function ? I want to check my data in a function that create an object in a class but it seems to have no effect :

@UsePipes(new ValidationPipe())
async create(createMemberDto: CreateMemberDto, temp: boolean=false) {
    // Do something
}

The pipe is working well for my endpoint in controller but not for this function in service (if a value is missing, not exception is thrown).

How can I deal with it, or is there any alternative ?

CodePudding user response:

No, it is not possible. This @UsePipes() sets up metadata that Nest reads later on. When Nest boots up, it sets up each route essentially as a middleware for the underlying HTTP adapter. In this middleware, Nest checks for all the possible metadata (method type, route name, use pipes, use guards, use interceptors, and use filters) and then the metadata for the route handler's parameters (req, body, param, query, etc) and essentially does something like this (heavy psuedocode coming in, the actual code is much cleaner and written way better)

const foundClasses = await this.discoveryService.findClassesWithMetadata(ControllerMetadata);
for (const found of foundClasses) {
  const routes = await this.discoveryService.findMethodsOfClassWithMetadata(RouteHandlerMetadata, found);
  for (const route of routes) {
    const usePipes = this.reflector.get(PipesMetadata, found, route);
    const useGuards = this.reflector.get(GuardMetadata, found, route);
    const useInterceptors = this.reflector.get(InterceptorMetadata, found, route);
    const useFilters = this.reflector.get(FilterMetadata, found, route);
    if (useGuards) {
      callGuardsToCheck(useGaurds.guards);
    }
    if (useInterceptors) {
      callInterceptors(useInterceptors.interceptors);
    }
    if (usePipes) {
      callPipes(usePipes.pipes);
    }
    if (useFilters) {
      bindFilters(useFilters.filters);
    }
    this.httpAdapter[route.method ?? 'use'](`${found.route}/${route.route}`, (req, res, next) => next(found[route.name](metadataFromParameters(req)));
  }
}

I promise, that's way messier and dirtier than anything in the code base.

But it illustrates that once the controller's route handler method is called (found[route.name]()) then the request is out of Nest's hands until the return of the controller comes back, so it can't bind the pipe to the service.


With all that said, it is possible to import transform from class-transformer and validate from class-validator and run the validations yourself. The pipe doesn't do anything special other than manage the calls to those and skip calling those on primitives

  • Related