How to Bulk Redirect URLs in NestJS

Updated: December 31, 2023 By: Guest Contributor Post a comment

Introduction

Handling bulk URL redirects efficiently can be essential for both SEO and user experience when restructuring websites. This tutorial walks you through setting up bulk redirects in a NestJS application using modern TypeScript syntax.

Prerequisites

  • Basic knowledge of TypeScript and NestJS
  • NestJS CLI installed and ready
  • A new or existing NestJS project

Creating a Redirection Module

To get started, we’ll create a dedicated module for handling redirects:

$ nest generate module redirects

Implementing a Simple Redirect

In your redirects module, set up a simple redirect with the controller and a predefined list of URL mappings.

import { Controller, Get, Redirect, Req } from '@nestjs/common';

@Controller('*') // Catch-all route
export class RedirectsController {
  private readonly urlMap = new Map<string, string>([
    ['/old-path', '/new-path'],
    ['/previous-page', '/current-page'],
    // add more mappings as needed
  ]);

  @Get()
  @Redirect()
  handleRedirect(@Req() req): any {
    const targetUrl = this.urlMap.get(req.path);
    if (targetUrl) {
      return { url: targetUrl, statusCode: 301 };
    }
    // Handle case when no redirect is found (optional)
    // e.g., redirect to a 404 page or a default route
  }
}

Advanced Bulk Redirect Management

For managing a large number of redirects, store them in a data source such as a file or a database. Here’s how to fetch redirect mappings from a JSON file:

import { Injectable } from '@nestjs/common';
import * as redirectData from './redirects.json';

@Injectable()
export class RedirectsService {
  private readonly urlMap: Map<string, string>;

  constructor() {
    this.urlMap = new Map(Object.entries(redirectData));
  }

  getUrlMapping(path: string): string {
    return this.urlMap.get(path);
  }
}

In the ‘redirects.json’ file:

{
  "/very-old-url": "/new-sexy-url",
  "/old-product-page": "/new-product-page"
}

Now, wire this service with the redirects controller to handle the lookups dynamically:

import { Controller, Get, Redirect, Req, Inject } from '@nestjs/common';

@Controller('*')
export class RedirectsController {

  constructor(@Inject(RedirectsService) private redirectsService: RedirectsService) {}

  @Get()
  @Redirect()
  handleRedirect(@Req() req): any {
    const targetUrl = this.redirectsService.getUrlMapping(req.path);
    if (targetUrl) {
      return { url: targetUrl, statusCode: 301 };
    }
      // Handle no-redirect-found logic here
  }
}

Database-Driven Redirection

When redirects scale up, a database solution becomes essential. Integrate a database model and service to retrieve redirect mappings.

Create a redirect entity and a corresponding module and service to query the database:

// redirects.entity.ts
import { Entity, Column, PrimaryGeneratedColumn } from 'typeorm';

@Entity()
export class Redirect {
  @PrimaryGeneratedColumn()
  id: number;

  @Column()
  fromPath: string;

  @Column()
  toPath: string;
} // Implement the service and module using TypeORM repository

Then, modify the redirects service to use database fetching:

// ... other imports
import { RedirectRepository } from './redirect.repository';

// Inside the RedirectsService:

async getUrlMapping(path: string): Promise {
  const redirectEntity =  await this.redirectRepository.findOne({ fromPath: path });
  return redirectEntity?.toPath;
}

And update the controller:

import { Controller, Get, Redirect, Req, Inject } from '@nestjs/common';

// ... other imports

@Controller('*')
export class RedirectsController {

  // ...constructor and other methods

  @Get()
  @Redirect()
  async handleRedirect(@Req() req): Promise {
    const targetUrl = await this.redirectsService.getUrlMapping(req.path);
    if (targetUrl) {
      return { url: targetUrl, statusCode: 301 };
    }
      // Handle no-redirect-found logic here
  }
}

Handling Wildcard and Regex Patterns

For complex matching like wildcards or regular expressions, enhance your service method:

async getUrlMapping(path: string): Promise {
  // Check for exact matches first
  let redirectEntity = await this.redirectRepository.findOne({ fromPath: path });
  if (!redirectEntity) {
    // Seek wildcard or regex matches next
    // Logic for handling wildcards or regex matches
  }
  return redirectEntity?.toPath;
}

You can extend this by implementing regex-based redirect matching inside the service method. It’s a more complex solution that depends on the number and type of redirects you need to handle.

Testing Your Redirects

Once the redirect system is in place, write unit and e2e tests to ensure it maintains the expected behavior as your application scales and changes.

Conclusion

Bulk URL redirect handling in NestJS can be streamlined for a variety of complexities. By implementing simple redirects and progressively enhancing the system with external data sources and database integration, you can maintain robust redirection that scales seamlessly with your application’s growth.