Search code examples
javascriptnestjspipehttpresponse

how to have HTTP response with pipe throwing error?


I have a nestjs application in which I created a pipe to check if the value is a valid URL. If the URL is invalid, throw an error. This is used in a controller to save an item into the database.

I just realized the pipe would throw 500 with Internal Server Error, I had to check the server log to see if it's actually from the pipe.

I wonder if there's a way that we can have an HTTP response directly with the message?

The pipe code I have is...

import { BadRequestException, Injectable, PipeTransform } from '@nestjs/common';

@Injectable()
export class ValidUrlPipe implements PipeTransform {
  transform(website: string) {
    if (website === '') return website;

    const validProtocols = ['http:', 'https:'];

    const { protocol } = new URL(website);
    if (validProtocols.includes(protocol)) {
      return website;
    }

    throw new BadRequestException(`invalid website value: ${website}`);
  }
}

the controller using the pipe looks like

  @Post()
  create(
    @Body('website', ValidUrlPipe) website: string,
    @Body() createTvDto: CreateTvDto,
    @CurrentUser() user: User,
  ) {
    return this.televisionsService.create(user._id, createTvDto);
  }

Thank you so much in advance for any suggestions/solutions.

enter image description here

EDIT: I added an image of the error thrown by using Postman to call the endpoint


Solution

  • Dora, let me help you with the actual solution:

    import { BadRequestException, Injectable, PipeTransform } from '@nestjs/common';
    
    @Injectable()
    export class ValidUrlPipe implements PipeTransform {
      transform(website: string) {
        if (website === '') return website;
    
        const validProtocols = ['http:', 'https:'];
    
        try {
          const { protocol } = new URL(website);
          if (validProtocols.includes(protocol)) {
            return website;
          }
        } catch (error) {
          // Maybe add another bit of logging here for your own records if it is of interest?
          throw new BadRequestException(`invalid website value: ${website}`);
        }
      }
    }
    

    For those of you privileged with Node 20:

    Instead of wrapping it all in a try/catch, you could use the static method URL.canParse().

    Implemented for your pipe:

    import { BadRequestException, Injectable, PipeTransform } from '@nestjs/common';
    
    @Injectable()
    export class ValidUrlPipe implements PipeTransform {
      transform(website: string) {
        if (website === '') return website;
    
        const validProtocols = ['http:', 'https:'];
    
        if (URL.canParse(website)) { 
           // URL.canParse(...) returns a boolean if the url is valid or not
           const { protocol } = new URL(website);
           if (validProtocols.includes(protocol)) {
             return website;
           }
        }
        throw new BadRequestException(`invalid website value: ${website}`);
      }
    }