From b48f806da47de59d237838aa2a3d5568c3081cfe Mon Sep 17 00:00:00 2001 From: Kfir Dayan Date: Sun, 21 Jan 2024 11:10:22 +0200 Subject: [PATCH] adding routes and service logic to url-shortener --- package-lock.json | 24 ++++++++++++++++- package.json | 4 ++- src/app.controller.ts | 7 +---- src/app.module.ts | 2 -- src/app.service.ts | 8 ------ src/url-shortener/url-shortener.controller.ts | 27 ++++++++++++++++--- src/url-shortener/url-shortener.service.ts | 18 ++++++++++++- 7 files changed, 68 insertions(+), 22 deletions(-) delete mode 100644 src/app.service.ts diff --git a/package-lock.json b/package-lock.json index d66afb8..78b4320 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,7 +13,8 @@ "@nestjs/core": "^10.0.0", "@nestjs/platform-express": "^10.0.0", "reflect-metadata": "^0.1.13", - "rxjs": "^7.8.1" + "rxjs": "^7.8.1", + "shortid": "^2.2.16" }, "devDependencies": { "@nestjs/cli": "^10.0.0", @@ -22,6 +23,7 @@ "@types/express": "^4.17.17", "@types/jest": "^29.5.2", "@types/node": "^20.3.1", + "@types/shortid": "^0.0.32", "@types/supertest": "^2.0.12", "@typescript-eslint/eslint-plugin": "^5.59.11", "@typescript-eslint/parser": "^5.59.11", @@ -2122,6 +2124,12 @@ "@types/node": "*" } }, + "node_modules/@types/shortid": { + "version": "0.0.32", + "resolved": "https://registry.npmjs.org/@types/shortid/-/shortid-0.0.32.tgz", + "integrity": "sha512-LwWF89yy6Ol8abraYbVedIKzMlgJCTx8zm40yx9t0ZPOJaVR0OmSO4zRRAKfyOJtCwZrEBmhueZX8OiNbQydYw==", + "dev": true + }, "node_modules/@types/stack-utils": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.3.tgz", @@ -6266,6 +6274,11 @@ "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", "dev": true }, + "node_modules/nanoid": { + "version": "2.1.11", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-2.1.11.tgz", + "integrity": "sha512-s/snB+WGm6uwi0WjsZdaVcuf3KJXlfGl2LcxgwkEwJF0D/BWzVWAZW/XY4bFaiR7s0Jk3FPvlnepg1H1b1UwlA==" + }, "node_modules/natural-compare": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", @@ -7425,6 +7438,15 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/shortid": { + "version": "2.2.16", + "resolved": "https://registry.npmjs.org/shortid/-/shortid-2.2.16.tgz", + "integrity": "sha512-Ugt+GIZqvGXCIItnsL+lvFJOiN7RYqlGy7QE41O3YC1xbNSeDGIRO7xg2JJXIAj1cAGnOeC1r7/T9pgrtQbv4g==", + "deprecated": "Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.", + "dependencies": { + "nanoid": "^2.1.0" + } + }, "node_modules/side-channel": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", diff --git a/package.json b/package.json index 54631b3..9b8b700 100644 --- a/package.json +++ b/package.json @@ -24,7 +24,8 @@ "@nestjs/core": "^10.0.0", "@nestjs/platform-express": "^10.0.0", "reflect-metadata": "^0.1.13", - "rxjs": "^7.8.1" + "rxjs": "^7.8.1", + "shortid": "^2.2.16" }, "devDependencies": { "@nestjs/cli": "^10.0.0", @@ -33,6 +34,7 @@ "@types/express": "^4.17.17", "@types/jest": "^29.5.2", "@types/node": "^20.3.1", + "@types/shortid": "^0.0.32", "@types/supertest": "^2.0.12", "@typescript-eslint/eslint-plugin": "^5.59.11", "@typescript-eslint/parser": "^5.59.11", diff --git a/src/app.controller.ts b/src/app.controller.ts index cce879e..20710aa 100644 --- a/src/app.controller.ts +++ b/src/app.controller.ts @@ -1,12 +1,7 @@ import { Controller, Get } from '@nestjs/common'; -import { AppService } from './app.service'; @Controller() export class AppController { - constructor(private readonly appService: AppService) {} + constructor() {} - @Get() - getHello(): string { - return this.appService.getHello(); - } } diff --git a/src/app.module.ts b/src/app.module.ts index b4f1518..2499576 100644 --- a/src/app.module.ts +++ b/src/app.module.ts @@ -1,11 +1,9 @@ import { Module } from '@nestjs/common'; import { AppController } from './app.controller'; -import { AppService } from './app.service'; import { UrlShortenerModule } from './url-shortener/url-shortener.module'; @Module({ imports: [UrlShortenerModule], controllers: [AppController], - providers: [AppService], }) export class AppModule {} diff --git a/src/app.service.ts b/src/app.service.ts deleted file mode 100644 index 927d7cc..0000000 --- a/src/app.service.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { Injectable } from '@nestjs/common'; - -@Injectable() -export class AppService { - getHello(): string { - return 'Hello World!'; - } -} diff --git a/src/url-shortener/url-shortener.controller.ts b/src/url-shortener/url-shortener.controller.ts index 0dc7d75..689d03c 100644 --- a/src/url-shortener/url-shortener.controller.ts +++ b/src/url-shortener/url-shortener.controller.ts @@ -1,6 +1,27 @@ -import { Controller } from '@nestjs/common'; +import { Controller, Post, Body, Get, Param, Redirect, HttpException, HttpStatus } from '@nestjs/common'; +import { UrlShortenerService } from './url-shortener.service'; @Controller('url-shortener') export class UrlShortenerController { - -} + constructor(private readonly urlShortenerService: UrlShortenerService) {} + + @Post('shorten') + shortenUrl(@Body('url') url: string): { shortUrl: string } { + // example route http://localhost:3000/url-shortener/shorten POST body { url: 'https://www.google.com' } + if (!url) { + throw new HttpException('URL is required', HttpStatus.BAD_REQUEST); + } + const shortUrl = this.urlShortenerService.generateShortUrl(url); + return { shortUrl }; + } + + @Get(':shortUrl') + @Redirect() + async resolveShortUrl(@Param('shortUrl') shortUrl: string) { + const originalUrl = this.urlShortenerService.getOriginalUrl(shortUrl); + if (!originalUrl) { + throw new HttpException('URL not found!', HttpStatus.NOT_FOUND); + } + return { url: originalUrl }; + } +} \ No newline at end of file diff --git a/src/url-shortener/url-shortener.service.ts b/src/url-shortener/url-shortener.service.ts index 134f743..01d30fc 100644 --- a/src/url-shortener/url-shortener.service.ts +++ b/src/url-shortener/url-shortener.service.ts @@ -1,4 +1,20 @@ import { Injectable } from '@nestjs/common'; +import * as shortid from 'shortid'; @Injectable() -export class UrlShortenerService {} +export class UrlShortenerService { + private urlMap = new Map(); + + generateShortUrl(originalUrl: string): string { + if(!originalUrl) { + throw new Error('URL is required'); + } + let shortUrl = shortid.generate(); + this.urlMap.set(shortUrl, originalUrl); + return shortUrl + } + + getOriginalUrl(shortUrl: string): string | undefined { + return this.urlMap.get(shortUrl); + } +} \ No newline at end of file