Dora
Dora

Reputation: 6970

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

Upvotes: 1

Views: 605

Answers (3)

Lior Kupers
Lior Kupers

Reputation: 847

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}`);
  }
}

Upvotes: 0

Nipuna Jayawardana
Nipuna Jayawardana

Reputation: 557

this line const { protocol } = new URL(website); will throw an error if the website parameter is not a valid URL. you could put validation to check if the parameter is a valid URL. it's better to have a try/ catch block to catch errors and return proper exceptions.

Upvotes: 0

Jay McDoniel
Jay McDoniel

Reputation: 70131

Your issue is that the new URL() call is throwing an exception. You can wrap that in a try/catch block to transform it to the proper BadRequestException you are wanting to throw. Otherwise, I'd probably just use a simple regex /https?:\/\//.test(website) to validate that the passed website is indeed an HTTP or HTTPS website.

Upvotes: 0

Related Questions