{"id":39483,"date":"2026-02-22T13:40:49","date_gmt":"2026-02-22T10:40:49","guid":{"rendered":"https:\/\/fatihsoysal.com\/blog\/?p=39483"},"modified":"2026-02-22T13:40:49","modified_gmt":"2026-02-22T10:40:49","slug":"nodejs-ve-nestjs-ile-tip-guvenli-type-safe-url-kisaltici-nasil-insa-edilir","status":"publish","type":"post","link":"https:\/\/fatihsoysal.com\/blog\/nodejs-ve-nestjs-ile-tip-guvenli-type-safe-url-kisaltici-nasil-insa-edilir\/","title":{"rendered":"NodeJS ve NestJS ile Tip-G\u00fcvenli (Type-Safe) URL K\u0131salt\u0131c\u0131 Nas\u0131l \u0130n\u015fa Edilir?"},"content":{"rendered":"<p><body><\/p>\n<h2>NodeJS ve NestJS ile Tip-G\u00fcvenli (Type-Safe) URL K\u0131salt\u0131c\u0131 Nas\u0131l \u0130n\u015fa Edilir?<\/h2>\n<h2>Giri\u015f<\/h2>\n<p>G\u00fcn\u00fcm\u00fcz\u00fcn dijital d\u00fcnyas\u0131nda, uzun ve karma\u015f\u0131k URL&#8217;ler hem estetik a\u00e7\u0131dan ho\u015f g\u00f6r\u00fcnmez hem de payla\u015f\u0131m, ileti\u015fim ve kullan\u0131labilirlik a\u00e7\u0131s\u0131ndan sorunlar yaratabilir. Bu sorunlara \u00e7\u00f6z\u00fcm olarak URL k\u0131salt\u0131c\u0131lar ortaya \u00e7\u0131km\u0131\u015ft\u0131r. Bir URL k\u0131salt\u0131c\u0131, uzun bir web adresini \u00e7ok daha k\u0131sa ve y\u00f6netilebilir bir forma d\u00f6n\u00fc\u015ft\u00fcren bir hizmettir. Bu makalede, modern bir web uygulamas\u0131 geli\u015ftirme yakla\u015f\u0131m\u0131yla, NodeJS ve NestJS \u00e7at\u0131s\u0131n\u0131 kullanarak tip-g\u00fcvenli bir URL k\u0131salt\u0131c\u0131y\u0131 ad\u0131m ad\u0131m nas\u0131l in\u015fa edece\u011fimizi detayl\u0131 bir \u015fekilde inceleyece\u011fiz.<\/p>\n<p>Tip-g\u00fcvenli\u011fi (type-safety), yaz\u0131l\u0131m geli\u015ftirmenin \u00f6nemli bir y\u00f6n\u00fcd\u00fcr. \u00d6zellikle b\u00fcy\u00fck ve karma\u015f\u0131k projelerde, veri t\u00fcrlerinin do\u011fru bir \u015fekilde y\u00f6netilmesi, hatalar\u0131 en aza indirmeye, kodun okunabilirli\u011fini art\u0131rmaya ve bak\u0131m\u0131n\u0131 kolayla\u015ft\u0131rmaya yard\u0131mc\u0131 olur. TypeScript&#8217;in g\u00fcc\u00fcn\u00fc arkas\u0131na alan NestJS, geli\u015ftiricilere bu tip-g\u00fcvenli ortam\u0131 sunarak, daha sa\u011flam ve \u00f6ng\u00f6r\u00fclebilir uygulamalar olu\u015fturma imkan\u0131 tan\u0131r. NodeJS&#8217;in asenkron yap\u0131s\u0131 ve NestJS&#8217;in mod\u00fcler, \u00f6l\u00e7eklenebilir mimarisi sayesinde, y\u00fcksek performansl\u0131 ve bak\u0131m\u0131 kolay bir URL k\u0131salt\u0131c\u0131 in\u015fa etmek m\u00fcmk\u00fcn olacakt\u0131r.<\/p>\n<p>Bu makalede, projemizin temel mimarisinden ba\u015flayarak, NestJS&#8217;in sundu\u011fu olanaklarla veritaban\u0131 entegrasyonu, veri aktar\u0131m nesneleri (DTO&#8217;lar) arac\u0131l\u0131\u011f\u0131yla tip-g\u00fcvenli validasyon, k\u0131saltma mant\u0131\u011f\u0131, API endpointlerinin olu\u015fturulmas\u0131 ve hata y\u00f6netimi gibi konular\u0131 ele alaca\u011f\u0131z. Son olarak, uygulamam\u0131z\u0131 daha da g\u00fc\u00e7l\u00fc hale getirecek geli\u015fmi\u015f \u00f6zellikler ve iyile\u015ftirmeler \u00fczerinde duraca\u011f\u0131z. Amac\u0131m\u0131z, sadece bir URL k\u0131salt\u0131c\u0131 in\u015fa etmek de\u011fil, ayn\u0131 zamanda modern web geli\u015ftirme pratiklerini ve tip-g\u00fcvenli\u011fin faydalar\u0131n\u0131 somut bir \u00f6rnek \u00fczerinden g\u00f6stermektir.<\/p>\n<h2>Temeller: URL K\u0131salt\u0131c\u0131 Mimarisi<\/h2>\n<p>Bir URL k\u0131salt\u0131c\u0131n\u0131n temel i\u015flevleri olduk\u00e7a basittir: uzun bir URL&#8217;i al\u0131r, benzersiz k\u0131sa bir kod \u00fcretir ve bu ikisini birbiriyle ili\u015fkilendirerek saklar. Kullan\u0131c\u0131 k\u0131sa URL&#8217;e eri\u015fti\u011finde, sistem orijinal URL&#8217;i bulur ve kullan\u0131c\u0131y\u0131 oraya y\u00f6nlendirir. Bu basit i\u015f ak\u0131\u015f\u0131n\u0131 desteklemek i\u00e7in belirli bile\u015fenlere ihtiyac\u0131m\u0131z var:<\/p>\n<h3>K\u0131saltma Mekanizmas\u0131<\/h3>\n<p>Uzun URL&#8217;i benzersiz bir k\u0131sa koda d\u00f6n\u00fc\u015ft\u00fcren algoritma. Bu kod genellikle rastgele karakterlerden olu\u015fur veya orijinal URL&#8217;in bir hash&#8217;i olabilir. Kodun benzersizli\u011fi kritik \u00f6neme sahiptir.<\/p>\n<h3>Veritaban\u0131<\/h3>\n<p>Orijinal URL&#8217;ler ile bunlara kar\u015f\u0131l\u0131k gelen k\u0131sa kodlar\u0131n depoland\u0131\u011f\u0131 yer. \u0130li\u015fkisel (PostgreSQL, MySQL) veya NoSQL (MongoDB, Redis) veritabanlar\u0131 kullan\u0131labilir. Veritaban\u0131, k\u0131sa kodlar\u0131n benzersizli\u011fini sa\u011flamal\u0131 ve h\u0131zl\u0131 okuma\/yazma i\u015flemleri sunmal\u0131d\u0131r.<\/p>\n<h3>API Endpointleri<\/h3>\n<p>Kullan\u0131c\u0131lar\u0131n URL k\u0131saltma ve y\u00f6nlendirme i\u015flemlerini ger\u00e7ekle\u015ftirebilece\u011fi aray\u00fczler. Genellikle bir <code>POST<\/code> endpointi yeni bir URL k\u0131saltmak i\u00e7in ve bir <code>GET<\/code> endpointi k\u0131sa URL&#8217;leri orijinal adreslerine y\u00f6nlendirmek i\u00e7in kullan\u0131l\u0131r.<\/p>\n<h3>Y\u00f6nlendirme Mant\u0131\u011f\u0131<\/h3>\n<p>K\u0131sa URL&#8217;e yap\u0131lan bir istek geldi\u011finde, veritaban\u0131ndan orijinal URL&#8217;i bulan ve kullan\u0131c\u0131y\u0131 bu adrese y\u00f6nlendiren sunucu taraf\u0131 mant\u0131k. HTTP 301 (Kal\u0131c\u0131 Olarak Ta\u015f\u0131nd\u0131) veya 302 (Ge\u00e7ici Olarak Ta\u015f\u0131nd\u0131) durum kodlar\u0131 kullan\u0131l\u0131r.<\/p>\n<p>Bu mimariyi NestJS&#8217;in mod\u00fcler yap\u0131s\u0131yla birle\u015ftirdi\u011fimizde, her bile\u015feni ayr\u0131 bir mod\u00fcl, servis veya kontrol\u00f6r olarak tan\u0131mlayabilir, b\u00f6ylece kodun okunabilirli\u011fini, test edilebilirli\u011fini ve bak\u0131m\u0131n\u0131 kolayla\u015ft\u0131rabiliriz.<\/p>\n<h2>NestJS&#8217;e Giri\u015f ve Proje Kurulumu<\/h2>\n<p>NestJS, TypeScript deste\u011fiyle modern, \u00f6l\u00e7eklenebilir ve kurumsal d\u00fczeyde uygulamalar geli\u015ftirmek i\u00e7in tasarlanm\u0131\u015f, a\u015famal\u0131 (progressive) bir Node.js \u00e7at\u0131s\u0131d\u0131r. Geli\u015ftiricilere tan\u0131d\u0131k gelen Angular benzeri bir yap\u0131 sunarak, Dependency Injection (Ba\u011f\u0131ml\u0131l\u0131k Enjeksiyonu), mod\u00fclerlik, dekorat\u00f6rler ve g\u00fc\u00e7l\u00fc bir CLI (Command Line Interface) ile birlikte gelir. TypeScript&#8217;in statik tip denetimi, NestJS&#8217;in tip-g\u00fcvenli bir ortam sunmas\u0131n\u0131n temelini olu\u015fturur.<\/p>\n<h3>Proje Olu\u015fturma<\/h3>\n<p>\u0130lk ad\u0131m olarak, NestJS CLI&#8217;yi kurmam\u0131z ve yeni bir proje olu\u015fturmam\u0131z gerekiyor.<\/p>\n<pre><code class=\"language-bash\">npm install -g @nestjs\/cli\nnest new url-shortener-app\ncd url-shortener-app<\/code><\/pre>\n<p>Bu komutlar, temel bir NestJS projesi olu\u015fturacak ve gerekli ba\u011f\u0131ml\u0131l\u0131klar\u0131 y\u00fckleyecektir. Proje yap\u0131s\u0131, <code>src<\/code> klas\u00f6r\u00fc alt\u0131nda <code>app.module.ts<\/code>, <code>app.controller.ts<\/code> ve <code>app.service.ts<\/code> gibi dosyalar\u0131 i\u00e7erir.<\/p>\n<h3>Gerekli Ba\u011f\u0131ml\u0131l\u0131klar<\/h3>\n<p>Projemiz i\u00e7in veritaban\u0131 etkile\u015fimi, veri validasyonu ve di\u011fer i\u015flevler i\u00e7in ek ba\u011f\u0131ml\u0131l\u0131klara ihtiyac\u0131m\u0131z olacak.<\/p>\n<pre><code class=\"language-bash\">npm install @nestjs\/typeorm typeorm pg class-validator class-transformer @nestjs\/config\nnpm install --save-dev @types\/express<\/code><\/pre>\n<p>*   <code>@nestjs\/typeorm<\/code>: NestJS ile TypeORM entegrasyonu sa\u011flar.<br \/>\n*   <code>typeorm<\/code>: NodeJS i\u00e7in g\u00fc\u00e7l\u00fc bir ORM (Object-Relational Mapper).<br \/>\n*   <code>pg<\/code>: PostgreSQL veritaban\u0131 s\u00fcr\u00fcc\u00fcs\u00fc. (E\u011fer MongoDB kullanacaksan\u0131z <code>mongoose<\/code> ve <code>@nestjs\/mongoose<\/code> kurmal\u0131s\u0131n\u0131z.)<br \/>\n*   <code>class-validator<\/code>: Gelen verileri do\u011frulamak i\u00e7in dekorat\u00f6r tabanl\u0131 validasyon sa\u011flar.<br \/>\n*   <code>class-transformer<\/code>: S\u0131n\u0131f \u00f6rneklerini d\u00fcz JavaScript nesnelerine veya tam tersine d\u00f6n\u00fc\u015ft\u00fcrmek i\u00e7in kullan\u0131l\u0131r.<br \/>\n*   <code>@nestjs\/config<\/code>: Ortam de\u011fi\u015fkenlerini y\u00f6netmek i\u00e7in NestJS mod\u00fcl\u00fc.<br \/>\n*   <code>@types\/express<\/code>: Express.js i\u00e7in TypeScript tip tan\u0131mlar\u0131 (NestJS varsay\u0131lan olarak Express kullan\u0131r).<\/p>\n<p>Bu ba\u011f\u0131ml\u0131l\u0131klar, tip-g\u00fcvenli bir \u015fekilde veritaban\u0131 i\u015flemleri yapmam\u0131z\u0131 ve gelen istekleri do\u011frulamam\u0131z\u0131 sa\u011flayacak temel ara\u00e7lard\u0131r.<\/p>\n<h2>Veritaban\u0131 Se\u00e7imi ve Entegrasyonu<\/h2>\n<p>URL k\u0131salt\u0131c\u0131m\u0131z\u0131n kalbi, orijinal URL&#8217;leri ve k\u0131sa kodlar\u0131 depolayan veritaban\u0131d\u0131r. Bu makalede, ili\u015fkisel bir veritaban\u0131 olan PostgreSQL&#8217;i ve NestJS ile sorunsuz bir \u015fekilde \u00e7al\u0131\u015fan TypeORM&#8217;i kullanaca\u011f\u0131z. TypeORM, veritaban\u0131 \u015femam\u0131z\u0131 TypeScript s\u0131n\u0131flar\u0131 (Entity&#8217;ler) arac\u0131l\u0131\u011f\u0131yla tan\u0131mlamam\u0131za olanak tan\u0131r, bu da tip-g\u00fcvenli\u011fini en \u00fcst d\u00fczeye \u00e7\u0131kar\u0131r.<\/p>\n<h3>TypeORM ve PostgreSQL Kurulumu<\/h3>\n<p>Yukar\u0131da belirtilen ba\u011f\u0131ml\u0131l\u0131klar\u0131 y\u00fcklediyseniz, art\u0131k TypeORM&#8217;i NestJS uygulamam\u0131za entegre edebiliriz.<\/p>\n<h3>Varl\u0131k (Entity) Tan\u0131m\u0131<\/h3>\n<p>Veritaban\u0131m\u0131zdaki <code>ShortUrl<\/code> tablosunu temsil edecek bir TypeScript s\u0131n\u0131f\u0131 olu\u015ftural\u0131m. Bu s\u0131n\u0131f, TypeORM dekorat\u00f6rleri ile veritaban\u0131 s\u00fctunlar\u0131n\u0131 ve k\u0131s\u0131tlamalar\u0131n\u0131 tan\u0131mlayacak.<\/p>\n<p><code>src\/url-shortener\/entities\/short-url.entity.ts<\/code>:<\/p>\n<pre><code class=\"language-typescript\">import { Entity, PrimaryGeneratedColumn, Column, CreateDateColumn, Index } from 'typeorm';\n\n@Entity('short_urls') \/\/ Veritaban\u0131ndaki tablo ad\u0131\nexport class ShortUrl {\n  @PrimaryGeneratedColumn('uuid') \/\/ Otomatik olarak UUID olu\u015fturur\n  id: string;\n\n  @Column({ type: 'text', unique: true, nullable: false })\n  originalUrl: string;\n\n  @Index({ unique: true }) \/\/ K\u0131sa kodun benzersizli\u011fini garanti eder\n  @Column({ type: 'varchar', length: 10, nullable: false })\n  shortCode: string;\n\n  @CreateDateColumn({ type: 'timestamp with time zone', default: () => 'CURRENT_TIMESTAMP' })\n  createdAt: Date;\n\n  @Column({ type: 'timestamp with time zone', nullable: true })\n  expiresAt: Date | null; \/\/ URL'nin ge\u00e7erlilik s\u00fcresi, iste\u011fe ba\u011fl\u0131\n}<\/code><\/pre>\n<p>Bu <code>ShortUrl<\/code> entity&#8217;si, her bir k\u0131salt\u0131lm\u0131\u015f URL i\u00e7in gerekli olan <code>id<\/code>, <code>originalUrl<\/code>, <code>shortCode<\/code>, <code>createdAt<\/code> ve <code>expiresAt<\/code> alanlar\u0131n\u0131 tan\u0131mlar. <code>Index({ unique: true })<\/code> dekorat\u00f6r\u00fc, <code>shortCode<\/code> alan\u0131n\u0131n veritaban\u0131nda benzersiz olmas\u0131n\u0131 sa\u011flar, bu da \u00e7ak\u0131\u015fmalar\u0131 \u00f6nlemek i\u00e7in kritik \u00f6neme sahiptir.<\/p>\n<h3>Veritaban\u0131 Ba\u011flant\u0131s\u0131n\u0131n Yap\u0131land\u0131r\u0131lmas\u0131<\/h3>\n<p><code>app.module.ts<\/code> dosyam\u0131z\u0131 TypeORM mod\u00fcl\u00fcn\u00fc i\u00e7erecek \u015fekilde g\u00fcncelleyelim. Ortam de\u011fi\u015fkenlerini y\u00f6netmek i\u00e7in <code>@nestjs\/config<\/code> mod\u00fcl\u00fcn\u00fc de kullanaca\u011f\u0131z.<\/p>\n<p><code>src\/app.module.ts<\/code>:<\/p>\n<pre><code class=\"language-typescript\">import { Module } from '@nestjs\/common';\nimport { TypeOrmModule } from '@nestjs\/typeorm';\nimport { ConfigModule, ConfigService } from '@nestjs\/config';\nimport { ShortUrl } from '.\/url-shortener\/entities\/short-url.entity';\nimport { UrlShortenerModule } from '.\/url-shortener\/url-shortener.module';\n\n@Module({\n  imports: [\n    ConfigModule.forRoot({\n      isGlobal: true, \/\/ ConfigModule'\u00fc global olarak eri\u015filebilir yapar\n    }),\n    TypeOrmModule.forRootAsync({\n      imports: [ConfigModule],\n      inject: [ConfigService],\n      useFactory: (configService: ConfigService) => ({\n        type: 'postgres',\n        host: configService.get<string>('DB_HOST'),\n        port: configService.get<number>('DB_PORT'),\n        username: configService.get<string>('DB_USERNAME'),\n        password: configService.get<string>('DB_PASSWORD'),\n        database: configService.get<string>('DB_DATABASE'),\n        entities: [ShortUrl], \/\/ Tan\u0131mlad\u0131\u011f\u0131m\u0131z entity'leri buraya ekliyoruz\n        synchronize: true, \/\/ Geli\u015ftirme ortam\u0131nda \u015fema senkronizasyonu i\u00e7in true, \u00fcretimde false olmal\u0131\n        logging: true, \/\/ SQL sorgular\u0131n\u0131 konsola yazd\u0131r\u0131r\n      }),\n    }),\n    UrlShortenerModule, \/\/ URL k\u0131salt\u0131c\u0131 mod\u00fcl\u00fcm\u00fcz\u00fc ekliyoruz\n  ],\n  controllers: [],\n  providers: [],\n})\nexport class AppModule {}<\/code><\/pre>\n<p><code>TypeOrmModule.forRootAsync<\/code> kullanarak, veritaban\u0131 yap\u0131land\u0131rmam\u0131z\u0131 ortam de\u011fi\u015fkenlerinden dinamik olarak alabiliriz. <code>synchronize: true<\/code> geli\u015ftirme a\u015famas\u0131nda entity&#8217;lerimizde yapt\u0131\u011f\u0131m\u0131z de\u011fi\u015fikliklerin veritaban\u0131 \u015femas\u0131n\u0131 otomatik olarak g\u00fcncellemesini sa\u011flar. Ancak, \u00fcretim ortam\u0131nda bu ayar\u0131n <code>false<\/code> olmas\u0131 ve veritaban\u0131 ge\u00e7i\u015fleri (migrations) kullan\u0131lmas\u0131 \u015fiddetle tavsiye edilir.<\/p>\n<p>Proje k\u00f6k dizininde bir <code>.env<\/code> dosyas\u0131 olu\u015fturarak veritaban\u0131 ba\u011flant\u0131 bilgilerini tan\u0131mlayal\u0131m:<\/p>\n<pre><code class=\"language-\">DB_HOST=localhost\nDB_PORT=5432\nDB_USERNAME=your_username\nDB_PASSWORD=your_password\nDB_DATABASE=url_shortener_db<\/code><\/pre>\n<p>Bu yap\u0131land\u0131rma ile NestJS uygulamam\u0131z ba\u015flat\u0131ld\u0131\u011f\u0131nda PostgreSQL veritaban\u0131na ba\u011flanacak ve <code>ShortUrl<\/code> entity&#8217;mizi kullanarak <code>short_urls<\/code> tablosunu otomatik olarak olu\u015fturacakt\u0131r.<\/p>\n<h2>Tip-G\u00fcvenli\u011fi \u0130\u00e7in DTO&#8217;lar ve Validasyon<\/h2>\n<p>Veri Aktar\u0131m Nesneleri (DTO&#8217;lar), a\u011f \u00fczerinden ta\u015f\u0131nacak verilerin yap\u0131s\u0131n\u0131 tan\u0131mlayan basit s\u0131n\u0131flard\u0131r. NestJS&#8217;te DTO&#8217;lar, gelen HTTP isteklerinin g\u00f6vdesini (body) veya sorgu parametrelerini tip-g\u00fcvenli bir \u015fekilde temsil etmek i\u00e7in kullan\u0131l\u0131r. <code>class-validator<\/code> ve <code>class-transformer<\/code> k\u00fct\u00fcphaneleriyle birlikte kullan\u0131ld\u0131\u011f\u0131nda, DTO&#8217;lar gelen verileri otomatik olarak do\u011frular ve d\u00f6n\u00fc\u015ft\u00fcr\u00fcr, b\u00f6ylece kontrol\u00f6rlerimizde manuel validasyon koduna olan ihtiyac\u0131 ortadan kald\u0131r\u0131r.<\/p>\n<h3>Neden DTO Kullanmal\u0131y\u0131z?<\/h3>\n<p>*   <strong>Tip-G\u00fcvenli\u011fi:<\/strong> Gelen verilerin beklenen tiplerde olmas\u0131n\u0131 garanti eder.<br \/>\n*   <strong>Validasyon:<\/strong> <code>@IsString()<\/code>, <code>@IsUrl()<\/code> gibi dekorat\u00f6rlerle kolayca validasyon kurallar\u0131 tan\u0131mlan\u0131r.<br \/>\n*   <strong>Kod Temizli\u011fi:<\/strong> Validasyon mant\u0131\u011f\u0131n\u0131 kontrol\u00f6rlerden ay\u0131r\u0131r.<br \/>\n*   <strong>Dok\u00fcmantasyon:<\/strong> API&#8217;nin bekledi\u011fi veri yap\u0131s\u0131n\u0131 a\u00e7\u0131k\u00e7a belirtir.<\/p>\n<h3><code>CreateShortUrlDto<\/code> Tan\u0131m\u0131<\/h3>\n<p>Yeni bir URL k\u0131saltma iste\u011fi i\u00e7in bir DTO olu\u015ftural\u0131m. Bu DTO, kullan\u0131c\u0131n\u0131n bize g\u00f6nderece\u011fi <code>originalUrl<\/code> ve iste\u011fe ba\u011fl\u0131 olarak <code>customShortCode<\/code> alanlar\u0131n\u0131 i\u00e7erecek.<\/p>\n<p><code>src\/url-shortener\/dto\/create-short-url.dto.ts<\/code>:<\/p>\n<pre><code class=\"language-typescript\">import { IsNotEmpty, IsUrl, IsOptional, IsString, MinLength, MaxLength } from 'class-validator';\n\nexport class CreateShortUrlDto {\n  @IsNotEmpty({ message: 'Orijinal URL bo\u015f olamaz.' })\n  @IsUrl({}, { message: 'Ge\u00e7erli bir URL giriniz.' })\n  originalUrl: string;\n\n  @IsOptional()\n  @IsString({ message: '\u00d6zel k\u0131sa kod bir metin olmal\u0131d\u0131r.' })\n  @MinLength(3, { message: '\u00d6zel k\u0131sa kod en az 3 karakter olmal\u0131d\u0131r.' })\n  @MaxLength(10, { message: '\u00d6zel k\u0131sa kod en fazla 10 karakter olabilir.' })\n  \/\/ Regex ile sadece alfanumerik karakterlere izin verilebilir\n  \/\/ @Matches(\/^[a-zA-Z0-9_-]+$\/, { message: '\u00d6zel k\u0131sa kod sadece alfanumerik karakterler, tire ve alt \u00e7izgi i\u00e7erebilir.' })\n  customShortCode?: string;\n}<\/code><\/pre>\n<p>Bu DTO&#8217;da, <code>originalUrl<\/code> alan\u0131n\u0131n bo\u015f olamayaca\u011f\u0131n\u0131 (<code>@IsNotEmpty<\/code>) ve ge\u00e7erli bir URL format\u0131nda olmas\u0131 gerekti\u011fini (<code>@IsUrl<\/code>) belirtiyoruz. <code>customShortCode<\/code> alan\u0131 ise iste\u011fe ba\u011fl\u0131d\u0131r (<code>@IsOptional<\/code>) ve belirli uzunluk k\u0131s\u0131tlamalar\u0131na sahiptir.<\/p>\n<h3><code>ValidationPipe<\/code> Kullan\u0131m\u0131<\/h3>\n<p>NestJS, <code>ValidationPipe<\/code> arac\u0131l\u0131\u011f\u0131yla DTO&#8217;lar\u0131m\u0131z\u0131n otomatik olarak do\u011frulanmas\u0131n\u0131 sa\u011flar. Bu boruyu global olarak veya belirli bir kontrol\u00f6r\/metot d\u00fczeyinde uygulayabiliriz.<\/p>\n<p><code>src\/main.ts<\/code> dosyas\u0131nda global olarak yap\u0131land\u0131rma:<\/p>\n<pre><code class=\"language-typescript\">import { NestFactory } from '@nestjs\/core';\nimport { AppModule } from '.\/app.module';\nimport { ValidationPipe } from '@nestjs\/common';\n\nasync function bootstrap() {\n  const app = await NestFactory.create(AppModule);\n  app.useGlobalPipes(new ValidationPipe({\n    whitelist: true, \/\/ DTO'da tan\u0131mlanmayan alanlar\u0131 otomatik olarak kald\u0131r\u0131r\n    forbidNonWhitelisted: true, \/\/ DTO'da tan\u0131mlanmayan alanlar varsa hata f\u0131rlat\u0131r\n    transform: true, \/\/ Gelen veriyi DTO s\u0131n\u0131f\u0131na d\u00f6n\u00fc\u015ft\u00fcr\u00fcr\n  }));\n  await app.listen(3000);\n}\nbootstrap();<\/code><\/pre>\n<p><code>whitelist: true<\/code> ve <code>forbidNonWhitelisted: true<\/code> se\u00e7enekleri, g\u00fcvenlik ve veri b\u00fct\u00fcnl\u00fc\u011f\u00fc a\u00e7\u0131s\u0131ndan \u00f6nemlidir. Bunlar, iste\u011fe DTO&#8217;da tan\u0131mlanmayan fazladan alanlar g\u00f6nderildi\u011finde bu alanlar\u0131n g\u00f6z ard\u0131 edilmesini veya hata f\u0131rlat\u0131lmas\u0131n\u0131 sa\u011flar. <code>transform: true<\/code> ise, gelen JSON verilerini otomatik olarak <code>CreateShortUrlDto<\/code> s\u0131n\u0131f\u0131n\u0131n bir \u00f6rne\u011fine d\u00f6n\u00fc\u015ft\u00fcr\u00fcr, b\u00f6ylece tip-g\u00fcvenli bir \u015fekilde eri\u015febiliriz.<\/p>\n<h2>K\u0131saltma Mant\u0131\u011f\u0131: Servis Katman\u0131<\/h2>\n<p>NestJS mimarisinde i\u015f mant\u0131\u011f\u0131 genellikle servis katman\u0131nda bulunur. Bu, kontrol\u00f6rlerin yaln\u0131zca HTTP isteklerini y\u00f6netmesini, servislerin ise veritaban\u0131 i\u015flemleri, harici API \u00e7a\u011fr\u0131lar\u0131 ve karma\u015f\u0131k algoritmalar gibi i\u015f s\u00fcre\u00e7lerini y\u00fcr\u00fctmesini sa\u011flar. URL k\u0131saltma ve orijinal URL&#8217;i bulma mant\u0131\u011f\u0131n\u0131 bir <code>UrlShortenerService<\/code> i\u00e7inde uygulayaca\u011f\u0131z.<\/p>\n<h3><code>UrlShortenerModule<\/code> Olu\u015fturma<\/h3>\n<p>URL k\u0131salt\u0131c\u0131ya \u00f6zg\u00fc t\u00fcm bile\u015fenleri (servis, kontrol\u00f6r, entity) bir mod\u00fcl alt\u0131nda toplamak, uygulaman\u0131n mod\u00fclerli\u011fini ve d\u00fczenini art\u0131r\u0131r.<\/p>\n<pre><code class=\"language-bash\">nest generate module url-shortener\nnest generate service url-shortener\nnest generate controller url-shortener<\/code><\/pre>\n<p><code>src\/url-shortener\/url-shortener.module.ts<\/code>:<\/p>\n<pre><code class=\"language-typescript\">import { Module } from '@nestjs\/common';\nimport { TypeOrmModule } from '@nestjs\/typeorm';\nimport { UrlShortenerService } from '.\/url-shortener.service';\nimport { UrlShortenerController } from '.\/url-shortener.controller';\nimport { ShortUrl } from '.\/entities\/short-url.entity';\n\n@Module({\n  imports: [TypeOrmModule.forFeature([ShortUrl])], \/\/ Bu mod\u00fclde ShortUrl entity'sini kullanaca\u011f\u0131m\u0131z\u0131 belirtiyoruz\n  providers: [UrlShortenerService],\n  controllers: [UrlShortenerController],\n  exports: [UrlShortenerService], \/\/ Di\u011fer mod\u00fcllerin bu servise eri\u015fmesini sa\u011flar\u0131z (e\u011fer gerekirse)\n})\nexport class UrlShortenerModule {}<\/code><\/pre>\n<h3>K\u0131saltma Kodu \u00dcretme Stratejileri<\/h3>\n<p>K\u0131sa kodun benzersiz ve k\u0131sa olmas\u0131 \u00f6nemlidir. \u0130\u015fte baz\u0131 stratejiler:<\/p>\n<p>1.  <strong>Rastgele String:<\/strong> Belirli bir karakter k\u00fcmesinden (\u00f6rne\u011fin, alfanumerik karakterler ve semboller) rastgele bir string olu\u015fturmak. \u00c7ak\u0131\u015fma olas\u0131l\u0131\u011f\u0131 d\u00fc\u015f\u00fckt\u00fcr ancak yine de veritaban\u0131nda kontrol etmek gerekir.<br \/>\n2.  <strong>Base62 D\u00f6n\u00fc\u015f\u00fcm\u00fc:<\/strong> Veritaban\u0131ndaki artan bir kimli\u011fi (ID) al\u0131p Base62 (0-9, a-z, A-Z) format\u0131na d\u00f6n\u00fc\u015ft\u00fcrmek. Bu, benzersizli\u011fi garanti eder ve daha k\u0131sa kodlar \u00fcretir. Ancak, ID&#8217;nin a\u00e7\u0131\u011fa \u00e7\u0131kmas\u0131 g\u00fcvenlik riski ta\u015f\u0131yabilir ve veritaban\u0131 ID&#8217;si olmadan \u00e7al\u0131\u015fmak zordur.<br \/>\n3.  <strong>Hash Fonksiyonlar\u0131:<\/strong> Orijinal URL&#8217;in bir hash&#8217;ini (MD5, SHA-256) almak ve ilk birka\u00e7 karakterini kullanmak. \u00c7ak\u0131\u015fma olas\u0131l\u0131\u011f\u0131 rastgele string&#8217;e g\u00f6re daha y\u00fcksektir ve hash&#8217;ler genellikle daha uzundur.<\/p>\n<p>Biz bu makalede, rastgele string \u00fcretme ve veritaban\u0131nda benzersizlik kontrol\u00fc yapma yakla\u015f\u0131m\u0131n\u0131 benimseyece\u011fiz, \u00e7\u00fcnk\u00fc bu basit ve etkilidir.<\/p>\n<p><code>src\/url-shortener\/url-shortener.service.ts<\/code>:<\/p>\n<pre><code class=\"language-typescript\">import { ConflictException, Injectable, NotFoundException } from '@nestjs\/common';\nimport { InjectRepository } from '@nestjs\/typeorm';\nimport { Repository } from 'typeorm';\nimport { ShortUrl } from '.\/entities\/short-url.entity';\nimport { CreateShortUrlDto } from '.\/dto\/create-short-url.dto';\nimport { nanoid } from 'nanoid'; \/\/ Benzersiz k\u0131sa kodlar olu\u015fturmak i\u00e7in nanoid kullanaca\u011f\u0131z\n\n@Injectable()\nexport class UrlShortenerService {\n  constructor(\n    @InjectRepository(ShortUrl)\n    private shortUrlRepository: Repository<ShortUrl>,\n  ) {}\n\n  private generateShortCode(): string {\n    \/\/ nanoid, k\u0131sa, benzersiz ve URL-safe ID'ler \u00fcretmek i\u00e7in idealdir.\n    \/\/ Varsay\u0131lan olarak 21 karakter \u00fcretir, biz 7-8 karakterle yetinebiliriz.\n    return nanoid(7); \n  }\n\n  async createShortUrl(createShortUrlDto: CreateShortUrlDto): Promise<ShortUrl> {\n    const { originalUrl, customShortCode } = createShortUrlDto;\n\n    \/\/ E\u011fer ayn\u0131 orijinal URL zaten k\u0131salt\u0131lm\u0131\u015fsa, mevcut k\u0131saltmay\u0131 d\u00f6nd\u00fcr\n    const existingShortUrl = await this.shortUrlRepository.findOne({ where: { originalUrl } });\n    if (existingShortUrl) {\n      return existingShortUrl;\n    }\n\n    let shortCode: string;\n    if (customShortCode) {\n      \/\/ E\u011fer \u00f6zel bir k\u0131sa kod belirtilmi\u015fse, benzersizli\u011fini kontrol et\n      const existingCustomShortCode = await this.shortUrlRepository.findOne({ where: { shortCode: customShortCode } });\n      if (existingCustomShortCode) {\n        throw new ConflictException('Bu \u00f6zel k\u0131sa kod zaten kullan\u0131l\u0131yor.');\n      }\n      shortCode = customShortCode;\n    } else {\n      \/\/ \u00d6zel k\u0131sa kod yoksa, rastgele bir tane olu\u015ftur ve benzersizli\u011fini garanti et\n      let isUnique = false;\n      while (!isUnique) {\n        shortCode = this.generateShortCode();\n        const found = await this.shortUrlRepository.findOne({ where: { shortCode } });\n        if (!found) {\n          isUnique = true;\n        }\n      }\n    }\n\n    const newShortUrl = this.shortUrlRepository.create({\n      originalUrl,\n      shortCode,\n      \/\/ expiresAt: new Date(Date.now() + 1000 <em> 60 <\/em> 60 <em> 24 <\/em> 30), \/\/ 30 g\u00fcn sonra sona ersin\n    });\n\n    await this.shortUrlRepository.save(newShortUrl);\n    return newShortUrl;\n  }\n\n  async getOriginalUrl(shortCode: string): Promise<string> {\n    const shortUrl = await this.shortUrlRepository.findOne({ where: { shortCode } });\n\n    if (!shortUrl) {\n      throw new NotFoundException('K\u0131salt\u0131lm\u0131\u015f URL bulunamad\u0131.');\n    }\n\n    \/\/ URL'nin s\u00fcresi dolmu\u015f mu kontrol\u00fc (iste\u011fe ba\u011fl\u0131)\n    if (shortUrl.expiresAt && shortUrl.expiresAt < new Date()) {\n      \/\/ URL'yi pasifize edebilir veya silebiliriz\n      \/\/ await this.shortUrlRepository.remove(shortUrl); \n      throw new NotFoundException('K\u0131salt\u0131lm\u0131\u015f URL s\u00fcresi dolmu\u015f.');\n    }\n\n    return shortUrl.originalUrl;\n  }\n}<\/code><\/pre>\n<p>Bu serviste <code>nanoid<\/code> k\u00fct\u00fcphanesini kullanarak k\u0131sa ve benzersiz kodlar \u00fcretiyoruz. <code>createShortUrl<\/code> metodunda, e\u011fer kullan\u0131c\u0131 \u00f6zel bir k\u0131sa kod belirtmi\u015fse, bunun zaten kullan\u0131l\u0131p kullan\u0131lmad\u0131\u011f\u0131n\u0131 kontrol ediyoruz. Aksi takdirde, rastgele bir kod \u00fcretiyor ve veritaban\u0131nda benzersizli\u011fini sa\u011fl\u0131yoruz. <code>getOriginalUrl<\/code> metodu ise, verilen k\u0131sa koda kar\u015f\u0131l\u0131k gelen orijinal URL'i bulur veya bir <code>NotFoundException<\/code> f\u0131rlat\u0131r.<\/p>\n<h2>API Katman\u0131: Controller<\/h2>\n<p>Kontrol\u00f6rler, gelen HTTP isteklerini i\u015fleyen ve uygun servis metotlar\u0131n\u0131 \u00e7a\u011f\u0131ran s\u0131n\u0131flard\u0131r. NestJS'te <code>@Controller()<\/code> dekorat\u00f6r\u00fc ile tan\u0131mlan\u0131rlar ve <code>@Get()<\/code>, <code>@Post()<\/code>, <code>@Put()<\/code>, <code>@Delete()<\/code> gibi HTTP metot dekorat\u00f6rleri ile belirli endpoint'leri y\u00f6netirler.<\/p>\n<p><code>src\/url-shortener\/url-shortener.controller.ts<\/code>:<\/p>\n<pre><code class=\"language-typescript\">import { Controller, Post, Body, Get, Param, Res, HttpStatus } from '@nestjs\/common';\nimport { UrlShortenerService } from '.\/url-shortener.service';\nimport { CreateShortUrlDto } from '.\/dto\/create-short-url.dto';\nimport { Response } from 'express'; \/\/ express'ten Response tipini i\u00e7e aktar\u0131yoruz\nimport { ConfigService } from '@nestjs\/config';\n\n\/\/ Yan\u0131t i\u00e7in tip-g\u00fcvenli bir aray\u00fcz tan\u0131mlayabiliriz\ninterface ShortUrlResponse {\n  originalUrl: string;\n  shortCode: string;\n  shortUrl: string;\n}\n\n@Controller() \/\/ K\u00f6k dizinde endpointleri tan\u0131mlayaca\u011f\u0131z\nexport class UrlShortenerController {\n  constructor(\n    private readonly urlShortenerService: UrlShortenerService,\n    private readonly configService: ConfigService,\n  ) {}\n\n  @Post('shorten')\n  async shortenUrl(@Body() createShortUrlDto: CreateShortUrlDto): Promise<ShortUrlResponse> {\n    const shortUrlEntity = await this.urlShortenerService.createShortUrl(createShortUrlDto);\n    const baseUrl = this.configService.get<string>('BASE_URL') || 'http:\/\/localhost:3000'; \/\/ Ortam de\u011fi\u015fkeninden BASE_URL al\n    const fullShortUrl = <code>${baseUrl}\/${shortUrlEntity.shortCode}<\/code>;\n\n    return {\n      originalUrl: shortUrlEntity.originalUrl,\n      shortCode: shortUrlEntity.shortCode,\n      shortUrl: fullShortUrl,\n    };\n  }\n\n  @Get(':shortCode')\n  async redirectToOriginalUrl(\n    @Param('shortCode') shortCode: string,\n    @Res() res: Response, \/\/ Express Response objesini do\u011frudan kullanmak i\u00e7in @Res() dekorat\u00f6r\u00fc\n  ): Promise<void> {\n    const originalUrl = await this.urlShortenerService.getOriginalUrl(shortCode);\n    res.redirect(HttpStatus.MOVED_PERMANENTLY, originalUrl); \/\/ HTTP 301 Kal\u0131c\u0131 Y\u00f6nlendirme\n  }\n}<\/code><\/pre>\n<p><code>POST \/shorten<\/code> endpoint'i, <code>CreateShortUrlDto<\/code> tipinde bir istek g\u00f6vdesi al\u0131r. <code>ValidationPipe<\/code> sayesinde, bu DTO otomatik olarak do\u011frulan\u0131r ve tip-g\u00fcvenli bir \u015fekilde <code>createShortUrlDto<\/code> de\u011fi\u015fkenine atan\u0131r. Servis \u00e7a\u011fr\u0131ld\u0131ktan sonra, k\u0131salt\u0131lm\u0131\u015f URL'i i\u00e7eren bir yan\u0131t d\u00f6nd\u00fcr\u00fcl\u00fcr. <code>BASE_URL<\/code> ortam de\u011fi\u015fkenini <code>.env<\/code> dosyan\u0131za eklemeyi unutmay\u0131n (\u00f6rn: <code>BASE_URL=http:\/\/localhost:3000<\/code>).<\/p>\n<p><code>GET \/:shortCode<\/code> endpoint'i, dinamik bir parametre olan <code>shortCode<\/code>'u al\u0131r. Bu kod kullan\u0131larak orijinal URL bulunur ve <code>res.redirect()<\/code> metodu ile kullan\u0131c\u0131 do\u011frudan orijinal URL'e y\u00f6nlendirilir. <code>HttpStatus.MOVED_PERMANENTLY<\/code> (301) SEO a\u00e7\u0131s\u0131ndan daha iyidir, \u00e7\u00fcnk\u00fc arama motorlar\u0131na bu k\u0131sa URL'in kal\u0131c\u0131 olarak orijinal URL'e ta\u015f\u0131nd\u0131\u011f\u0131n\u0131 bildirir.<\/p>\n<h2>Hata Y\u00f6netimi ve \u0130stisnalar<\/h2>\n<p>NestJS, uygulamalarda olu\u015fan hatalar\u0131 y\u00f6netmek i\u00e7in g\u00fc\u00e7l\u00fc bir mekanizma sunar. Standart HTTP istisnalar\u0131 (\u00f6rn. <code>NotFoundException<\/code>, <code>BadRequestException<\/code>, <code>ConflictException<\/code>) do\u011frudan NestJS'ten import edilebilir ve f\u0131rlat\u0131labilir. Bu istisnalar, otomatik olarak uygun HTTP durum kodlar\u0131 ve hata mesajlar\u0131yla JSON yan\u0131tlar\u0131na d\u00f6n\u00fc\u015ft\u00fcr\u00fcl\u00fcr.<\/p>\n<p>Yukar\u0131daki servis ve kontrol\u00f6r kodlar\u0131m\u0131zda <code>NotFoundException<\/code> ve <code>ConflictException<\/code> kulland\u0131k. \u00d6rne\u011fin:<\/p>\n<p>*   <code>throw new NotFoundException('K\u0131salt\u0131lm\u0131\u015f URL bulunamad\u0131.');<\/code><br \/>\n*   <code>throw new ConflictException('Bu \u00f6zel k\u0131sa kod zaten kullan\u0131l\u0131yor.');<\/code><\/p>\n<p>Bu, kullan\u0131c\u0131ya anla\u015f\u0131l\u0131r hata mesajlar\u0131 sunarken, geli\u015ftiricinin de sorunun kayna\u011f\u0131n\u0131 h\u0131zl\u0131ca tespit etmesine yard\u0131mc\u0131 olur. NestJS'in dahili hata y\u00f6netimi \u00e7o\u011fu senaryo i\u00e7in yeterli olsa da, daha karma\u015f\u0131k veya \u00f6zelle\u015ftirilmi\u015f hata yan\u0131tlar\u0131 i\u00e7in <code>ExceptionFilter<\/code>'lar olu\u015fturulabilir.<\/p>\n<h2>Geli\u015fmi\u015f \u00d6zellikler ve \u0130yile\u015ftirmeler<\/h2>\n<p>Temel bir URL k\u0131salt\u0131c\u0131 \u00e7al\u0131\u015f\u0131r durumda oldu\u011funa g\u00f6re, \u015fimdi uygulamam\u0131z\u0131 daha sa\u011flam, kullan\u0131\u015fl\u0131 ve \u00f6l\u00e7eklenebilir hale getirecek baz\u0131 geli\u015fmi\u015f \u00f6zellikler ve iyile\u015ftirmeler \u00fczerinde durabiliriz.<\/p>\n<h3>TTL (Time-To-Live) \/ S\u00fcre Sonu<\/h3>\n<p>Baz\u0131 URL'lerin belirli bir s\u00fcre sonra ge\u00e7erlili\u011fini yitirmesi istenebilir. <code>ShortUrl<\/code> entity'mizde zaten <code>expiresAt<\/code> alan\u0131 bulunmaktad\u0131r.<\/p>\n<p>*   <strong>Uygulama:<\/strong> <code>createShortUrl<\/code> metodunda, iste\u011fe ba\u011fl\u0131 olarak <code>expiresAt<\/code> alan\u0131n\u0131 ayarlayabiliriz (\u00f6rn: 30 g\u00fcn sonras\u0131).<br \/>\n*   <strong>Otomatik Silme\/Pasifle\u015ftirme:<\/strong> S\u00fcresi dolmu\u015f URL'leri periyodik olarak kontrol etmek ve silmek veya pasifle\u015ftirmek i\u00e7in bir cron job (zamanlanm\u0131\u015f g\u00f6rev) kullanabiliriz. NestJS'in <code>@nestjs\/schedule<\/code> mod\u00fcl\u00fc bu t\u00fcr g\u00f6revler i\u00e7in idealdir.<\/p>\n<pre><code class=\"language-bash\">npm install @nestjs\/schedule<\/code><\/pre>\n<p>Ve <code>app.module.ts<\/code>'e <code>ScheduleModule.forRoot()<\/code> ekleyip, servisimize <code>@Cron()<\/code> dekorat\u00f6rl\u00fc bir metot ekleyebiliriz.<\/p>\n<h3>Kullan\u0131c\u0131 Tan\u0131ml\u0131 K\u0131sa Kodlar<\/h3>\n<p><code>CreateShortUrlDto<\/code> i\u00e7inde <code>customShortCode<\/code> alan\u0131n\u0131 zaten ekledik. Servisimizde bu kodun benzersizli\u011fini kontrol ederek kullan\u0131c\u0131n\u0131n istedi\u011fi k\u0131sa kodu kullanmas\u0131na izin veriyoruz. Bu, markala\u015fma veya kolay hat\u0131rlanabilirlik i\u00e7in \u00f6nemlidir.<\/p>\n<h3>Analitik ve \u0130statistikler<\/h3>\n<p>K\u0131salt\u0131lm\u0131\u015f URL'lerin ne kadar t\u0131kland\u0131\u011f\u0131n\u0131, hangi co\u011frafyalardan eri\u015fildi\u011fini veya hangi zamanlarda daha pop\u00fcler oldu\u011funu takip etmek isteyebiliriz.<\/p>\n<p>*   <strong>Uygulama:<\/strong> <code>ShortUrl<\/code> entity'sine <code>clickCount: number<\/code> gibi bir alan ekleyebiliriz. <code>getOriginalUrl<\/code> metodunda her ba\u015far\u0131l\u0131 y\u00f6nlendirmede bu sayac\u0131 art\u0131rabiliriz.<br \/>\n*   <strong>Daha Detayl\u0131 Analitik:<\/strong> Her t\u0131klamada kullan\u0131c\u0131n\u0131n IP adresi, taray\u0131c\u0131 bilgisi, referans URL gibi verileri ayr\u0131 bir <code>ClickLog<\/code> entity'sinde saklayabiliriz. Bu, daha zengin istatistikler sunar.<\/p>\n<h3>Rate Limiting (\u0130stek S\u0131n\u0131rlama)<\/h3>\n<p>API'mizi k\u00f6t\u00fc niyetli kullan\u0131mlardan veya a\u015f\u0131r\u0131 y\u00fcklenmelerden korumak i\u00e7in istek s\u0131n\u0131rlamas\u0131 uygulamak \u00f6nemlidir.<\/p>\n<p>*   <strong>Uygulama:<\/strong> <code>@nestjs\/throttler<\/code> gibi bir k\u00fct\u00fcphane kullanarak belirli bir IP adresinden veya kullan\u0131c\u0131dan belirli bir zaman diliminde yap\u0131labilecek istek say\u0131s\u0131n\u0131 s\u0131n\u0131rlayabiliriz.<\/p>\n<pre><code class=\"language-bash\">npm install @nestjs\/throttler<\/code><\/pre>\n<p>Ve <code>app.module.ts<\/code>'e <code>ThrottlerModule<\/code>'\u00fc ekleyip, kontrol\u00f6rlere veya metotlara <code>@Throttle()<\/code> dekorat\u00f6r\u00fcn\u00fc uygulayabiliriz.<\/p>\n<h3>\u00d6nbellekleme (Caching)<\/h3>\n<p>S\u0131k eri\u015filen k\u0131sa kodlar i\u00e7in veritaban\u0131 sorgular\u0131n\u0131 azaltmak ve yan\u0131t s\u00fcrelerini iyile\u015ftirmek amac\u0131yla \u00f6nbellekleme kullanabiliriz. Redis gibi bir in-memory veritaban\u0131 bu i\u015f i\u00e7in m\u00fckemmeldir.<\/p>\n<p>*   <strong>Uygulama:<\/strong> <code>@nestjs\/cache-manager<\/code> mod\u00fcl\u00fc ve Redis adapt\u00f6r\u00fc ile <code>UrlShortenerService<\/code>'deki <code>getOriginalUrl<\/code> metodu i\u00e7in \u00f6nbellekleme uygulayabiliriz.<\/p>\n<pre><code class=\"language-bash\">npm install cache-manager cache-manager-redis-store\nnpm install --save-dev @types\/cache-manager-redis-store<\/code><\/pre>\n<h3>Testler<\/h3>\n<p>Uygulaman\u0131n do\u011fru \u00e7al\u0131\u015ft\u0131\u011f\u0131ndan emin olmak ve gelecekteki de\u011fi\u015fikliklerin mevcut i\u015flevselli\u011fi bozmad\u0131\u011f\u0131n\u0131 garanti etmek i\u00e7in unit ve E2E (u\u00e7tan uca) testleri yazmak kritik \u00f6neme sahiptir. NestJS, <code>@nestjs\/testing<\/code> mod\u00fcl\u00fc ile kapsaml\u0131 bir test altyap\u0131s\u0131 sunar.<\/p>\n<p>*   <strong>Unit Testleri:<\/strong> <code>UrlShortenerService<\/code> gibi i\u015f mant\u0131\u011f\u0131n\u0131 i\u00e7eren servislerin her bir metodunu izole bir \u015fekilde test etmek.<br \/>\n*   <strong>E2E Testleri:<\/strong> Uygulaman\u0131n API endpoint'lerini \u00e7a\u011f\u0131rarak ve beklenen yan\u0131tlar\u0131 kontrol ederek t\u00fcm ak\u0131\u015f\u0131 test etmek.<\/p>\n<h3>G\u00fcvenlik<\/h3>\n<p>URL k\u0131salt\u0131c\u0131lar, k\u00f6t\u00fc ama\u00e7l\u0131 URL'lerin yay\u0131lmas\u0131 i\u00e7in kullan\u0131labilir.<\/p>\n<p>*   <strong>XSS ve SQL Injection:<\/strong> NestJS ve TypeORM, bu t\u00fcr sald\u0131r\u0131lara kar\u015f\u0131 yerle\u015fik korumalar sa\u011flar. Ancak yine de kullan\u0131c\u0131dan gelen verileri dikkatlice i\u015flemek \u00f6nemlidir.<br \/>\n*   <strong>K\u00f6t\u00fc Ama\u00e7l\u0131 URL Tespiti:<\/strong> K\u0131salt\u0131lmak istenen URL'leri bilinen k\u00f6t\u00fc ama\u00e7l\u0131 URL listeleriyle (\u00f6rn. Google Safe Browsing API) kar\u015f\u0131la\u015ft\u0131rarak kara listeye al\u0131nm\u0131\u015f siteleri engellemek.<\/p>\n<p>Bu geli\u015fmi\u015f \u00f6zellikler, URL k\u0131salt\u0131c\u0131m\u0131z\u0131 sadece i\u015flevsel de\u011fil, ayn\u0131 zamanda g\u00fcvenli, performansl\u0131 ve bak\u0131m\u0131 kolay bir uygulamaya d\u00f6n\u00fc\u015ft\u00fcrecektir. Her bir \u00f6zellik, uygulaman\u0131n farkl\u0131 bir y\u00f6n\u00fcn\u00fc iyile\u015ftirir ve kullan\u0131c\u0131 deneyimini zenginle\u015ftirir.<\/p>\n<h2>Sonu\u00e7<\/h2>\n<p>Bu makalede, NodeJS ve NestJS \u00e7at\u0131s\u0131n\u0131 kullanarak s\u0131f\u0131rdan tip-g\u00fcvenli bir URL k\u0131salt\u0131c\u0131 uygulamas\u0131n\u0131 nas\u0131l in\u015fa edece\u011fimizi detayl\u0131 bir \u015fekilde inceledik. NestJS'in mod\u00fcler yap\u0131s\u0131, TypeScript'in sa\u011flad\u0131\u011f\u0131 tip-g\u00fcvenli\u011fi ve TypeORM gibi g\u00fc\u00e7l\u00fc k\u00fct\u00fcphanelerle entegrasyonu sayesinde, sadece \u00e7al\u0131\u015fan bir uygulama de\u011fil, ayn\u0131 zamanda bak\u0131m\u0131 kolay, \u00f6l\u00e7eklenebilir ve sa\u011flam bir \u00e7\u00f6z\u00fcm geli\u015ftirdik.<\/p>\n<p>Projemizin temel ad\u0131mlar\u0131 aras\u0131nda NestJS projesi kurulumu, PostgreSQL ile TypeORM entegrasyonu, veri aktar\u0131m nesneleri (DTO'lar) arac\u0131l\u0131\u011f\u0131yla gelen isteklerin tip-g\u00fcvenli validasyonu, <code>nanoid<\/code> kullanarak benzersiz k\u0131sa kodlar \u00fcretme mant\u0131\u011f\u0131, API endpointlerinin olu\u015fturulmas\u0131 ve NestJS'in dahili hata y\u00f6netimi mekanizmalar\u0131n\u0131n kullan\u0131m\u0131 yer ald\u0131.<\/p>\n<p>Tip-g\u00fcvenli\u011fin \u00f6nemi, \u00f6zellikle <code>CreateShortUrlDto<\/code> gibi DTO'lar ve <code>ShortUrl<\/code> entity'si arac\u0131l\u0131\u011f\u0131yla a\u00e7\u0131k\u00e7a g\u00f6r\u00fcld\u00fc. Bu yap\u0131lar, hem geli\u015ftirme s\u00fcrecinde olas\u0131 hatalar\u0131 azaltmam\u0131za yard\u0131mc\u0131 oldu hem de kodun niyetini ve veri yap\u0131s\u0131n\u0131 daha \u015feffaf hale getirdi. NestJS'in <code>ValidationPipe<\/code> gibi dahili borular\u0131, bu tip-g\u00fcvenli validasyon s\u00fcrecini otomatikle\u015ftirmemizi sa\u011flayarak geli\u015ftirici verimlili\u011fini art\u0131rd\u0131.<\/p>\n<p>Uygulamam\u0131z\u0131 daha da iyile\u015ftirmek i\u00e7in TTL, analitik, rate limiting, \u00f6nbellekleme ve kapsaml\u0131 testler gibi geli\u015fmi\u015f \u00f6zelliklere de de\u011findik. Bu iyile\u015ftirmeler, bir URL k\u0131salt\u0131c\u0131n\u0131n ger\u00e7ek d\u00fcnya senaryolar\u0131nda kar\u015f\u0131la\u015fabilece\u011fi zorluklara kar\u015f\u0131 daha dayan\u0131kl\u0131 olmas\u0131n\u0131 sa\u011flar.<\/p>\n<p>Sonu\u00e7 olarak, NestJS ve TypeScript'in birle\u015fimi, modern ve g\u00fc\u00e7l\u00fc bir backend uygulamas\u0131 geli\u015ftirmek i\u00e7in m\u00fckemmel bir kombinasyon sunmaktad\u0131r. Bu makaledeki ad\u0131mlar\u0131 takip ederek, sadece bir URL k\u0131salt\u0131c\u0131 in\u015fa etmekle kalmayacak, ayn\u0131 zamanda NestJS'in temel prensiplerini ve tip-g\u00fcvenli geli\u015ftirme pratiklerini somut bir \u00f6rnek \u00fczerinden deneyimlemi\u015f olacaks\u0131n\u0131z. Bu bilgiler, gelecekteki daha karma\u015f\u0131k projeleriniz i\u00e7in sa\u011flam bir temel olu\u015fturacakt\u0131r.<\/body><\/p>\n","protected":false},"excerpt":{"rendered":"NodeJS ve NestJS ile Tip-G\u00fcvenli (Type-Safe) URL K\u0131salt\u0131c\u0131 Nas\u0131l \u0130n\u015fa Edilir?\nGiri\u015f\nG\u00fcn\u00fcm\u00fcz\u00fcn dijital d\u00fcnyas\u0131nda, uzun ve karma\u015f\u0131k UR","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"csco_page_header_type":"","csco_page_load_nextpost":"","csco_page_subscribe_form":"","csco_page_contact_form":"","footnotes":""},"categories":[136],"tags":[],"class_list":{"0":"post-39483","1":"post","2":"type-post","3":"status-publish","4":"format-standard","6":"category-node-js","7":"cs-entry","8":"cs-video-wrap"},"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v20.5 (Yoast SEO v25.3.1) - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>NodeJS ve NestJS ile Tip-G\u00fcvenli (Type-Safe) URL K\u0131salt\u0131c\u0131 Nas\u0131l \u0130n\u015fa Edilir? - Kodlar\u0131n Gizemli D\u00fcnyas\u0131<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/fatihsoysal.com\/blog\/nodejs-ve-nestjs-ile-tip-guvenli-type-safe-url-kisaltici-nasil-insa-edilir\/\" \/>\n<meta property=\"og:locale\" content=\"tr_TR\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"NodeJS ve NestJS ile Tip-G\u00fcvenli (Type-Safe) URL K\u0131salt\u0131c\u0131 Nas\u0131l \u0130n\u015fa Edilir?\" \/>\n<meta property=\"og:description\" content=\"NodeJS ve NestJS ile Tip-G\u00fcvenli (Type-Safe) URL K\u0131salt\u0131c\u0131 Nas\u0131l \u0130n\u015fa Edilir? Giri\u015f G\u00fcn\u00fcm\u00fcz\u00fcn dijital d\u00fcnyas\u0131nda, uzun ve karma\u015f\u0131k UR\" \/>\n<meta property=\"og:url\" content=\"https:\/\/fatihsoysal.com\/blog\/nodejs-ve-nestjs-ile-tip-guvenli-type-safe-url-kisaltici-nasil-insa-edilir\/\" \/>\n<meta property=\"og:site_name\" content=\"Kodlar\u0131n Gizemli D\u00fcnyas\u0131\" \/>\n<meta property=\"article:published_time\" content=\"2026-02-22T10:40:49+00:00\" \/>\n<meta name=\"author\" content=\"Fatih Soysal\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Yazan:\" \/>\n\t<meta name=\"twitter:data1\" content=\"Fatih Soysal\" \/>\n\t<meta name=\"twitter:label2\" content=\"Tahmini okuma s\u00fcresi\" \/>\n\t<meta name=\"twitter:data2\" content=\"21 dakika\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/fatihsoysal.com\/blog\/nodejs-ve-nestjs-ile-tip-guvenli-type-safe-url-kisaltici-nasil-insa-edilir\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/fatihsoysal.com\/blog\/nodejs-ve-nestjs-ile-tip-guvenli-type-safe-url-kisaltici-nasil-insa-edilir\/\"},\"author\":{\"name\":\"Fatih Soysal\",\"@id\":\"https:\/\/fatihsoysal.com\/blog\/#\/schema\/person\/002a254750921dcfd568a99e48240dd1\"},\"headline\":\"NodeJS ve NestJS ile Tip-G\u00fcvenli (Type-Safe) URL K\u0131salt\u0131c\u0131 Nas\u0131l \u0130n\u015fa Edilir?\",\"datePublished\":\"2026-02-22T10:40:49+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/fatihsoysal.com\/blog\/nodejs-ve-nestjs-ile-tip-guvenli-type-safe-url-kisaltici-nasil-insa-edilir\/\"},\"wordCount\":2974,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\/\/fatihsoysal.com\/blog\/#\/schema\/person\/002a254750921dcfd568a99e48240dd1\"},\"articleSection\":[\"Node.js\"],\"inLanguage\":\"tr\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\/\/fatihsoysal.com\/blog\/nodejs-ve-nestjs-ile-tip-guvenli-type-safe-url-kisaltici-nasil-insa-edilir\/#respond\"]}],\"copyrightYear\":\"2026\",\"copyrightHolder\":{\"@id\":\"https:\/\/fatihsoysal.com\/blog\/#organization\"}},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/fatihsoysal.com\/blog\/nodejs-ve-nestjs-ile-tip-guvenli-type-safe-url-kisaltici-nasil-insa-edilir\/\",\"url\":\"https:\/\/fatihsoysal.com\/blog\/nodejs-ve-nestjs-ile-tip-guvenli-type-safe-url-kisaltici-nasil-insa-edilir\/\",\"name\":\"NodeJS ve NestJS ile Tip-G\u00fcvenli (Type-Safe) URL K\u0131salt\u0131c\u0131 Nas\u0131l \u0130n\u015fa Edilir? - Kodlar\u0131n Gizemli D\u00fcnyas\u0131\",\"isPartOf\":{\"@id\":\"https:\/\/fatihsoysal.com\/blog\/#website\"},\"datePublished\":\"2026-02-22T10:40:49+00:00\",\"breadcrumb\":{\"@id\":\"https:\/\/fatihsoysal.com\/blog\/nodejs-ve-nestjs-ile-tip-guvenli-type-safe-url-kisaltici-nasil-insa-edilir\/#breadcrumb\"},\"inLanguage\":\"tr\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/fatihsoysal.com\/blog\/nodejs-ve-nestjs-ile-tip-guvenli-type-safe-url-kisaltici-nasil-insa-edilir\/\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/fatihsoysal.com\/blog\/nodejs-ve-nestjs-ile-tip-guvenli-type-safe-url-kisaltici-nasil-insa-edilir\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Anasayfa\",\"item\":\"https:\/\/fatihsoysal.com\/blog\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"NodeJS ve NestJS ile Tip-G\u00fcvenli (Type-Safe) URL K\u0131salt\u0131c\u0131 Nas\u0131l \u0130n\u015fa Edilir?\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/fatihsoysal.com\/blog\/#website\",\"url\":\"https:\/\/fatihsoysal.com\/blog\/\",\"name\":\"Fatihsoysal.com\",\"description\":\"Blog - Yaz\u0131l\u0131m D\u00fcnyas\u0131 Tecr\u00fcbelerim\",\"publisher\":{\"@id\":\"https:\/\/fatihsoysal.com\/blog\/#\/schema\/person\/002a254750921dcfd568a99e48240dd1\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/fatihsoysal.com\/blog\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"tr\"},{\"@type\":[\"Person\",\"Organization\"],\"@id\":\"https:\/\/fatihsoysal.com\/blog\/#\/schema\/person\/002a254750921dcfd568a99e48240dd1\",\"name\":\"Fatih Soysal\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"tr\",\"@id\":\"https:\/\/fatihsoysal.com\/blog\/#\/schema\/person\/image\/\",\"url\":\"https:\/\/fatihsoysal.com\/blog\/wp-content\/uploads\/2024\/04\/cropped-replicate-prediction-3kgg1hgjn5rgp0cf0p5tr0jw7w-1.png\",\"contentUrl\":\"https:\/\/fatihsoysal.com\/blog\/wp-content\/uploads\/2024\/04\/cropped-replicate-prediction-3kgg1hgjn5rgp0cf0p5tr0jw7w-1.png\",\"width\":512,\"height\":512,\"caption\":\"Fatih Soysal\"},\"logo\":{\"@id\":\"https:\/\/fatihsoysal.com\/blog\/#\/schema\/person\/image\/\"},\"description\":\"Kullan\u0131m ve kodlama m\u00fckemmeliyetini odak alan uygulamalar olu\u015fturma deneyimine sahip, profesyonel olarak 15+ y\u0131l \u00fczeri deneyime sahip bir yaz\u0131l\u0131m m\u00fchendisi.\",\"url\":\"https:\/\/fatihsoysal.com\/blog\/author\/fatihsoysal\/\"}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"NodeJS ve NestJS ile Tip-G\u00fcvenli (Type-Safe) URL K\u0131salt\u0131c\u0131 Nas\u0131l \u0130n\u015fa Edilir? - Kodlar\u0131n Gizemli D\u00fcnyas\u0131","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/fatihsoysal.com\/blog\/nodejs-ve-nestjs-ile-tip-guvenli-type-safe-url-kisaltici-nasil-insa-edilir\/","og_locale":"tr_TR","og_type":"article","og_title":"NodeJS ve NestJS ile Tip-G\u00fcvenli (Type-Safe) URL K\u0131salt\u0131c\u0131 Nas\u0131l \u0130n\u015fa Edilir?","og_description":"NodeJS ve NestJS ile Tip-G\u00fcvenli (Type-Safe) URL K\u0131salt\u0131c\u0131 Nas\u0131l \u0130n\u015fa Edilir? Giri\u015f G\u00fcn\u00fcm\u00fcz\u00fcn dijital d\u00fcnyas\u0131nda, uzun ve karma\u015f\u0131k UR","og_url":"https:\/\/fatihsoysal.com\/blog\/nodejs-ve-nestjs-ile-tip-guvenli-type-safe-url-kisaltici-nasil-insa-edilir\/","og_site_name":"Kodlar\u0131n Gizemli D\u00fcnyas\u0131","article_published_time":"2026-02-22T10:40:49+00:00","author":"Fatih Soysal","twitter_card":"summary_large_image","twitter_misc":{"Yazan:":"Fatih Soysal","Tahmini okuma s\u00fcresi":"21 dakika"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/fatihsoysal.com\/blog\/nodejs-ve-nestjs-ile-tip-guvenli-type-safe-url-kisaltici-nasil-insa-edilir\/#article","isPartOf":{"@id":"https:\/\/fatihsoysal.com\/blog\/nodejs-ve-nestjs-ile-tip-guvenli-type-safe-url-kisaltici-nasil-insa-edilir\/"},"author":{"name":"Fatih Soysal","@id":"https:\/\/fatihsoysal.com\/blog\/#\/schema\/person\/002a254750921dcfd568a99e48240dd1"},"headline":"NodeJS ve NestJS ile Tip-G\u00fcvenli (Type-Safe) URL K\u0131salt\u0131c\u0131 Nas\u0131l \u0130n\u015fa Edilir?","datePublished":"2026-02-22T10:40:49+00:00","mainEntityOfPage":{"@id":"https:\/\/fatihsoysal.com\/blog\/nodejs-ve-nestjs-ile-tip-guvenli-type-safe-url-kisaltici-nasil-insa-edilir\/"},"wordCount":2974,"commentCount":0,"publisher":{"@id":"https:\/\/fatihsoysal.com\/blog\/#\/schema\/person\/002a254750921dcfd568a99e48240dd1"},"articleSection":["Node.js"],"inLanguage":"tr","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/fatihsoysal.com\/blog\/nodejs-ve-nestjs-ile-tip-guvenli-type-safe-url-kisaltici-nasil-insa-edilir\/#respond"]}],"copyrightYear":"2026","copyrightHolder":{"@id":"https:\/\/fatihsoysal.com\/blog\/#organization"}},{"@type":"WebPage","@id":"https:\/\/fatihsoysal.com\/blog\/nodejs-ve-nestjs-ile-tip-guvenli-type-safe-url-kisaltici-nasil-insa-edilir\/","url":"https:\/\/fatihsoysal.com\/blog\/nodejs-ve-nestjs-ile-tip-guvenli-type-safe-url-kisaltici-nasil-insa-edilir\/","name":"NodeJS ve NestJS ile Tip-G\u00fcvenli (Type-Safe) URL K\u0131salt\u0131c\u0131 Nas\u0131l \u0130n\u015fa Edilir? - Kodlar\u0131n Gizemli D\u00fcnyas\u0131","isPartOf":{"@id":"https:\/\/fatihsoysal.com\/blog\/#website"},"datePublished":"2026-02-22T10:40:49+00:00","breadcrumb":{"@id":"https:\/\/fatihsoysal.com\/blog\/nodejs-ve-nestjs-ile-tip-guvenli-type-safe-url-kisaltici-nasil-insa-edilir\/#breadcrumb"},"inLanguage":"tr","potentialAction":[{"@type":"ReadAction","target":["https:\/\/fatihsoysal.com\/blog\/nodejs-ve-nestjs-ile-tip-guvenli-type-safe-url-kisaltici-nasil-insa-edilir\/"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/fatihsoysal.com\/blog\/nodejs-ve-nestjs-ile-tip-guvenli-type-safe-url-kisaltici-nasil-insa-edilir\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Anasayfa","item":"https:\/\/fatihsoysal.com\/blog\/"},{"@type":"ListItem","position":2,"name":"NodeJS ve NestJS ile Tip-G\u00fcvenli (Type-Safe) URL K\u0131salt\u0131c\u0131 Nas\u0131l \u0130n\u015fa Edilir?"}]},{"@type":"WebSite","@id":"https:\/\/fatihsoysal.com\/blog\/#website","url":"https:\/\/fatihsoysal.com\/blog\/","name":"Fatihsoysal.com","description":"Blog - Yaz\u0131l\u0131m D\u00fcnyas\u0131 Tecr\u00fcbelerim","publisher":{"@id":"https:\/\/fatihsoysal.com\/blog\/#\/schema\/person\/002a254750921dcfd568a99e48240dd1"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/fatihsoysal.com\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"tr"},{"@type":["Person","Organization"],"@id":"https:\/\/fatihsoysal.com\/blog\/#\/schema\/person\/002a254750921dcfd568a99e48240dd1","name":"Fatih Soysal","image":{"@type":"ImageObject","inLanguage":"tr","@id":"https:\/\/fatihsoysal.com\/blog\/#\/schema\/person\/image\/","url":"https:\/\/fatihsoysal.com\/blog\/wp-content\/uploads\/2024\/04\/cropped-replicate-prediction-3kgg1hgjn5rgp0cf0p5tr0jw7w-1.png","contentUrl":"https:\/\/fatihsoysal.com\/blog\/wp-content\/uploads\/2024\/04\/cropped-replicate-prediction-3kgg1hgjn5rgp0cf0p5tr0jw7w-1.png","width":512,"height":512,"caption":"Fatih Soysal"},"logo":{"@id":"https:\/\/fatihsoysal.com\/blog\/#\/schema\/person\/image\/"},"description":"Kullan\u0131m ve kodlama m\u00fckemmeliyetini odak alan uygulamalar olu\u015fturma deneyimine sahip, profesyonel olarak 15+ y\u0131l \u00fczeri deneyime sahip bir yaz\u0131l\u0131m m\u00fchendisi.","url":"https:\/\/fatihsoysal.com\/blog\/author\/fatihsoysal\/"}]}},"yoast_meta":{"yoast_wpseo_title":"","yoast_wpseo_metadesc":"","yoast_wpseo_canonical":""},"amp_enabled":true,"_links":{"self":[{"href":"https:\/\/fatihsoysal.com\/blog\/wp-json\/wp\/v2\/posts\/39483","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/fatihsoysal.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/fatihsoysal.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/fatihsoysal.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/fatihsoysal.com\/blog\/wp-json\/wp\/v2\/comments?post=39483"}],"version-history":[{"count":1,"href":"https:\/\/fatihsoysal.com\/blog\/wp-json\/wp\/v2\/posts\/39483\/revisions"}],"predecessor-version":[{"id":39484,"href":"https:\/\/fatihsoysal.com\/blog\/wp-json\/wp\/v2\/posts\/39483\/revisions\/39484"}],"wp:attachment":[{"href":"https:\/\/fatihsoysal.com\/blog\/wp-json\/wp\/v2\/media?parent=39483"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/fatihsoysal.com\/blog\/wp-json\/wp\/v2\/categories?post=39483"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/fatihsoysal.com\/blog\/wp-json\/wp\/v2\/tags?post=39483"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}