Tip Güvenli URL Kısaltıcı Geliştirme: NestJS ve TypeScript Rehberi 🔗
Bu rehberde, NestJS’in modüler yapısını kullanarak tip güvenli bir URL kısaltma servisini sıfırdan geliştireceksiniz.
Hem backend mantığını hem de veri doğrulama sürecini adım adım öğreneceksiniz.
🧠 Bu Rehberde Ne Öğreneceksiniz?
- NestJS CLI ile yeni bir proje oluşturmayı,
- TypeORM + SQLite ile veritabanı bağlantısı kurmayı,
nanoidile benzersiz kısa kodlar üretmeyi,class-validatorile veri doğrulamayı,- Denetleyici (Controller) ve Servis (Service) yapısını uygulamayı,
- Testler ile kısaltma ve yönlendirme mantığını doğrulamayı öğreneceksiniz.
1️⃣ Geliştirme Ortamını Hazırlama
Adım 1.1 — NestJS CLI ve Proje Kurulumu
NestJS CLI’ı küresel olarak kurun:
npm install -g @nestjs/cli
Bu komut, NestJS komut satırı aracını sisteminize yükler.
Yeni proje oluşturun (örnek ad: rabisu-link-kisaltici):
nest new rabisu-link-kisaltici
cd rabisu-link-kisaltici
NestJS gerekli iskeleti oluşturacak ve paket yöneticisini (npm) seçecektir.
Adım 1.2 — Gerekli Bağımlılıkların Kurulumu
Veritabanı ve doğrulama için gerekli tüm paketleri yükleyin:
npm install @nestjs/typeorm typeorm sqlite3
npm install class-validator class-transformer nanoid@^3.0.0
class-validator gelen veriyi doğrular, nanoid benzersiz kısa kodlar üretir, sqlite3 ise basit bir yerel veritabanı sağlar.
Adım 1.3 — Modül ve Servis Dosyalarını Oluşturma
NestJS CLI ile temel modül, servis ve kontrol dosyalarını oluşturun:
nest generate module url
nest generate service url --no-spec
nest generate controller url --no-spec
Bu komutlar sırasıyla url.module.ts, url.service.ts ve url.controller.ts dosyalarını oluşturur.
2️⃣ Veritabanı Bağlantısı ve Varlık (Entity) Tanımlama
Adım 2.1 — URL Varlığını Oluşturma
nano src/url/url.entity.ts
Aşağıdaki kodu ekleyin:
import { Entity, Column, PrimaryGeneratedColumn } from 'typeorm';
@Entity()
export class Url {
@PrimaryGeneratedColumn()
id: number;
@Column()
urlCode: string; // nanoid tarafından üretilen benzersiz kod
@Column()
longUrl: string; // Orijinal uzun URL
@Column()
shortUrl: string; // Kısaltılmış URL
}
Bu model, URL verilerinin veritabanında nasıl saklanacağını tanımlar.
Adım 2.2 — Veritabanı Bağlantısını Yapılandırma
nano src/app.module.ts
Aşağıdaki kodu ekleyin:
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { Url } from './url/url.entity';
import { UrlModule } from './url/url.module';
@Module({
imports: [
TypeOrmModule.forRoot({
type: 'sqlite',
database: 'link_kisaltici.sqlite',
entities: [Url],
synchronize: true, // Geliştirmede aktif, üretimde kapalı olmalı
}),
UrlModule,
],
})
export class AppModule {}
synchronize: true veritabanı tablosunu otomatik günceller. Üretim ortamında false olmalıdır.
Adım 2.3 — Modüle Depo (Repository) Erişimi Ekleme
nano src/url/url.module.ts
import { Module } from '@nestjs/common';
import { UrlService } from './url.service';
import { UrlController } from './url.controller';
import { TypeOrmModule } from '@nestjs/typeorm';
import { Url } from './url.entity';
@Module({
imports: [TypeOrmModule.forFeature([Url])],
providers: [UrlService],
controllers: [UrlController],
})
export class UrlModule {}
forFeature() metodu, sadece bu modül için Url deposuna erişim sağlar.
3️⃣ Servis (Service) Mantığını Uygulama
Adım 3.1 — Veri Transfer Nesnesi (DTO) ve Doğrulama
mkdir src/url/dtos
nano src/url/dtos/url.dto.ts
import { IsString, IsNotEmpty } from 'class-validator';
export class ShortenURLDto {
@IsString()
@IsNotEmpty()
longUrl: string; // Zorunlu alan
}
Ana uygulama dosyasında global doğrulama borusu ekleyin:
nano src/main.ts
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { ValidationPipe } from '@nestjs/common';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
app.useGlobalPipes(new ValidationPipe({ whitelist: true }));
await app.listen(3000);
}
bootstrap();
Bu yapı, tüm gelen verilerin DTO kurallarına uygunluğunu otomatik kontrol eder.
Adım 3.2 — Servise Repository Erişimi Sağlama
nano src/url/url.service.ts
import {
BadRequestException,
Injectable,
NotFoundException,
UnprocessableEntityException,
} from '@nestjs/common';
import { Repository } from 'typeorm';
import { InjectRepository } from '@nestjs/typeorm';
import { Url } from './url.entity';
import { ShortenURLDto } from './dtos/url.dto';
import { nanoid } from 'nanoid';
import { isURL } from 'class-validator';
@Injectable()
export class UrlService {
constructor(
@InjectRepository(Url)
private repo: Repository<Url>,
) {}
}
InjectRepository sayesinde TypeORM deposuna erişim sağlanır.
Adım 3.3 — Kısaltma Mantığı (shortenUrl)
async shortenUrl(url: ShortenURLDto): Promise<string> {
const { longUrl } = url;
if (!isURL(longUrl)) {
throw new BadRequestException('Lütfen geçerli bir URL girin');
}
let existing = await this.repo.findOneBy({ longUrl });
if (existing) return existing.shortUrl;
const urlCode = nanoid(10);
const baseURL = 'http://localhost:3000';
const shortUrl = `${baseURL}/${urlCode}`;
try {
const newUrl = this.repo.create({ urlCode, longUrl, shortUrl });
await this.repo.save(newUrl);
return newUrl.shortUrl;
} catch {
throw new UnprocessableEntityException('Sunucu hatası oluştu');
}
}
Aynı URL tekrar kısaltılırsa, sistem önceki kaydı döndürerek verimliliği artırır.
Adım 3.4 — Yönlendirme Mantığı (redirect)
async redirect(urlCode: string) {
const url = await this.repo.findOneBy({ urlCode });
if (url) return url;
throw new NotFoundException('Kaynak bulunamadı');
}
Bu metot, kısa kodu bulur ve orijinal URL’ye yönlendirme işlemini sağlar.
4️⃣ Denetleyici (Controller) Rotalarını Tanımlama
nano src/url/url.controller.ts
import {
Body,
Controller,
Get,
Param,
Post,
Res,
} from '@nestjs/common';
import { UrlService } from './url.service';
import { ShortenURLDto } from './dtos/url.dto';
import { Response } from 'express';
@Controller()
export class UrlController {
constructor(private service: UrlService) {}
@Post('shorten')
shortenUrl(@Body() url: ShortenURLDto) {
return this.service.shortenUrl(url);
}
@Get(':code')
async redirect(@Res() res: Response, @Param('code') code: string) {
const urlEntity = await this.service.redirect(code);
return res.redirect(urlEntity.longUrl);
}
}
@Controller() parametresiz bırakılarak kök rota (/) dinlenir.
5️⃣ Test Etme
Uygulamayı başlatın:
npm run start
6️⃣ URL Kısaltma Testi
curl -X POST -H "Content-Type: application/json" \
-d '{"longUrl":"https://rabisu.cloud/uzun-ornek-link"}' \
http://localhost:3000/shorten
Bu komut uzun bir URL'yi kısaltır ve kısa bağlantıyı döndürür.
7️⃣ Yönlendirme Testi
curl -v http://localhost:3000/sOmEkOd
-v parametresi yönlendirme detaylarını (302 yanıt kodu) gösterir.
❓ Sıkça Sorulan Sorular (SSS)
- nanoid yerine kendi özel kodlarımı kullanabilir miyim?
Evet, ancak bu durumda customCode alanını POST isteğine ekleyip veritabanında benzersizlik kontrolü yapmanız gerekir.
- synchronize: true neden üretimde tehlikeli?
Bu ayar tabloyu her çalıştırmada senkronize eder ve yanlış değişikliklerde veri kaybı yaşanabilir.
@Controller('url')yerine neden@Controller()kullandık?
Çünkü kısaltılmış linklerin http://localhost:3000/kod şeklinde çalışması gerekir; url/kod yapısı amaca ters olur.
- DTO kullanımı neden önemli?
DTO’lar, gelen verinin tip ve biçim açısından güvenliğini sağlar. Hatalı veya eksik veri uygulamaya ulaşmadan engellenir.
🏁 Sonuç
Bu rehberde, NestJS ve TypeScript kullanarak tam tip güvenli bir URL Kısaltıcı uygulaması geliştirdiniz. Veri doğrulama, servis mantığı ve yönlendirme süreçlerini uçtan uca öğrendiniz.
💡 Projenizi Rabisu Bulut altyapısında dağıtarak, yüksek ölçeklenebilirlik ve güvenlik avantajı elde edebilirsiniz. Rabisu Bulut platformunda hemen deneyin.