{"id":30938,"date":"2025-10-03T19:03:09","date_gmt":"2025-10-03T16:03:09","guid":{"rendered":"https:\/\/fatihsoysal.com\/blog\/node-js-ve-express-ile-rest-api-sifirdan-uretime-tam-kilavuz\/"},"modified":"2025-10-03T19:03:09","modified_gmt":"2025-10-03T16:03:09","slug":"node-js-ve-express-ile-rest-api-sifirdan-uretime-tam-kilavuz","status":"publish","type":"post","link":"https:\/\/fatihsoysal.com\/blog\/node-js-ve-express-ile-rest-api-sifirdan-uretime-tam-kilavuz\/","title":{"rendered":"Node.js ve Express ile REST API: S\u0131f\u0131rdan \u00dcretime Tam K\u0131lavuz"},"content":{"rendered":"<p><body><\/p>\n<p>Node.js ve Express kullanarak s\u0131f\u0131rdan g\u00fcvenli, \u00f6l\u00e7eklenebilir bir REST API nas\u0131l olu\u015fturulur? Temel kavramlardan da\u011f\u0131t\u0131ma uzanan bu kapsaml\u0131 rehberle kendi API&#8217;nizi geli\u015ftirin ve modern web uygulamalar\u0131n\u0131n g\u00fcc\u00fcn\u00fc ke\u015ffedin.<\/p>\n<p>G\u00fcn\u00fcm\u00fcz dijital d\u00fcnyas\u0131nda, uygulamalar\u0131m\u0131z\u0131n birbirleriyle ve veri kaynaklar\u0131yla etkile\u015fime girmesi temel bir gerekliliktir. Ak\u0131ll\u0131 telefonlar\u0131m\u0131zdaki mobil uygulamalardan, web taray\u0131c\u0131m\u0131zdaki karma\u015f\u0131k tek sayfal\u0131k uygulamalara (SPA) kadar her \u015fey, arka planda bir sunucuyla ileti\u015fim kurarak \u00e7al\u0131\u015f\u0131r. \u0130\u015fte bu noktada <strong>REST API&#8217;ler<\/strong> (Representational State Transfer Application Programming Interface) devreye girer. API&#8217;ler, farkl\u0131 yaz\u0131l\u0131m sistemlerinin birbiriyle g\u00fcvenli ve standart bir \u015fekilde konu\u015fmas\u0131n\u0131 sa\u011flayan k\u00f6pr\u00fclerdir. Bir API, uygulaman\u0131z\u0131n belirli verileri almas\u0131n\u0131, g\u00f6ndermesini, g\u00fcncellemesini veya silmesini sa\u011flayan bir dizi kural ve protokol setidir. \u00d6rne\u011fin, bir hava durumu uygulamas\u0131, hava durumu verilerini almak i\u00e7in \u00fc\u00e7\u00fcnc\u00fc taraf bir hava durumu API&#8217;sine istek g\u00f6nderir. Sosyal medya uygulamalar\u0131 ise g\u00f6nderileri, yorumlar\u0131 veya kullan\u0131c\u0131 bilgilerini y\u00f6netmek i\u00e7in kendi REST API&#8217;lerini kullan\u0131r.<\/p>\n<p>Peki, bir API olu\u015fturmak i\u00e7in neden Node.js ve Express&#8217;i se\u00e7meliyiz? Node.js, Google Chrome&#8217;un V8 JavaScript motoru \u00fczerine kurulu, sunucu taraf\u0131 JavaScript \u00e7al\u0131\u015fma zaman\u0131 ortam\u0131d\u0131r. Bu, geli\u015ftiricilerin hem \u00f6n u\u00e7ta hem de arka u\u00e7ta ayn\u0131 dili kullanabilmesini sa\u011flar, bu da \u00f6\u011frenme e\u011frisini d\u00fc\u015f\u00fcr\u00fcr ve geli\u015ftirme s\u00fcre\u00e7lerini h\u0131zland\u0131r\u0131r. Node.js&#8217;in temel avantajlar\u0131ndan biri, <strong>olay tabanl\u0131, e\u015fzamans\u0131z ve engellemeyen G\/\u00c7 modeli<\/strong> sayesinde y\u00fcksek performansl\u0131 ve \u00f6l\u00e7eklenebilir uygulamalar geli\u015ftirmeye olanak tan\u0131mas\u0131d\u0131r. \u00d6zellikle yo\u011fun veri trafi\u011fi olan ve anl\u0131k tepki vermesi gereken uygulamalar i\u00e7in idealdir. Bir istek gelir, Node.js bu iste\u011fi i\u015fler ve ba\u015fka bir i\u015flemi beklemek yerine hemen bir sonraki iste\u011fe ge\u00e7er. Bu, sunucunun ayn\u0131 anda \u00e7ok say\u0131da ba\u011flant\u0131y\u0131 etkin bir \u015fekilde y\u00f6netebilece\u011fi anlam\u0131na gelir.<\/p>\n<p><strong>Express.js<\/strong> ise Node.js i\u00e7in minimalist ve esnek bir web uygulama \u00e7at\u0131s\u0131d\u0131r (framework). Node.js&#8217;in d\u00fc\u015f\u00fck seviyeli API&#8217;lerini kullanarak web uygulamalar\u0131 ve REST API&#8217;leri olu\u015fturmay\u0131 \u00e7ok daha kolay ve h\u0131zl\u0131 hale getirir. Y\u00f6nlendirme, middleware y\u00f6netimi, \u015fablon motoru entegrasyonu gibi temel web i\u015flevlerini basitle\u015ftirir. Express&#8217;in hafif yap\u0131s\u0131, projenizin ihtiya\u00e7lar\u0131na g\u00f6re \u00f6zelle\u015ftirilebilen mod\u00fcler bir yap\u0131 sunar. B\u00fcy\u00fck ve aktif bir toplulu\u011fa sahip olmas\u0131 sayesinde, kar\u015f\u0131la\u015fabilece\u011finiz hemen hemen her sorun i\u00e7in kolayca \u00e7\u00f6z\u00fcm bulabilir ve \u00e7ok say\u0131da \u00fc\u00e7\u00fcnc\u00fc taraf k\u00fct\u00fcphaneden faydalanabilirsiniz. Bu kombinasyon, Node.js&#8217;in performans\u0131 ile Express&#8217;in geli\u015ftirme kolayl\u0131\u011f\u0131n\u0131 bir araya getirerek, s\u0131f\u0131rdan \u00fcretime ge\u00e7i\u015f s\u00fcrecinde g\u00fc\u00e7l\u00fc ve verimli bir \u00e7\u00f6z\u00fcm sunar. \u00d6rne\u011fin, bir e-ticaret uygulamas\u0131nda \u00fcr\u00fcn listeleme, sepet y\u00f6netimi, \u00f6deme i\u015flemleri gibi kritik ad\u0131mlar\u0131n her biri arka u\u00e7ta \u00e7al\u0131\u015fan g\u00fcvenilir bir REST API&#8217;ye ihtiya\u00e7 duyar. Node.js ve Express bu t\u00fcr bir sistemin bel kemi\u011fini olu\u015fturmak i\u00e7in m\u00fckemmel ara\u00e7lard\u0131r.<\/p>\n<div class=\"interactive-element expert-tip\">\n  Uzman \u0130pucu: Node.js&#8217;in asenkron yap\u0131s\u0131, \u00f6zellikle I\/O yo\u011fun (veritaban\u0131 i\u015flemleri, dosya okuma\/yazma, a\u011f istekleri) uygulamalar i\u00e7in b\u00fcy\u00fck bir performans avantaj\u0131 sa\u011flar. Ancak, CPU yo\u011fun i\u015flemler (karma\u015f\u0131k hesaplamalar) i\u00e7in Node.js&#8217;in tek i\u015f par\u00e7ac\u0131kl\u0131 yap\u0131s\u0131 darbo\u011faz olu\u015fturabilir. Bu t\u00fcr durumlarda Worker Threads veya mikroservis mimarileri d\u00fc\u015f\u00fcn\u00fclebilir.\n<\/div>\n<h2>Temel Kavramlar: REST API Nedir ve Nas\u0131l \u00c7al\u0131\u015f\u0131r?<\/h2>\n<p>REST API&#8217;ler hakk\u0131nda konu\u015furken, &#8220;REST&#8221; kelimesinin tam olarak ne anlama geldi\u011fini anlamak \u00f6nemlidir. REST, bir mimari stilidir; yani, da\u011f\u0131t\u0131k sistemlerin nas\u0131l tasarlanmas\u0131 gerekti\u011fine dair bir dizi ilke ve k\u0131s\u0131tlamad\u0131r. Roy Fielding taraf\u0131ndan 2000 y\u0131l\u0131nda doktora tezinde tan\u0131mlanm\u0131\u015ft\u0131r. REST API&#8217;lerin temel amac\u0131, istemci-sunucu aras\u0131ndaki ileti\u015fimi basit, standartla\u015ft\u0131r\u0131lm\u0131\u015f ve durumsal olmayan (stateless) bir \u015fekilde sa\u011flamakt\u0131r. Bu mimarinin temel ilkeleri \u015funlard\u0131r:<\/p>\n<ol>\n<li><strong>\u0130stemci-Sunucu (Client-Server):<\/strong> \u0130stemci (taray\u0131c\u0131, mobil uygulama vb.) ve sunucu birbirinden ba\u011f\u0131ms\u0131zd\u0131r. Her ikisi de kendi sorumluluk alan\u0131na sahiptir. \u0130stemci sadece kullan\u0131c\u0131 aray\u00fcz\u00fc ve sunucuyla etkile\u015fimden sorumluyken, sunucu veriyi depolama, i\u015fleme ve istemciye sunmaktan sorumludur. Bu ayr\u0131m, farkl\u0131 istemcilerin ayn\u0131 API&#8217;yi kullanmas\u0131na olanak tan\u0131r.<\/li>\n<li><strong>Durumsuzluk (Statelessness):<\/strong> Her istek, sunucuya t\u00fcm gerekli bilgiyi i\u00e7ermelidir. Sunucu, istemciden gelen \u00f6nceki hi\u00e7bir iste\u011fin durumunu hat\u0131rlamaz. Bu, sunucunun her iste\u011fi ba\u011f\u0131ms\u0131z olarak ele almas\u0131n\u0131 sa\u011flar ve \u00f6l\u00e7eklenebilirli\u011fi art\u0131r\u0131r, \u00e7\u00fcnk\u00fc sunucu taraf\u0131nda oturum bilgisi tutulmas\u0131na gerek kalmaz.<\/li>\n<li><strong>\u00d6nbelleklenebilirlik (Cacheability):<\/strong> \u0130stemci taraf\u0131nda \u00f6nbelle\u011fe al\u0131nabilecek yan\u0131tlar a\u00e7\u0131k\u00e7a belirtilmelidir. Bu, a\u011f trafi\u011fini azalt\u0131r ve performans\u0131 art\u0131r\u0131r, \u00e7\u00fcnk\u00fc s\u0131k talep edilen veriler sunucudan tekrar tekrar istenmez.<\/li>\n<li><strong>Katmanl\u0131 Sistem (Layered System):<\/strong> \u0130stemci, son sunucuya m\u0131 yoksa bir ara katmandaki (proxy, y\u00fck dengeleyici vb.) bir sunucuya m\u0131 ba\u011fl\u0131 oldu\u011funu bilmez. Bu, sistemin esnekli\u011fini ve \u00f6l\u00e7eklenebilirli\u011fini art\u0131r\u0131r.<\/li>\n<li><strong>Birle\u015fik Aray\u00fcz (Uniform Interface):<\/strong> Bu en kritik ilkedir ve REST&#8217;i di\u011fer mimarilerden ay\u0131ran ana fakt\u00f6rd\u00fcr.\n<ul>\n<li><strong>Kaynaklar\u0131n Tan\u0131mlanmas\u0131 (Identification of Resources):<\/strong> Her kayna\u011f\u0131n (\u00f6rne\u011fin, bir kullan\u0131c\u0131, bir \u00fcr\u00fcn) benzersiz bir URI (Uniform Resource Identifier) ile tan\u0131mlanmas\u0131 gerekir. \u00d6rne\u011fin, <code>\/api\/urunler\/123<\/code>.<\/li>\n<li><strong>Kaynaklar\u0131n Temsili Arac\u0131l\u0131\u011f\u0131yla Manip\u00fclasyon (Manipulation of Resources Through Representations):<\/strong> \u0130stemci, bir kayna\u011f\u0131n temsilini (genellikle JSON veya XML format\u0131nda) alarak veya g\u00f6ndererek o kayna\u011f\u0131 manip\u00fcle eder.<\/li>\n<li><strong>Kendi Kendini A\u00e7\u0131klay\u0131c\u0131 Mesajlar (Self-descriptive Messages):<\/strong> Her mesaj, istemcinin iste\u011fi veya yan\u0131t\u0131 nas\u0131l i\u015fleyece\u011fini anlayabilmesi i\u00e7in yeterli bilgiyi i\u00e7ermelidir. HTTP ba\u015fl\u0131klar\u0131 bu konuda \u00f6nemli bir rol oynar.<\/li>\n<li><strong>Uygulama Durumunun Motoru Olarak HATEOAS (Hypermedia As The Engine Of Application State):<\/strong> Bu, API&#8217;nin yan\u0131tlar\u0131nda ilgili eylemler veya kaynaklara ba\u011flant\u0131lar i\u00e7ermesi gerekti\u011fi anlam\u0131na gelir. \u0130stemci, bu ba\u011flant\u0131lar\u0131 izleyerek uygulaman\u0131n durumunu ke\u015ffeder ve de\u011fi\u015ftirir. Bu prensip genellikle en az uygulanan\u0131d\u0131r ama REST&#8217;in &#8220;seviyelerini&#8221; belirleyen \u00f6nemli bir kriterdir.<\/li>\n<\/ul>\n<\/li>\n<\/ol>\n<p>REST API&#8217;ler genellikle <strong>HTTP protokol\u00fc<\/strong> \u00fczerinde \u00e7al\u0131\u015f\u0131r ve HTTP metodlar\u0131n\u0131 (fiillerini) kaynaklar \u00fczerinde ger\u00e7ekle\u015ftirebilece\u011finiz eylemleri belirtmek i\u00e7in kullan\u0131r:<\/p>\n<ul>\n<li><strong>GET:<\/strong> Bir veya daha fazla kaynak almak i\u00e7in kullan\u0131l\u0131r. Sunucu \u00fczerinde herhangi bir de\u011fi\u015fiklik yapmaz. (\u00d6rnek: <code>GET \/api\/urunler<\/code>, <code>GET \/api\/urunler\/123<\/code>)<\/li>\n<li><strong>POST:<\/strong> Yeni bir kaynak olu\u015fturmak i\u00e7in kullan\u0131l\u0131r. (\u00d6rnek: <code>POST \/api\/urunler<\/code>, istek g\u00f6vdesinde yeni \u00fcr\u00fcn bilgileri ile)<\/li>\n<li><strong>PUT:<\/strong> Var olan bir kayna\u011f\u0131 tamamen g\u00fcncellemek i\u00e7in kullan\u0131l\u0131r. (\u00d6rnek: <code>PUT \/api\/urunler\/123<\/code>, istek g\u00f6vdesinde \u00fcr\u00fcn\u00fcn g\u00fcncel hali ile)<\/li>\n<li><strong>PATCH:<\/strong> Var olan bir kayna\u011f\u0131n sadece belirli bir k\u0131sm\u0131n\u0131 g\u00fcncellemek i\u00e7in kullan\u0131l\u0131r. (\u00d6rnek: <code>PATCH \/api\/urunler\/123<\/code>, istek g\u00f6vdesinde sadece de\u011fi\u015fecek alanlar ile)<\/li>\n<li><strong>DELETE:<\/strong> Bir kayna\u011f\u0131 silmek i\u00e7in kullan\u0131l\u0131r. (\u00d6rnek: <code>DELETE \/api\/urunler\/123<\/code>)<\/li>\n<\/ul>\n<p>API istekleri genellikle <strong>JSON (JavaScript Object Notation)<\/strong> format\u0131nda veri ta\u015f\u0131r. JSON, hem insanlar taraf\u0131ndan okunabilir hem de makineler taraf\u0131ndan kolayca ayr\u0131\u015ft\u0131r\u0131labilir oldu\u011fu i\u00e7in web API&#8217;lerinde en yayg\u0131n veri de\u011fi\u015fim format\u0131d\u0131r. Her iste\u011fe kar\u015f\u0131l\u0131k sunucu bir yan\u0131t d\u00f6ner ve bu yan\u0131t bir <strong>HTTP durum kodu<\/strong> (\u00f6rne\u011fin, <code>200 OK<\/code>, <code>404 Not Found<\/code>, <code>500 Internal Server Error<\/code>) ile birlikte gelir. Bu kodlar, iste\u011fin ba\u015far\u0131l\u0131 olup olmad\u0131\u011f\u0131n\u0131 veya hangi t\u00fcr bir hatan\u0131n olu\u015ftu\u011funu g\u00f6sterir. Bir e-ticaret uygulamas\u0131n\u0131n \u00fcr\u00fcn katalo\u011fu API&#8217;si \u00fczerinden \u00f6rneklendirecek olursak: bir mobil uygulama yeni \u00fcr\u00fcnleri listelemek i\u00e7in <code>GET \/api\/products<\/code> iste\u011fi g\u00f6nderir, bir y\u00f6netici yeni bir \u00fcr\u00fcn eklemek i\u00e7in <code>POST \/api\/products<\/code> iste\u011fi kullan\u0131r. Bu s\u00fcre\u00e7, REST&#8217;in sa\u011flad\u0131\u011f\u0131 standartlar sayesinde sorunsuz bir \u015fekilde ilerler. Bu temel kavramlar\u0131 anlamak, sa\u011flam ve s\u00fcrd\u00fcr\u00fclebilir bir REST API olu\u015fturman\u0131n ilk ad\u0131m\u0131d\u0131r.<\/p>\n<div class=\"interactive-element expert-tip\">\n  Uzman \u0130pucu: REST API&#8217;leri tasarlarken kaynak adlar\u0131n\u0131n (endpoint&#8217;lerin) \u00e7o\u011ful isimler kullanmas\u0131na dikkat edin (\u00f6rne\u011fin, <code>\/api\/users<\/code> yerine <code>\/api\/user<\/code>). Bu, API&#8217;nin daha tutarl\u0131 ve anla\u015f\u0131l\u0131r olmas\u0131n\u0131 sa\u011flar. Ayr\u0131ca, kaynaklar aras\u0131nda ili\u015fkileri belirtmek i\u00e7in i\u00e7 i\u00e7e URI&#8217;lar kullanmaktan ka\u00e7\u0131n\u0131n (\u00f6rne\u011fin, <code>\/api\/users\/1\/posts<\/code> yerine <code>\/api\/posts?userId=1<\/code>).\n<\/div>\n<h2>Ba\u015flang\u0131\u00e7: Node.js ve Express Ortam\u0131n\u0131 Kurulumu ve \u0130lk API&#8217;m\u0131z\u0131 Olu\u015fturma<\/h2>\n<p>S\u0131f\u0131rdan bir REST API olu\u015fturmaya ba\u015flamadan \u00f6nce, geli\u015ftirme ortam\u0131m\u0131z\u0131 kurmam\u0131z gerekiyor. Node.js ve Express ile \u00e7al\u0131\u015fmak i\u00e7in \u00f6ncelikle Node.js&#8217;in sistemimizde y\u00fckl\u00fc olmas\u0131 \u015fart. Node.js&#8217;i <a href=\"https:\/\/nodejs.org\/\" target=\"_blank\">resmi web sitesinden<\/a> indirebilir veya daha esnek bir y\u00f6netim i\u00e7in NVM (Node Version Manager) kullanabilirsiniz. NVM, farkl\u0131 Node.js s\u00fcr\u00fcmleri aras\u0131nda kolayca ge\u00e7i\u015f yapman\u0131z\u0131 sa\u011flar, bu da farkl\u0131 projelerle \u00e7al\u0131\u015f\u0131rken olduk\u00e7a faydal\u0131d\u0131r. Kurulum tamamland\u0131ktan sonra, terminalinizde <code>node -v<\/code> ve <code>npm -v<\/code> komutlar\u0131n\u0131 \u00e7al\u0131\u015ft\u0131rarak Node.js ve npm&#8217;in (Node Package Manager) ba\u015far\u0131l\u0131 bir \u015fekilde y\u00fcklendi\u011fini do\u011frulayabilirsiniz.<\/p>\n<h3>Proje Klas\u00f6r\u00fc Olu\u015fturma ve Express&#8217;i Kurma<\/h3>\n<p>\u0130lk ad\u0131m, projeniz i\u00e7in bir klas\u00f6r olu\u015fturmak ve terminalde bu klas\u00f6re gitmek olmal\u0131d\u0131r:<\/p>\n<pre><code class=\"language-bash\">\nmkdir my-first-api\ncd my-first-api\n<\/pre>\n<p><\/code><\/p>\n<p>Ard\u0131ndan, npm kullanarak yeni bir Node.js projesi ba\u015flataca\u011f\u0131z. Bu komut, projenizin metadata's\u0131n\u0131 i\u00e7eren bir <code>package.json<\/code> dosyas\u0131 olu\u015fturacakt\u0131r. Sorular\u0131 varsay\u0131lan de\u011ferlerle ge\u00e7mek i\u00e7in <code>-y<\/code> bayra\u011f\u0131n\u0131 kullanabilirsiniz:<\/p>\n<pre><code class=\"language-bash\">\nnpm init -y\n<\/pre>\n<p><\/code><\/p>\n<p>\u015eimdi projemize Express.js'i kurabiliriz:<\/p>\n<pre><code class=\"language-bash\">\nnpm install express\n<\/pre>\n<p><\/code><\/p>\n<p>Ayr\u0131ca, geli\u015ftirme s\u00fcrecimizi h\u0131zland\u0131rmak i\u00e7in <code>nodemon<\/code> adl\u0131 bir arac\u0131 kurman\u0131z\u0131 \u015fiddetle tavsiye ederim. Nodemon, kodunuzda yapt\u0131\u011f\u0131n\u0131z de\u011fi\u015fiklikleri alg\u0131lar ve sunucuyu otomatik olarak yeniden ba\u015flat\u0131r, b\u00f6ylece her de\u011fi\u015fiklikten sonra sunucuyu manuel olarak kapat\u0131p a\u00e7mak zorunda kalmazs\u0131n\u0131z:<\/p>\n<pre><code class=\"language-bash\">\nnpm install --save-dev nodemon\n<\/pre>\n<p><\/code><\/p>\n<p><code>package.json<\/code> dosyan\u0131za, sunucuyu nodemon ile ba\u015flatmak i\u00e7in bir \"start\" veya \"dev\" komutu ekleyelim:<\/p>\n<pre><code class=\"language-json\">\n{\n  \"name\": \"my-first-api\",\n  \"version\": \"1.0.0\",\n  \"description\": \"\",\n  \"main\": \"app.js\",\n  \"scripts\": {\n    \"start\": \"node app.js\",\n    \"dev\": \"nodemon app.js\"\n  },\n  \"keywords\": [],\n  \"author\": \"\",\n  \"license\": \"ISC\",\n  \"dependencies\": {\n    \"express\": \"^4.18.2\"\n  },\n  \"devDependencies\": {\n    \"nodemon\": \"^3.0.1\"\n  }\n}\n<\/pre>\n<p><\/code><\/p>\n<h3>\u0130lk API'm\u0131z\u0131 Olu\u015fturma: Hello World!<\/h3>\n<p>Proje klas\u00f6r\u00fcn\u00fczde <code>app.js<\/code> ad\u0131nda yeni bir dosya olu\u015fturun ve a\u015fa\u011f\u0131daki kodu i\u00e7ine yap\u0131\u015ft\u0131r\u0131n:<\/p>\n<pre><code class=\"language-javascript\">\n\/\/ Gerekli mod\u00fclleri i\u00e7eri aktar\u0131yoruz\nconst express = require('express'); \/\/ Express framework'\u00fcn\u00fc dahil ediyoruz\nconst app = express(); \/\/ Express uygulamas\u0131n\u0131 olu\u015fturuyoruz\nconst port = process.env.PORT || 3000; \/\/ Sunucunun \u00e7al\u0131\u015faca\u011f\u0131 portu belirliyoruz, e\u011fer ortam de\u011fi\u015fkeni varsa onu kullan, yoksa 3000\n\n\/\/ Gelen JSON isteklerini ayr\u0131\u015ft\u0131rmak i\u00e7in Express'in yerle\u015fik middleware'ini kullan\u0131yoruz\napp.use(express.json());\n\n\/\/ K\u00f6k dizin i\u00e7in basit bir GET iste\u011fi yan\u0131t\u0131 tan\u0131ml\u0131yoruz\napp.get('\/', (req, res) => {\n  res.send('Node.js ve Express ile REST API Rehberine Ho\u015f Geldiniz!');\n});\n\n\/\/ \"\/api\/selam\" ad\u0131nda yeni bir GET endpoint'i olu\u015fturuyoruz\napp.get('\/api\/selam', (req, res) => {\n  res.json({ message: 'Merhaba d\u00fcnya, ilk REST API endpoint\\'iniz \u00e7al\u0131\u015f\u0131yor!' });\n});\n\n\/\/ Parametre alan bir GET endpoint'i. \u00d6rne\u011fin: \/api\/kullanici\/Ahmet\napp.get('\/api\/kullanici\/:isim', (req, res) => {\n  const isim = req.params.isim; \/\/ URL'deki parametreyi al\u0131yoruz\n  res.json({ message: <code>Merhaba, ${isim}! Kullan\u0131c\u0131 profilinize ho\u015f geldiniz.<\/code> });\n});\n\n\/\/ POST iste\u011fi ile veri g\u00f6nderme \u00f6rne\u011fi\napp.post('\/api\/kayit', (req, res) => {\n  const { kullaniciAdi, sifre } = req.body; \/\/ \u0130stek g\u00f6vdesinden verileri al\u0131yoruz\n  \/\/ Ger\u00e7ek bir uygulamada burada veritaban\u0131na kay\u0131t i\u015flemi yap\u0131l\u0131r\n  if (kullaniciAdi && sifre) {\n    res.status(201).json({ message: <code>Kullan\u0131c\u0131 ${kullaniciAdi} ba\u015far\u0131yla kaydedildi!<\/code>, data: { kullaniciAdi } });\n  } else {\n    res.status(400).json({ message: 'Kullan\u0131c\u0131 ad\u0131 ve \u015fifre gerekli.' });\n  }\n});\n\n\/\/ Sunucuyu belirtilen port \u00fczerinden dinlemeye ba\u015fl\u0131yoruz\napp.listen(port, () => {\n  console.log(<code>Sunucu http:\/\/localhost:${port} adresinde \u00e7al\u0131\u015f\u0131yor...<\/code>);\n});\n<\/pre>\n<p><\/code><\/p>\n<p>Bu kodda neler oldu\u011funa bir g\u00f6z atal\u0131m:<\/p>\n<ul>\n<li><code>const express = require('express');<\/code>: Express mod\u00fcl\u00fcn\u00fc projemize dahil ediyoruz.<\/li>\n<li><code>const app = express();<\/code>: Express uygulamas\u0131n\u0131n bir \u00f6rne\u011fini olu\u015fturuyoruz. T\u00fcm API rotalar\u0131m\u0131z ve middleware'lerimiz bu <code>app<\/code> objesi \u00fczerinden tan\u0131mlanacak.<\/li>\n<li><code>const port = process.env.PORT || 3000;<\/code>: Sunucumuzun \u00e7al\u0131\u015faca\u011f\u0131 portu belirliyoruz. E\u011fer bir ortam de\u011fi\u015fkeni (<code>PORT<\/code>) tan\u0131ml\u0131ysa onu kullanacak, yoksa varsay\u0131lan olarak 3000 portunu se\u00e7ecek.<\/li>\n<li><code>app.use(express.json());<\/code>: Bu sat\u0131r, Express'e gelen t\u00fcm isteklerin g\u00f6vdesindeki JSON verilerini otomatik olarak ayr\u0131\u015ft\u0131rmas\u0131n\u0131 s\u00f6yler. B\u00f6ylece <code>req.body<\/code> \u00fczerinden g\u00f6nderilen verilere kolayca eri\u015febiliriz.<\/li>\n<li><code>app.get('\/', ...)<\/code>: K\u00f6k URL'e (<code>\/<\/code>) yap\u0131lan bir <code>GET<\/code> iste\u011fine nas\u0131l yan\u0131t verilece\u011fini tan\u0131ml\u0131yoruz. <code>res.send()<\/code> metodu ile basit bir metin yan\u0131t\u0131 g\u00f6nderiyoruz.<\/li>\n<li><code>app.get('\/api\/selam', ...)<\/code>: <code>\/api\/selam<\/code> yoluna yap\u0131lan <code>GET<\/code> iste\u011fi i\u00e7in bir endpoint tan\u0131ml\u0131yoruz. <code>res.json()<\/code> metodu ile bir JSON objesi yan\u0131t olarak g\u00f6nderiyoruz.<\/li>\n<li><code>app.get('\/api\/kullanici\/:isim', ...)<\/code>: URL parametrelerini nas\u0131l yakalayaca\u011f\u0131m\u0131z\u0131 g\u00f6steren bir \u00f6rnek. <code>:isim<\/code> k\u0131sm\u0131 bir placeholder'd\u0131r ve URL'de bu k\u0131sma gelen de\u011fer <code>req.params.isim<\/code> ile eri\u015filebilir.<\/li>\n<li><code>app.post('\/api\/kayit', ...)<\/code>: <code>\/api\/kayit<\/code> yoluna yap\u0131lan <code>POST<\/code> iste\u011fi i\u00e7in bir endpoint tan\u0131ml\u0131yoruz. Bu endpoint, kullan\u0131c\u0131 ad\u0131 ve \u015fifre gibi verilerin istek g\u00f6vdesinde nas\u0131l al\u0131nd\u0131\u011f\u0131n\u0131 g\u00f6sterir. Ger\u00e7ek bir uygulamada burada bir veritaban\u0131 i\u015flemi ger\u00e7ekle\u015ftirilirdi.<\/li>\n<li><code>app.listen(port, ...)<\/code>: Sunucuyu belirtilen port \u00fczerinden dinlemeye ba\u015flat\u0131r. Sunucu ba\u015far\u0131yla ba\u015flad\u0131\u011f\u0131nda konsola bir mesaj yazd\u0131r\u0131r.<\/li>\n<\/ul>\n<p>\u015eimdi projemizi \u00e7al\u0131\u015ft\u0131rmak i\u00e7in terminalde \u015fu komutu yaz\u0131n:<\/p>\n<pre><code class=\"language-bash\">\nnpm run dev\n<\/pre>\n<p><\/code><\/p>\n<p>Konsolda \"Sunucu http:\/\/localhost:3000 adresinde \u00e7al\u0131\u015f\u0131yor...\" mesaj\u0131n\u0131 g\u00f6rmelisiniz. Art\u0131k taray\u0131c\u0131n\u0131zdan veya Postman gibi bir API test arac\u0131 kullanarak <code>http:\/\/localhost:3000<\/code>, <code>http:\/\/localhost:3000\/api\/selam<\/code> veya <code>http:\/\/localhost:3000\/api\/kullanici\/Ali<\/code> adreslerini ziyaret ederek API'nizin \u00e7al\u0131\u015ft\u0131\u011f\u0131n\u0131 g\u00f6rebilirsiniz. <code>POST \/api\/kayit<\/code> endpoint'ini test etmek i\u00e7in Postman gibi bir ara\u00e7 kullanman\u0131z gerekecektir. \u0130stek g\u00f6vdesinde (Body) Raw JSON olarak <code>{\"kullaniciAdi\": \"testuser\", \"sifre\": \"password123\"}<\/code> g\u00f6nderebilirsiniz.<\/p>\n<p>Bu temel kurulum ve ilk API endpoint'lerinin olu\u015fturulmas\u0131yla, Node.js ve Express d\u00fcnyas\u0131na sa\u011flam bir ad\u0131m atm\u0131\u015f oluyorsunuz. Bir sonraki b\u00f6l\u00fcmde, bu API'ye kal\u0131c\u0131 veri depolama yetene\u011fi kazand\u0131rmak i\u00e7in bir veritaban\u0131n\u0131 nas\u0131l entegre edece\u011fimizi inceleyece\u011fiz.<\/p>\n<h2>Veritaban\u0131 Entegrasyonu: MongoDB ile Kal\u0131c\u0131 Veri Depolama Nas\u0131l Sa\u011flan\u0131r?<\/h2>\n<p>Bir REST API, genellikle verileri depolamak, almak ve manip\u00fcle etmek i\u00e7in bir veritaban\u0131na ihtiya\u00e7 duyar. \u00d6nceki b\u00f6l\u00fcmde olu\u015fturdu\u011fumuz \"Hello World\" API'si sadece statik yan\u0131tlar d\u00f6nd\u00fcr\u00fcyordu. Ancak ger\u00e7ek d\u00fcnya uygulamalar\u0131nda, kullan\u0131c\u0131lar, \u00fcr\u00fcnler, g\u00f6nderiler gibi dinamik verileri y\u00f6netmemiz gerekir. Bu verilerin kal\u0131c\u0131 olmas\u0131, yani sunucu yeniden ba\u015flat\u0131ld\u0131\u011f\u0131nda bile kaybolmamas\u0131 i\u00e7in bir veritaban\u0131 \u015fartt\u0131r. Piyasada bir\u00e7ok farkl\u0131 veritaban\u0131 t\u00fcr\u00fc bulunsa da, Node.js ekosistemiyle harika bir uyum sa\u011flayan ve esnek yap\u0131s\u0131yla dikkat \u00e7eken <strong>MongoDB<\/strong> (NoSQL bir veritaban\u0131) ve onun Node.js s\u00fcr\u00fcc\u00fcs\u00fc olan <strong>Mongoose<\/strong>'u kullanaca\u011f\u0131z. MongoDB, JSON benzeri BSON (Binary JSON) format\u0131nda belge tabanl\u0131 veri depolayan, \u015femas\u0131z bir veritaban\u0131d\u0131r, bu da h\u0131zl\u0131 geli\u015ftirme ve de\u011fi\u015fen veri yap\u0131lar\u0131na kolay uyum sa\u011flar.<\/p>\n<h3>MongoDB ve Mongoose Kurulumu<\/h3>\n<p>\u00d6ncelikle, sisteminizde MongoDB'nin kurulu ve \u00e7al\u0131\u015f\u0131r durumda olmas\u0131 gerekir. Yerel olarak kurabilir veya MongoDB Atlas gibi bulut tabanl\u0131 bir hizmet kullanabilirsiniz. Basitlik a\u00e7\u0131s\u0131ndan, bu rehberde yerel bir kurulum varsay\u0131lacakt\u0131r. E\u011fer yerel kurulumunuz yoksa, MongoDB'nin <a href=\"https:\/\/docs.mongodb.com\/manual\/installation\/\" target=\"_blank\">resmi belgelerini<\/a> takip ederek kurabilirsiniz.<\/p>\n<p>MongoDB \u00e7al\u0131\u015f\u0131r durumdayken, projemize Mongoose'u kurmal\u0131y\u0131z:<\/p>\n<pre><code class=\"language-bash\">\nnpm install mongoose\n<\/pre>\n<p><\/code><\/p>\n<h3>Veritaban\u0131 Ba\u011flant\u0131s\u0131 ve Model Tan\u0131m\u0131<\/h3>\n<p><code>app.js<\/code> dosyam\u0131zda veya ayr\u0131 bir <code>db.js<\/code> dosyas\u0131nda veritaban\u0131 ba\u011flant\u0131m\u0131z\u0131 kural\u0131m. Kolayl\u0131k sa\u011flamas\u0131 a\u00e7\u0131s\u0131ndan \u015fimdilik <code>app.js<\/code> i\u00e7ine ekleyelim:<\/p>\n<pre><code class=\"language-javascript\">\n\/\/ app.js dosyan\u0131z\u0131n en \u00fcst\u00fcne veya ba\u011flant\u0131 kurulacak yere ekleyin\nconst mongoose = require('mongoose');\n\n\/\/ MongoDB ba\u011flant\u0131 URL'si. Kendi veritaban\u0131 ad\u0131n\u0131z\u0131 belirtebilirsiniz.\nconst dbURI = 'mongodb:\/\/localhost:27017\/myapi_db'; \n\nmongoose.connect(dbURI, {\n  useNewUrlParser: true,\n  useUnifiedTopology: true\n})\n.then(() => console.log('MongoDB ba\u011flant\u0131s\u0131 ba\u015far\u0131l\u0131.'))\n.catch(err => console.error('MongoDB ba\u011flant\u0131 hatas\u0131:', err));\n\n\/\/ Bir \u00f6rnek veri modeli tan\u0131mlayal\u0131m: \"Item\" (\u00d6\u011fe)\n\/\/ Her \u00f6\u011fenin bir ad\u0131 (String) ve bir a\u00e7\u0131klamas\u0131 (String) olsun.\nconst itemSchema = new mongoose.Schema({\n  name: {\n    type: String,\n    required: true,\n    trim: true\n  },\n  description: {\n    type: String,\n    required: false,\n    trim: true\n  },\n  createdAt: {\n    type: Date,\n    default: Date.now\n  }\n});\n\n\/\/ \u015eemadan bir model olu\u015fturuyoruz. Mongoose otomatik olarak 'items' koleksiyonunu olu\u015fturacakt\u0131r.\nconst Item = mongoose.model('Item', itemSchema);\n\n\/\/ ... mevcut Express uygulaman\u0131z\u0131n di\u011fer kodlar\u0131 ...\n<\/pre>\n<p><\/code><\/p>\n<p>Yukar\u0131daki kodda:<\/p>\n<ul>\n<li><code>mongoose.connect()<\/code> ile MongoDB'ye ba\u011flan\u0131yoruz. Ba\u011flant\u0131 dizesinde veritaban\u0131 sunucunuzun adresi (<code>localhost:27017<\/code> varsay\u0131lan) ve kullanmak istedi\u011finiz veritaban\u0131n\u0131n ad\u0131 (<code>myapi_db<\/code>) yer al\u0131r.<\/li>\n<li><code>itemSchema<\/code>, veritaban\u0131ndaki \"Item\" koleksiyonunda saklanacak belgelerin yap\u0131s\u0131n\u0131 tan\u0131mlar. <code>name<\/code> alan\u0131 zorunlu ve metin tipi iken, <code>description<\/code> alan\u0131 iste\u011fe ba\u011fl\u0131d\u0131r. <code>createdAt<\/code> alan\u0131 ise otomatik olarak olu\u015fturulma tarihini tutar.<\/li>\n<li><code>mongoose.model('Item', itemSchema);<\/code> ile bu \u015femadan bir Mongoose modeli olu\u015fturuyoruz. Bu model, koleksiyonumuzdaki belgelerle etkile\u015fim kurmam\u0131z\u0131 sa\u011flayacak aray\u00fczd\u00fcr.<\/li>\n<\/ul>\n<h3>CRUD \u0130\u015flemleri i\u00e7in API Endpoint'leri Olu\u015fturma<\/h3>\n<p>\u015eimdi, <code>Item<\/code> modelini kullanarak CRUD (Create, Read, Update, Delete) operasyonlar\u0131 i\u00e7in REST API endpoint'leri olu\u015ftural\u0131m. Bu endpoint'leri <code>app.js<\/code> dosyan\u0131zdaki mevcut Express kodlar\u0131n\u0131z\u0131n alt\u0131na ekleyebilirsiniz:<\/p>\n<pre><code class=\"language-javascript\">\n\/\/ ... mevcut app.js kodlar\u0131 ve Item modeli tan\u0131m\u0131ndan sonra ...\n\n\/\/ 1. T\u00fcm \u00f6\u011feleri getir (READ all)\napp.get('\/api\/items', async (req, res) => {\n  try {\n    const items = await Item.find(); \/\/ T\u00fcm \u00f6\u011feleri veritaban\u0131ndan \u00e7ekiyoruz\n    res.json(items);\n  } catch (err) {\n    res.status(500).json({ message: err.message });\n  }\n});\n\n\/\/ 2. Belirli bir \u00f6\u011feyi ID'ye g\u00f6re getir (READ one)\napp.get('\/api\/items\/:id', async (req, res) => {\n  try {\n    const item = await Item.findById(req.params.id); \/\/ ID'ye g\u00f6re \u00f6\u011feyi bul\n    if (item == null) {\n      return res.status(404).json({ message: '\u00d6\u011fe bulunamad\u0131.' });\n    }\n    res.json(item);\n  } catch (err) {\n    res.status(500).json({ message: err.message });\n  }\n});\n\n\/\/ 3. Yeni bir \u00f6\u011fe olu\u015ftur (CREATE)\napp.post('\/api\/items', async (req, res) => {\n  const item = new Item({\n    name: req.body.name,\n    description: req.body.description\n  });\n\n  try {\n    const newItem = await item.save(); \/\/ Yeni \u00f6\u011feyi veritaban\u0131na kaydet\n    res.status(201).json(newItem); \/\/ Ba\u015far\u0131l\u0131 olu\u015fturma (201 Created) ve yeni \u00f6\u011feyi d\u00f6nd\u00fcr\n  } catch (err) {\n    res.status(400).json({ message: err.message }); \/\/ Hatal\u0131 istek (400 Bad Request)\n  }\n});\n\n\/\/ 4. Belirli bir \u00f6\u011feyi g\u00fcncelle (UPDATE)\napp.put('\/api\/items\/:id', async (req, res) => {\n  try {\n    const item = await Item.findById(req.params.id);\n    if (item == null) {\n      return res.status(404).json({ message: '\u00d6\u011fe bulunamad\u0131.' });\n    }\n\n    if (req.body.name != null) {\n      item.name = req.body.name;\n    }\n    if (req.body.description != null) {\n      item.description = req.body.description;\n    }\n    \n    const updatedItem = await item.save(); \/\/ G\u00fcncellenmi\u015f \u00f6\u011feyi kaydet\n    res.json(updatedItem);\n  } catch (err) {\n    res.status(400).json({ message: err.message });\n  }\n});\n\n\/\/ 5. Belirli bir \u00f6\u011feyi sil (DELETE)\napp.delete('\/api\/items\/:id', async (req, res) => {\n  try {\n    const item = await Item.findById(req.params.id);\n    if (item == null) {\n      return res.status(404).json({ message: '\u00d6\u011fe bulunamad\u0131.' });\n    }\n\n    await item.deleteOne(); \/\/ \u00d6\u011feyi sil\n    res.json({ message: '\u00d6\u011fe ba\u015far\u0131yla silindi.' });\n  } catch (err) {\n    res.status(500).json({ message: err.message });\n  }\n});\n\n\/\/ ... app.listen k\u0131sm\u0131 ...\n<\/pre>\n<p><\/code><\/p>\n<p>Bu kod blo\u011funda, her bir HTTP metodunu (GET, POST, PUT, DELETE) belirli bir CRUD operasyonuyla e\u015fle\u015ftirdik. Async\/await yap\u0131s\u0131n\u0131 kullanarak asenkron veritaban\u0131 i\u015flemlerini daha okunabilir hale getirdik. Her endpoint, olas\u0131 hatalar\u0131 (\u00f6rne\u011fin, \u00f6\u011fe bulunamad\u0131, ge\u00e7ersiz istek) uygun HTTP durum kodlar\u0131 ile ele alacak bir <code>try-catch<\/code> blo\u011fu i\u00e7erir. Art\u0131k <code>npm run dev<\/code> ile sunucunuzu \u00e7al\u0131\u015ft\u0131rd\u0131\u011f\u0131n\u0131zda, Postman veya benzeri bir ara\u00e7la bu endpoint'leri test edebilir, kendi verilerinizi ekleyip y\u00f6netebilirsiniz. Bu, API'nizin dinamik ve veritaban\u0131yla etkile\u015fimli hale gelmesi i\u00e7in \u00f6nemli bir ad\u0131md\u0131r. \u00d6rne\u011fin, bir g\u00f6rev listesi uygulamas\u0131 i\u00e7in bu <code>Item<\/code> modelini <code>Todo<\/code> olarak adland\u0131rabilir ve her bir g\u00f6rev i\u00e7in bir ba\u015fl\u0131k ve tamamlama durumu tutabiliriz. B\u00f6ylece, kullan\u0131c\u0131lar yeni g\u00f6revler ekleyebilir, mevcut g\u00f6revleri g\u00fcncelleyebilir veya tamamlanan g\u00f6revleri silebilirler. Bu, Node.js ve Express ile dinamik bir veri y\u00f6netim sistemi olu\u015fturman\u0131n temelini olu\u015fturur.<\/p>\n<h2>G\u00fcvenlik ve Kimlik Do\u011frulama: API'mizi Yetkisiz Eri\u015fimden Nas\u0131l Koruruz?<\/h2>\n<p>Bir REST API geli\u015ftirmek sadece veri ak\u0131\u015f\u0131n\u0131 sa\u011flamakla bitmez; ayn\u0131 zamanda bu veriyi yetkisiz eri\u015fime kar\u015f\u0131 korumak da kritik \u00f6neme sahiptir. Kullan\u0131c\u0131lar\u0131n kimli\u011fini do\u011frulamak (Authentication) ve neye eri\u015febileceklerini belirlemek (Authorization), modern API'lerin olmazsa olmazlar\u0131ndand\u0131r. Bu b\u00f6l\u00fcmde, kullan\u0131c\u0131 kayd\u0131, giri\u015fi ve JSON Web Tokens (JWT) kullanarak API'mizi nas\u0131l g\u00fcvenli hale getirece\u011fimizi inceleyece\u011fiz.<\/p>\n<h3>JSON Web Tokens (JWT) Nedir ve Neden Kullan\u0131r\u0131z?<\/h3>\n<p>JWT, JSON format\u0131nda bilgi i\u00e7eren, imzal\u0131 ve iste\u011fe ba\u011fl\u0131 olarak \u015fifrelenmi\u015f bir standartt\u0131r. Genellikle istemci ile sunucu aras\u0131nda g\u00fcvenli bir \u015fekilde bilgi al\u0131\u015fveri\u015fi yapmak i\u00e7in kullan\u0131l\u0131r. Bir kullan\u0131c\u0131 giri\u015f yapt\u0131\u011f\u0131nda, sunucu bir JWT olu\u015fturur ve bu token'\u0131 istemciye geri g\u00f6nderir. \u0130stemci, sonraki her istekte bu token'\u0131 iste\u011fin ba\u015fl\u0131k k\u0131sm\u0131na (genellikle Authorization ba\u015fl\u0131\u011f\u0131 alt\u0131nda \"Bearer\" \u015femas\u0131yla) ekler. Sunucu, gelen her istekte token'\u0131 do\u011frulayarak kullan\u0131c\u0131n\u0131n kimli\u011fini ve yetkisini anlar. JWT'nin avantajlar\u0131 aras\u0131nda \u015funlar bulunur:<\/p>\n<ul>\n<li><strong>Durumsuzluk:<\/strong> Sunucuda oturum bilgisi tutmaya gerek kalmaz, bu da API'nin \u00f6l\u00e7eklenebilirli\u011fini art\u0131r\u0131r.<\/li>\n<li><strong>Verimli:<\/strong> K\u00fc\u00e7\u00fck ve hafiftirler, a\u011f trafi\u011fini azalt\u0131r.<\/li>\n<li><strong>G\u00fcvenli:<\/strong> Dijital olarak imzaland\u0131klar\u0131 i\u00e7in de\u011fi\u015ftirilemedikleri garanti edilir (ancak i\u00e7erdikleri veriler \u015fifrelenmedi\u011fi s\u00fcrece okunabilir).<\/li>\n<\/ul>\n<h3>Kullan\u0131c\u0131 Modeli ve \u015eifreleme (Bcrypt)<\/h3>\n<p>Kullan\u0131c\u0131 verilerini veritaban\u0131nda saklamadan \u00f6nce \u015fifrelerini g\u00fcvenli bir \u015fekilde hash'lemeliyiz. Bunun i\u00e7in <code>bcrypt.js<\/code> k\u00fct\u00fcphanesini kullanaca\u011f\u0131z:<\/p>\n<pre><code class=\"language-bash\">\nnpm install bcryptjs jsonwebtoken\n<\/pre>\n<p><\/code><\/p>\n<p>\u015eimdi bir <code>User<\/code> modeli tan\u0131mlayal\u0131m ve \u015fifre hash'leme logic'ini ekleyelim:<\/p>\n<pre><code class=\"language-javascript\">\n\/\/ models\/User.js (ayr\u0131 bir dosya olu\u015fturmak daha d\u00fczenli olacakt\u0131r)\nconst mongoose = require('mongoose');\nconst bcrypt = require('bcryptjs'); \/\/ \u015eifreleri hashlemek i\u00e7in\n\nconst UserSchema = new mongoose.Schema({\n  username: {\n    type: String,\n    required: true,\n    unique: true,\n    trim: true\n  },\n  email: {\n    type: String,\n    required: true,\n    unique: true,\n    trim: true,\n    lowercase: true\n  },\n  password: {\n    type: String,\n    required: true\n  },\n  createdAt: {\n    type: Date,\n    default: Date.now\n  }\n});\n\n\/\/ \u015eifreyi kaydetmeden veya g\u00fcncellemeden \u00f6nce hash'le\nUserSchema.pre('save', async function(next) {\n  if (!this.isModified('password')) { \/\/ \u015eifre de\u011fi\u015fmediyse, hash'lemeye gerek yok\n    return next();\n  }\n  const salt = await bcrypt.genSalt(10); \/\/ Tuz olu\u015ftur\n  this.password = await bcrypt.hash(this.password, salt); \/\/ \u015eifreyi hash'le\n  next();\n});\n\n\/\/ \u015eifre kar\u015f\u0131la\u015ft\u0131rma metodu\nUserSchema.methods.comparePassword = async function(candidatePassword) {\n  return bcrypt.compare(candidatePassword, this.password);\n};\n\nmodule.exports = mongoose.model('User', UserSchema);\n<\/pre>\n<p><\/code><\/p>\n<p>Bu <code>User.js<\/code> dosyas\u0131n\u0131 ana <code>app.js<\/code> dosyan\u0131za <code>const User = require('.\/models\/User');<\/code> \u015feklinde dahil etmeniz gerekecek. <code>pre(&#039;save&#039;)<\/code> hook'u sayesinde, her kullan\u0131c\u0131 kaydoldu\u011funda veya \u015fifresi g\u00fcncellendi\u011finde, \u015fifre otomatik olarak hash'lenecektir. <code>comparePassword<\/code> metodu ise giri\u015f s\u0131ras\u0131nda \u015fifreleri kar\u015f\u0131la\u015ft\u0131rmak i\u00e7in kullan\u0131lacakt\u0131r.<\/p>\n<h3>Kay\u0131t ve Giri\u015f Endpoint'leri Olu\u015fturma<\/h3>\n<p>\u015eimdi kullan\u0131c\u0131lar\u0131n kay\u0131t olabilece\u011fi ve giri\u015f yapabilece\u011fi endpoint'leri olu\u015ftural\u0131m. Bu endpoint'lerde JWT olu\u015fturulacak ve d\u00f6nd\u00fcr\u00fclecektir. <code>app.js<\/code> dosyan\u0131za ekleyin:<\/p>\n<pre><code class=\"language-javascript\">\n\/\/ app.js dosyan\u0131zda veya ayr\u0131 bir 'auth.js' y\u00f6nlendirici dosyas\u0131nda\nconst jwt = require('jsonwebtoken'); \/\/ JWT olu\u015fturmak ve do\u011frulamak i\u00e7in\nconst User = require('.\/models\/User'); \/\/ Daha \u00f6nce tan\u0131mlad\u0131\u011f\u0131m\u0131z User modelini dahil ediyoruz\n\n\/\/ JWT gizli anahtar\u0131n\u0131z, g\u00fc\u00e7l\u00fc ve rastgele bir anahtar olmal\u0131\nconst JWT_SECRET = process.env.JWT_SECRET || 'cokgizli_bir_anahtar'; \n\n\/\/ Yeni kullan\u0131c\u0131 kayd\u0131\napp.post('\/api\/auth\/register', async (req, res) => {\n  try {\n    const { username, email, password } = req.body;\n\n    \/\/ Kullan\u0131c\u0131 ad\u0131 veya e-posta zaten mevcut mu kontrol et\n    let user = await User.findOne({ $or: [{ username }, { email }] });\n    if (user) {\n      return res.status(400).json({ message: 'Bu kullan\u0131c\u0131 ad\u0131 veya e-posta zaten kullan\u0131mda.' });\n    }\n\n    user = new User({ username, email, password });\n    await user.save(); \/\/ \u015eifre otomatik olarak hash'lenecek\n\n    \/\/ JWT olu\u015ftur\n    const token = jwt.sign({ userId: user._id }, JWT_SECRET, { expiresIn: '1h' });\n\n    res.status(201).json({ message: 'Kullan\u0131c\u0131 ba\u015far\u0131yla kaydedildi.', token });\n  } catch (err) {\n    res.status(500).json({ message: err.message });\n  }\n});\n\n\/\/ Kullan\u0131c\u0131 giri\u015fi\napp.post('\/api\/auth\/login', async (req, res) => {\n  try {\n    const { email, password } = req.body;\n\n    \/\/ E-posta ile kullan\u0131c\u0131y\u0131 bul\n    const user = await User.findOne({ email });\n    if (!user) {\n      return res.status(400).json({ message: 'Ge\u00e7ersiz kimlik bilgileri.' });\n    }\n\n    \/\/ \u015eifreyi kar\u015f\u0131la\u015ft\u0131r\n    const isMatch = await user.comparePassword(password);\n    if (!isMatch) {\n      return res.status(400).json({ message: 'Ge\u00e7ersiz kimlik bilgileri.' });\n    }\n\n    \/\/ JWT olu\u015ftur\n    const token = jwt.sign({ userId: user._id }, JWT_SECRET, { expiresIn: '1h' });\n\n    res.json({ message: 'Ba\u015far\u0131yla giri\u015f yap\u0131ld\u0131.', token });\n  } catch (err) {\n    res.status(500).json({ message: err.message });\n  }\n});\n<\/pre>\n<p><\/code><\/p>\n<h3>JWT Do\u011frulama Middleware'i Olu\u015fturma<\/h3>\n<p>\u015eimdi, belirli endpoint'leri korumak i\u00e7in bir middleware (ara yaz\u0131l\u0131m) olu\u015ftural\u0131m. Bu middleware, her istekte token'\u0131 do\u011frulayacak ve kullan\u0131c\u0131 bilgilerini <code>req<\/code> objesine ekleyecektir:<\/p>\n<pre><code class=\"language-javascript\">\n\/\/ middleware\/auth.js (ayr\u0131 bir dosya)\nconst jwt = require('jsonwebtoken');\nconst JWT_SECRET = process.env.JWT_SECRET || 'cokgizli_bir_anahtar'; \n\nconst authMiddleware = (req, res, next) => {\n  \/\/ Authorization ba\u015fl\u0131\u011f\u0131ndan token'\u0131 al\n  const token = req.header('Authorization');\n\n  \/\/ Token yoksa yetkisiz eri\u015fim d\u00f6nd\u00fcr\n  if (!token) {\n    return res.status(401).json({ message: 'Eri\u015fim reddedildi, token bulunamad\u0131.' });\n  }\n\n  try {\n    \/\/ \"Bearer TOKEN_STRING\" format\u0131ndan token'\u0131 ay\u0131r\n    const actualToken = token.split(' ')[1]; \n    if (!actualToken) {\n        return res.status(401).json({ message: 'Ge\u00e7ersiz token format\u0131.' });\n    }\n\n    \/\/ Token'\u0131 do\u011frula\n    const decoded = jwt.verify(actualToken, JWT_SECRET);\n    req.userId = decoded.userId; \/\/ Kullan\u0131c\u0131 ID'sini req objesine ekle\n    next(); \/\/ Bir sonraki middleware veya route handler'a ge\u00e7\n  } catch (err) {\n    res.status(401).json({ message: 'Ge\u00e7ersiz token.' }); \/\/ Token ge\u00e7ersizse\n  }\n};\n\nmodule.exports = authMiddleware;\n<\/pre>\n<p><\/code><\/p>\n<p>Bu middleware'i <code>app.js<\/code> dosyan\u0131za dahil edin: <code>const auth = require('.\/middleware\/auth');<\/code><\/p>\n<h3>Korunan Endpoint'ler<\/h3>\n<p>Art\u0131k herhangi bir endpoint'i bu middleware ile koruyabiliriz. \u00d6rne\u011fin, <code>\/api\/items<\/code> rotalar\u0131m\u0131z\u0131n sadece giri\u015f yapm\u0131\u015f kullan\u0131c\u0131lar taraf\u0131ndan eri\u015filebilir olmas\u0131n\u0131 istiyorsak:<\/p>\n<pre><code class=\"language-javascript\">\n\/\/ ... Di\u011fer t\u00fcm kodlar\u0131n \u00fcst\u00fcnde auth middleware'\u0131n\u0131 dahil edin ...\nconst auth = require('.\/middleware\/auth');\n\n\/\/ Korunan bir rota \u00f6rne\u011fi: Sadece giri\u015f yapm\u0131\u015f kullan\u0131c\u0131lar kendi \u00f6\u011felerini g\u00f6rebilir\napp.get('\/api\/protected-items', auth, async (req, res) => {\n    try {\n        \/\/ req.userId sayesinde, bu kullan\u0131c\u0131n\u0131n ID'sine eri\u015febiliriz\n        \/\/ const userItems = await Item.find({ userId: req.userId }); \/\/ E\u011fer Item modelinde userId alan\u0131 olsayd\u0131\n        res.json({ message: <code>Ho\u015f geldiniz, kullan\u0131c\u0131 ID&#039;niz: ${req.userId}. Buras\u0131 korunan bir alan.<\/code> });\n    } catch (err) {\n        res.status(500).json({ message: err.message });\n    }\n});\n\n\/\/ Mevcut GET \/api\/items rotas\u0131n\u0131 korumak i\u00e7in\napp.get('\/api\/items', auth, async (req, res) => {\n    try {\n        const items = await Item.find(); \n        res.json(items);\n    } catch (err) {\n        res.status(500).json({ message: err.message });\n    }\n});\n\/\/ Ayn\u0131 \u015fekilde POST, PUT, DELETE rotalar\u0131n\u0131 da koruyabilirsiniz:\napp.post('\/api\/items', auth, async (req, res) => { \/* ... *\/ });\napp.put('\/api\/items\/:id', auth, async (req, res) => { \/* ... *\/ });\napp.delete('\/api\/items\/:id', auth, async (req, res) => { \/* ... *\/ });\n\n\/\/ ... app.listen k\u0131sm\u0131 ...\n<\/pre>\n<p><\/code><\/p>\n<p>Bu \u015fekilde, API'mize yetkisiz eri\u015fimi engelleyebilir ve sadece kimli\u011fi do\u011frulanm\u0131\u015f kullan\u0131c\u0131lar\u0131n belirli kaynaklara eri\u015fmesine izin verebiliriz. <code>JWT_SECRET<\/code> gibi hassas bilgileri do\u011frudan kod i\u00e7ine yazmak yerine ortam de\u011fi\u015fkenleri olarak tutmak \u00f6nemlidir, bu konuya \"Da\u011f\u0131t\u0131m ve \u00d6l\u00e7eklendirme\" b\u00f6l\u00fcm\u00fcnde de\u011finece\u011fiz. Bu yap\u0131, hem g\u00fcvenlik hem de \u00f6l\u00e7eklenebilirlik a\u00e7\u0131s\u0131ndan modern bir API'nin temelini olu\u015fturur. \u00d6rne\u011fin, bir blog platformunda, sadece giri\u015f yapm\u0131\u015f kullan\u0131c\u0131lar yeni bir makale yay\u0131nlayabilir veya mevcut makaleleri g\u00fcncelleyebilirken, herkes makaleleri okuyabilir. Bu ayr\u0131m, JWT ve middleware'ler arac\u0131l\u0131\u011f\u0131yla kolayca sa\u011flan\u0131r.<\/p>\n<h2>Hata Y\u00f6netimi ve Giri\u015f Do\u011frulama: Sa\u011flam Bir API \u0130\u00e7in Olmazsa Olmazlar<\/h2>\n<p>Bir API geli\u015ftirirken, beklenmedik durumlar\u0131 (\u00f6rne\u011fin, ge\u00e7ersiz kullan\u0131c\u0131 giri\u015fi, veritaban\u0131 ba\u011flant\u0131 sorunlar\u0131, bulunamayan kaynaklar) do\u011fru bir \u015fekilde ele almak hayati \u00f6nem ta\u015f\u0131r. Etkili <strong>hata y\u00f6netimi<\/strong> ve <strong>giri\u015f do\u011frulama<\/strong>, hem API'nizin kullan\u0131c\u0131 dostu olmas\u0131n\u0131 sa\u011flar hem de geli\u015ftiricilerin hatalar\u0131 daha kolay tespit etmesine yard\u0131mc\u0131 olur. Yanl\u0131\u015f veya eksik veri giri\u015fi, API'nin istikrars\u0131z \u00e7al\u0131\u015fmas\u0131na veya g\u00fcvenlik a\u00e7\u0131klar\u0131na yol a\u00e7abilir. Bu nedenle, kullan\u0131c\u0131dan gelen her veriyi dikkatlice do\u011frulamak ve sistemin belirli bir \u015fekilde yan\u0131t vermesini sa\u011flamak \u00f6nemlidir.<\/p>\n<h3>Giri\u015f Do\u011frulama (Input Validation)<\/h3>\n<p>Kullan\u0131c\u0131dan gelen verilerin (<code>req.body<\/code>, <code>req.params<\/code>, <code>req.query<\/code>) bekledi\u011fimiz formatta ve i\u00e7erikte olup olmad\u0131\u011f\u0131n\u0131 kontrol etmek, API'mizi g\u00fcvende tutman\u0131n ilk ad\u0131m\u0131d\u0131r. Express ekosisteminde bunun i\u00e7in kullanabilece\u011fimiz pop\u00fcler k\u00fct\u00fcphanelerden biri <code>express-validator<\/code>'d\u0131r. Bu k\u00fct\u00fcphane, verileri do\u011frulamak ve temizlemek i\u00e7in esnek ve g\u00fc\u00e7l\u00fc bir ara\u00e7 seti sunar.<\/p>\n<pre><code class=\"language-bash\">\nnpm install express-validator\n<\/pre>\n<p><\/code><\/p>\n<p>\u015eimdi, <code>\/api\/auth\/register<\/code> endpoint'imizi <code>express-validator<\/code> ile g\u00fc\u00e7lendirelim. <code>app.js<\/code> dosyan\u0131zdaki ilgili yere a\u015fa\u011f\u0131daki gibi eklemeler yapabilirsiniz:<\/p>\n<pre><code class=\"language-javascript\">\n\/\/ app.js dosyan\u0131z\u0131n ba\u015f\u0131nda veya ayr\u0131 bir validation middleware dosyas\u0131nda\nconst { body, validationResult } = require('express-validator');\n\n\/\/ ...\n\n\/\/ Yeni kullan\u0131c\u0131 kayd\u0131 (giri\u015f do\u011frulama ile)\napp.post('\/api\/auth\/register', [\n  body('username').trim().isLength({ min: 3 }).withMessage('Kullan\u0131c\u0131 ad\u0131 en az 3 karakter olmal\u0131d\u0131r.'),\n  body('email').isEmail().withMessage('Ge\u00e7erli bir e-posta adresi girin.'),\n  body('password').isLength({ min: 6 }).withMessage('\u015eifre en az 6 karakter olmal\u0131d\u0131r.')\n], async (req, res) => {\n  \/\/ Do\u011frulama hatalar\u0131n\u0131 kontrol et\n  const errors = validationResult(req);\n  if (!errors.isEmpty()) {\n    return res.status(400).json({ errors: errors.array() }); \/\/ Hatalar\u0131 JSON olarak d\u00f6nd\u00fcr\n  }\n\n  try {\n    const { username, email, password } = req.body;\n    let user = await User.findOne({ $or: [{ username }, { email }] });\n    if (user) {\n      return res.status(400).json({ message: 'Bu kullan\u0131c\u0131 ad\u0131 veya e-posta zaten kullan\u0131mda.' });\n    }\n\n    user = new User({ username, email, password });\n    await user.save(); \n\n    const token = jwt.sign({ userId: user._id }, JWT_SECRET, { expiresIn: '1h' });\n    res.status(201).json({ message: 'Kullan\u0131c\u0131 ba\u015far\u0131yla kaydedildi.', token });\n  } catch (err) {\n    res.status(500).json({ message: err.message });\n  }\n});\n\n\/\/ ...\n<\/pre>\n<p><\/code><\/p>\n<p>Bu \u00f6rnekte, <code>body()<\/code> fonksiyonlar\u0131 ile her bir alan i\u00e7in do\u011frulama kurallar\u0131 tan\u0131mlad\u0131k (<code>trim<\/code>, <code>isLength<\/code>, <code>isEmail<\/code>). E\u011fer do\u011frulama ba\u015far\u0131s\u0131z olursa, <code>validationResult(req)<\/code> ile hatalar\u0131 yakalay\u0131p istemciye <code>400 Bad Request<\/code> durumuyla birlikte d\u00f6neriz. Bu, istemcinin hangi alanda hata yapt\u0131\u011f\u0131n\u0131 anlamas\u0131na yard\u0131mc\u0131 olur ve gereksiz veritaban\u0131 i\u015flemlerini \u00f6nler.<\/p>\n<div class=\"interactive-element expert-tip\">\n  Uzman \u0130pucu: Karma\u015f\u0131k do\u011frulama kurallar\u0131 i\u00e7in \u00f6zel bir middleware dosyas\u0131 olu\u015fturarak kodunuzu daha okunabilir hale getirebilirsiniz. \u00d6rne\u011fin, <code>middleware\/validation.js<\/code> i\u00e7inde t\u00fcm do\u011frulama mant\u0131\u011f\u0131n\u0131 toplay\u0131p router'lar\u0131n\u0131zda kullanabilirsiniz.\n<\/div>\n<h3>Etkili Hata Y\u00f6netimi (Error Handling)<\/h3>\n<p>Express'te hata y\u00f6netimi i\u00e7in \u00f6zel bir t\u00fcr middleware kullan\u0131l\u0131r: d\u00f6rt arg\u00fcman alan bir fonksiyon (<code>(err, req, res, next) => { ... }<\/code>). Bu middleware'ler, bir route handler'\u0131 veya ba\u015fka bir middleware i\u00e7inde bir hata olu\u015ftu\u011funda tetiklenir ve hatay\u0131 merkezi bir noktadan yakalay\u0131p i\u015fleyebiliriz. B\u00f6ylece, her route i\u00e7inde tekrar tekrar <code>try-catch<\/code> bloklar\u0131 yazmaktan kurtuluruz ve tutarl\u0131 hata yan\u0131tlar\u0131 sa\u011flayabiliriz.<\/p>\n<p><code>app.js<\/code> dosyan\u0131z\u0131n en alt\u0131na, <code>app.listen()<\/code> \u00e7a\u011fr\u0131s\u0131ndan hemen \u00f6nce a\u015fa\u011f\u0131daki hata yakalama middleware'ini ekleyin:<\/p>\n<pre><code class=\"language-javascript\">\n\/\/ app.js dosyas\u0131n\u0131n en alt\u0131nda, t\u00fcm rotalardan sonra ekleyin\n\n\/\/ Hata yakalama middleware'i\napp.use((err, req, res, next) => {\n  console.error(err.stack); \/\/ Hata detaylar\u0131n\u0131 sunucu konsolunda logla\n\n  \/\/ \u00d6zel hata s\u0131n\u0131flar\u0131 veya belirli hata t\u00fcrleri i\u00e7in farkl\u0131 yan\u0131tlar verebiliriz\n  if (err.name === 'ValidationError') { \/\/ Mongoose do\u011frulama hatalar\u0131 i\u00e7in\n    return res.status(400).json({ \n      message: 'Do\u011frulama hatas\u0131', \n      errors: Object.values(err.errors).map(e => e.message) \n    });\n  }\n  if (err.name === 'CastError' && err.kind === 'ObjectId') { \/\/ Ge\u00e7ersiz MongoDB ID'leri i\u00e7in\n    return res.status(400).json({ message: 'Ge\u00e7ersiz ID format\u0131.' });\n  }\n  \n  \/\/ Varsay\u0131lan hata yan\u0131t\u0131\n  res.status(500).json({ message: 'Sunucu hatas\u0131 olu\u015ftu.' });\n});\n\n\/\/ Bilinmeyen rotalar\u0131 ele almak i\u00e7in (404 Not Found)\napp.use((req, res, next) => {\n  res.status(404).json({ message: 'Arad\u0131\u011f\u0131n\u0131z rota bulunamad\u0131.' });\n});\n\n\/\/ ... app.listen k\u0131sm\u0131 ...\n<\/pre>\n<p><\/code><\/p>\n<p>Bu hata yakalama middleware'i \u015funlar\u0131 yapar:<\/p>\n<ul>\n<li><code>console.error(err.stack);<\/code>: Sunucu taraf\u0131nda hatan\u0131n tam izini (stack trace) loglar, bu da debugging i\u00e7in \u00e7ok \u00f6nemlidir. Bu loglar\u0131 \u00fcretimde bir loglama servisine (\u00f6rne\u011fin, Sentry, ELK Stack) g\u00f6ndermek isteyebilirsiniz.<\/li>\n<li>Mongoose'un otomatik olarak f\u0131rlatt\u0131\u011f\u0131 <code>ValidationError<\/code> veya <code>CastError<\/code> gibi spesifik hatalar\u0131 tan\u0131yarak, istemciye daha anlaml\u0131 yan\u0131tlar d\u00f6nd\u00fcr\u00fcr. \u00d6rne\u011fin, bir kullan\u0131c\u0131n\u0131n ge\u00e7ersiz bir ID ile bir \u00f6\u011feyi aramas\u0131n\u0131 engeller ve daha a\u00e7\u0131klay\u0131c\u0131 bir mesaj sunar.<\/li>\n<li>Di\u011fer t\u00fcm beklenmeyen hatalar i\u00e7in genel bir <code>500 Internal Server Error<\/code> yan\u0131t\u0131 d\u00f6nd\u00fcr\u00fcr. Bu, hassas sunucu bilgilerinin istemciye s\u0131zmas\u0131n\u0131 engeller.<\/li>\n<li>En son <code>app.use((req, res, next) => { ... });<\/code> blo\u011fu, Express'in hi\u00e7bir \u00f6nceki rotay\u0131 e\u015fle\u015ftiremedi\u011fi durumlarda devreye girer ve <code>404 Not Found<\/code> yan\u0131t\u0131 d\u00f6nd\u00fcr\u00fcr. Bu, API'nizin bilinmeyen URL'lere kar\u015f\u0131 da tutarl\u0131 yan\u0131tlar vermesini sa\u011flar.<\/li>\n<\/ul>\n<p>Bu iki bile\u015feni (giri\u015f do\u011frulama ve merkezi hata y\u00f6netimi) API'nize entegre ederek, hem geli\u015ftirme s\u00fcrecinde hatalar\u0131 daha kolay yakalar hem de son kullan\u0131c\u0131ya daha g\u00fcvenilir ve tahmin edilebilir bir deneyim sunars\u0131n\u0131z. \u00d6rne\u011fin, bir bankac\u0131l\u0131k uygulamas\u0131nda hatal\u0131 bir para transferi iste\u011fi geldi\u011finde, API'nin hem istemciyi do\u011fru hata kodu ve mesaj\u0131yla uyarmas\u0131 hem de sunucu taraf\u0131nda bu hatay\u0131 g\u00fcvenli bir \u015fekilde kaydetmesi hayati \u00f6neme sahiptir.<\/p>\n<h2>API Belgelendirme ve Test Etme: Geli\u015ftirici Deneyimini Nas\u0131l \u0130yile\u015ftiririz?<\/h2>\n<p>Bir REST API'yi ba\u015far\u0131l\u0131 bir \u015fekilde olu\u015fturmak kadar, onu ba\u015fkalar\u0131 (veya gelecekteki siz) taraf\u0131ndan anla\u015f\u0131l\u0131r, kullan\u0131labilir ve bak\u0131m\u0131 yap\u0131labilir k\u0131lmak da \u00f6nemlidir. Bu noktada <strong>API belgelendirme<\/strong> ve <strong>test etme<\/strong> devreye girer. \u0130yi belgelenmi\u015f bir API, geli\u015ftiricilerin onu kolayca entegre etmesini sa\u011flarken, kapsaml\u0131 testler API'nin do\u011fru ve hatas\u0131z \u00e7al\u0131\u015ft\u0131\u011f\u0131n\u0131 garanti eder.<\/p>\n<h3>API Belgelendirme: Swagger\/OpenAPI ile Kolayla\u015ft\u0131rma<\/h3>\n<p>API belgelendirmesi, endpoint'lerin ne i\u015f yapt\u0131\u011f\u0131n\u0131, hangi parametreleri bekledi\u011fini, hangi yan\u0131tlar\u0131 d\u00f6nd\u00fcrebilece\u011fini ve hangi HTTP durum kodlar\u0131n\u0131 kullanabilece\u011fini a\u00e7\u0131klayan bir k\u0131lavuzdur. Manuel olarak belge yazmak zahmetli ve g\u00fcncel tutmas\u0131 zorken, Swagger (\u015fimdiki ad\u0131yla OpenAPI Specification) bu s\u00fcreci otomatikle\u015ftiren pop\u00fcler bir \u00e7\u00f6z\u00fcmd\u00fcr. OpenAPI, API'nizin yap\u0131s\u0131n\u0131 standart, dilden ba\u011f\u0131ms\u0131z bir formatta tan\u0131mlaman\u0131z\u0131 sa\u011flar ve Swagger UI gibi ara\u00e7lar bu tan\u0131m\u0131 etkile\u015fimli, web tabanl\u0131 bir belgeye d\u00f6n\u00fc\u015ft\u00fcr\u00fcr.<\/p>\n<p>Express projenizde Swagger'\u0131 kullanmak i\u00e7in <code>swagger-ui-express<\/code> ve <code>swagger-jsdoc<\/code> gibi k\u00fct\u00fcphaneleri kullanabiliriz:<\/p>\n<pre><code class=\"language-bash\">\nnpm install swagger-ui-express swagger-jsdoc\n<\/pre>\n<p><\/code><\/p>\n<p><code>app.js<\/code> dosyan\u0131zda veya ayr\u0131 bir <code>swagger.js<\/code> dosyas\u0131nda Swagger yap\u0131land\u0131rmas\u0131n\u0131 yapal\u0131m:<\/p>\n<pre><code class=\"language-javascript\">\n\/\/ app.js i\u00e7inde veya ayr\u0131 bir swaggerConfig.js dosyas\u0131nda\nconst swaggerUi = require('swagger-ui-express');\nconst swaggerJsdoc = require('swagger-jsdoc');\n\n\/\/ Swagger\/OpenAPI tan\u0131mlamas\u0131\nconst swaggerOptions = {\n  definition: {\n    openapi: '3.0.0', \/\/ OpenAPI s\u00fcr\u00fcm\u00fc\n    info: {\n      title: 'Node.js Express API Dok\u00fcmantasyonu',\n      version: '1.0.0',\n      description: 'S\u0131f\u0131rdan \u00dcretime Node.js ve Express API rehberi i\u00e7in \u00f6rnek API dok\u00fcmantasyonu.',\n      contact: {\n        name: 'Geli\u015ftirici Ekibi',\n        email: 'developer@example.com'\n      }\n    },\n    servers: [\n      {\n        url: 'http:\/\/localhost:3000', \/\/ API'nizin \u00e7al\u0131\u015ft\u0131\u011f\u0131 temel URL\n        description: 'Yerel Geli\u015ftirme Sunucusu'\n      }\n    ],\n    components: {\n        securitySchemes: {\n            bearerAuth: { \/\/ JWT i\u00e7in bir g\u00fcvenlik \u015femas\u0131 tan\u0131ml\u0131yoruz\n                type: 'http',\n                scheme: 'bearer',\n                bearerFormat: 'JWT'\n            }\n        }\n    },\n    security: [{\n        bearerAuth: [] \/\/ Varsay\u0131lan olarak t\u00fcm rotalar\u0131n JWT ile korunaca\u011f\u0131n\u0131 belirtiriz\n    }]\n  },\n  \/\/ API belgelerini olu\u015fturmak i\u00e7in hangi dosyalar\u0131 tarayaca\u011f\u0131n\u0131 belirtiyoruz\n  apis: ['.\/app.js', '.\/routes\/*.js'], \/\/ app.js ve routes klas\u00f6r\u00fcndeki t\u00fcm JS dosyalar\u0131\n};\n\nconst swaggerSpec = swaggerJsdoc(swaggerOptions);\n\n\/\/ Swagger UI'\u0131 \/api-docs adresinde aktif ediyoruz\napp.use('\/api-docs', swaggerUi.serve, swaggerUi.setup(swaggerSpec));\n\n\/\/ Rotan\u0131z\u0131n ba\u015f\u0131na Swagger yorumlar\u0131n\u0131 ekleyebilirsiniz. \u00d6rne\u011fin, \/api\/items POST i\u00e7in:\n\/**\n * @swagger\n * \/api\/items:\n *   post:\n *     summary: Yeni bir \u00f6\u011fe olu\u015fturur\n *     tags: [Items]\n *     security:\n *       - bearerAuth: []\n *     requestBody:\n *       required: true\n *       content:\n *         application\/json:\n *           schema:\n *             type: object\n *             required:\n *               - name\n *             properties:\n *               name:\n *                 type: string\n *                 description: \u00d6\u011fenin ad\u0131\n *               description:\n *                 type: string\n *                 description: \u00d6\u011fenin a\u00e7\u0131klamas\u0131\n *     responses:\n *       201:\n *         description: \u00d6\u011fe ba\u015far\u0131yla olu\u015fturuldu\n *         content:\n *           application\/json:\n *             schema:\n *               type: object\n *               properties:\n *                 _id:\n *                   type: string\n *                 name:\n *                   type: string\n *                 description:\n *                   type: string\n *       400:\n *         description: Ge\u00e7ersiz istek\n *\/\n\/\/ Yukar\u0131daki yorum blo\u011funu app.js'deki app.post('\/api\/items', ...) rotan\u0131z\u0131n hemen \u00fcst\u00fcne ekleyin.\n<\/pre>\n<p><\/code><\/p>\n<p>Sunucuyu \u00e7al\u0131\u015ft\u0131rd\u0131\u011f\u0131n\u0131zda (<code>npm run dev<\/code>), taray\u0131c\u0131n\u0131zdan <code>http:\/\/localhost:3000\/api-docs<\/code> adresine giderek etkile\u015fimli API belgelerinizi g\u00f6rebilirsiniz. Bu, API'nizi kullanan di\u011fer geli\u015ftiriciler i\u00e7in paha bi\u00e7ilmez bir kaynakt\u0131r.<\/p>\n<h3>API Test Etme: Postman ve Otomatik Testler (Jest, Supertest)<\/h3>\n<p>API'nizi geli\u015ftirdik\u00e7e ve yeni \u00f6zellikler ekledik\u00e7e, her \u015feyin beklendi\u011fi gibi \u00e7al\u0131\u015ft\u0131\u011f\u0131ndan emin olmak i\u00e7in testler yapman\u0131z gerekir. \u0130ki ana test t\u00fcr\u00fc vard\u0131r:<\/p>\n<h4>1. Manuel Testler (Postman, Insomnia)<\/h4>\n<p>Geli\u015ftirme s\u0131ras\u0131nda endpoint'leri h\u0131zl\u0131ca test etmek i\u00e7in Postman veya Insomnia gibi ara\u00e7lar kullan\u0131\u015fl\u0131d\u0131r. Bu ara\u00e7lar, HTTP istekleri olu\u015fturman\u0131za, farkl\u0131 HTTP metodlar\u0131n\u0131 (GET, POST, PUT, DELETE) kullanman\u0131za, istek g\u00f6vdesine veri eklemenize, ba\u015fl\u0131klar\u0131 ayarlaman\u0131za ve yan\u0131tlar\u0131 incelemenize olanak tan\u0131r. \u00d6zellikle yeni bir endpoint yazarken veya bir hatay\u0131 ay\u0131klarken bu ara\u00e7lar olduk\u00e7a zaman kazand\u0131r\u0131r.<\/p>\n<p>Bir Postman \u00f6rne\u011fi i\u00e7in, <code>POST \/api\/auth\/register<\/code> iste\u011fi atarken, \"Body\" sekmesinden \"raw\" ve \"JSON\" se\u00e7ene\u011fini i\u015faretleyerek a\u015fa\u011f\u0131daki gibi bir JSON g\u00f6nderebilirsiniz:<\/p>\n<pre><code class=\"language-json\">\n{\n  \"username\": \"testuser123\",\n  \"email\": \"test@example.com\",\n  \"password\": \"password123\"\n}\n<\/pre>\n<p><\/code><\/p>\n<p>G\u00f6nderdi\u011finizde <code>201 Created<\/code> yan\u0131t\u0131 ve bir JWT almal\u0131s\u0131n\u0131z. Bu JWT'yi kopyalay\u0131p di\u011fer korunan endpoint'lerde (\u00f6rne\u011fin <code>GET \/api\/items<\/code>) \"Authorization\" ba\u015fl\u0131\u011f\u0131 alt\u0131nda \"Bearer TOKEN_STRING\" format\u0131nda kullanabilirsiniz.<\/p>\n<h4>2. Otomatik Testler (Jest ve Supertest)<\/h4>\n<p>Manuel testler h\u0131zl\u0131 olsa da, her de\u011fi\u015fiklikte t\u00fcm API'yi elle test etmek s\u00fcrd\u00fcr\u00fclebilir de\u011fildir. Bu y\u00fczden otomatik testler \u00e7ok \u00f6nemlidir. <strong>Jest<\/strong>, bir JavaScript test \u00e7at\u0131s\u0131d\u0131r ve <strong>Supertest<\/strong> ise HTTP isteklerini kolayca test etmenizi sa\u011flayan bir k\u00fct\u00fcphanedir. Bu ikilinin kombinasyonu, API endpoint'lerinizin do\u011fru yan\u0131tlar d\u00f6nd\u00fcrd\u00fc\u011f\u00fcnden ve beklenmedik durumlar\u0131 do\u011fru bir \u015fekilde ele ald\u0131\u011f\u0131ndan emin olman\u0131z\u0131 sa\u011flar.<\/p>\n<pre><code class=\"language-bash\">\nnpm install --save-dev jest supertest\n<\/pre>\n<p><\/code><\/p>\n<p><code>package.json<\/code> dosyan\u0131za bir test komutu ekleyin:<\/p>\n<pre><code class=\"language-json\">\n{\n  \"scripts\": {\n    \"start\": \"node app.js\",\n    \"dev\": \"nodemon app.js\",\n    \"test\": \"jest\" \/\/ Yeni test komutu\n  },\n  \/\/ ...\n}\n<\/pre>\n<p><\/code><\/p>\n<p>Testlerinizi yazmaya ba\u015flamak i\u00e7in projenizin k\u00f6k dizininde bir <code>__tests__<\/code> klas\u00f6r\u00fc olu\u015fturun (veya <code>.test.js<\/code> uzant\u0131l\u0131 dosyalar kullan\u0131n) ve i\u00e7ine <code>items.test.js<\/code> gibi bir dosya olu\u015fturun:<\/p>\n<pre><code class=\"language-javascript\">\n\/\/ __tests__\/items.test.js\nconst request = require('supertest');\nconst app = require('..\/app'); \/\/ app.js dosyan\u0131z\u0131 buraya import etti\u011finizden emin olun\nconst mongoose = require('mongoose');\nconst Item = require('..\/models\/Item'); \/\/ Item modelinizi import edin\n\n\/\/ Testler ba\u015flamadan \u00f6nce veritaban\u0131 ba\u011flant\u0131s\u0131n\u0131 kur ve test verilerini temizle\nbeforeAll(async () => {\n  const dbURI = 'mongodb:\/\/localhost:27017\/test_db'; \/\/ Test i\u00e7in ayr\u0131 bir veritaban\u0131 kullan\u0131n\n  await mongoose.connect(dbURI, { useNewUrlParser: true, useUnifiedTopology: true });\n});\n\n\/\/ Her testten sonra veritaban\u0131n\u0131 temizle\nafterEach(async () => {\n  await Item.deleteMany({});\n});\n\n\/\/ T\u00fcm testler bittikten sonra veritaban\u0131 ba\u011flant\u0131s\u0131n\u0131 kapat\nafterAll(async () => {\n  await mongoose.connection.close();\n});\n\ndescribe('Item API', () => {\n  it('GET \/api\/items - T\u00fcm \u00f6\u011feleri getirmeli', async () => {\n    \/\/ \u00d6rnek olarak birka\u00e7 \u00f6\u011fe ekleyelim\n    await Item.create({ name: 'Test Item 1', description: 'Description 1' });\n    await Item.create({ name: 'Test Item 2', description: 'Description 2' });\n\n    const res = await request(app).get('\/api\/items');\n    expect(res.statusCode).toEqual(200);\n    expect(res.body).toHaveLength(2);\n    expect(res.body[0]).toHaveProperty('name', 'Test Item 1');\n  });\n\n  it('POST \/api\/items - Yeni bir \u00f6\u011fe olu\u015fturmal\u0131', async () => {\n    const newItem = { name: 'Yeni \u00d6\u011fe', description: 'Yeni \u00f6\u011fe a\u00e7\u0131klamas\u0131' };\n    const res = await request(app)\n      .post('\/api\/items')\n      .send(newItem);\n\n    expect(res.statusCode).toEqual(201);\n    expect(res.body).toHaveProperty('_id');\n    expect(res.body).toHaveProperty('name', 'Yeni \u00d6\u011fe');\n\n    const itemInDb = await Item.findById(res.body._id);\n    expect(itemInDb).not.toBeNull();\n    expect(itemInDb.name).toEqual('Yeni \u00d6\u011fe');\n  });\n\n  \/\/ Di\u011fer CRUD operasyonlar\u0131 i\u00e7in de testler yaz\u0131labilir (GET by ID, PUT, DELETE)\n});\n<\/pre>\n<p><\/code><\/p>\n<p><code>app.js<\/code> dosyan\u0131zda <code>module.exports = app;<\/code> sat\u0131r\u0131n\u0131 ekleyerek Express uygulaman\u0131z\u0131 test dosyalar\u0131n\u0131zdan import edilebilir hale getirmelisiniz. Art\u0131k terminalde <code>npm test<\/code> komutunu \u00e7al\u0131\u015ft\u0131rarak testlerinizi otomatik olarak \u00e7al\u0131\u015ft\u0131rabilirsiniz. Bu testler, API'nizin beklenen davran\u0131\u015flar\u0131 sergilemesini ve potansiyel hatalar\u0131 erken a\u015famada yakalaman\u0131z\u0131 sa\u011flar. \u00d6rne\u011fin, bir rezervasyon sistemi API'sinde, yeni bir rezervasyon olu\u015fturma endpoint'inin, mevcut bir \u00e7ak\u0131\u015fma durumunda do\u011fru hata koduyla yan\u0131t verdi\u011fini ve veritaban\u0131na yanl\u0131\u015f bilgi kaydetmedi\u011fini bu testlerle kolayca do\u011frulayabilirsiniz.<\/p>\n<h2>Da\u011f\u0131t\u0131m ve \u00d6l\u00e7eklendirme: API'mizi \u00dcretim Ortam\u0131na Nas\u0131l Ta\u015f\u0131r\u0131z?<\/h2>\n<p>API'nizi geli\u015ftirip test ettikten sonra, onu d\u00fcnya ile payla\u015fma zaman\u0131 gelir. Bir geli\u015ftirme ortam\u0131nda sorunsuz \u00e7al\u0131\u015fan bir API'nin, \u00fcretim ortam\u0131nda da ayn\u0131 performans\u0131 ve g\u00fcvenilirli\u011fi sergilemesi i\u00e7in do\u011fru da\u011f\u0131t\u0131m ve \u00f6l\u00e7eklendirme stratejileri uygulamak \u015fartt\u0131r. Bu b\u00f6l\u00fcm, API'nizi \u00fcretim ortam\u0131na ta\u015f\u0131mak i\u00e7in baz\u0131 temel ad\u0131mlar\u0131 ve en iyi uygulamalar\u0131 ele almaktad\u0131r.<\/p>\n<h3>1. Ortam De\u011fi\u015fkenleri ile G\u00fcvenli Yap\u0131land\u0131rma (<code>dotenv<\/code>)<\/h3>\n<p>Hassas bilgiler (veritaban\u0131 ba\u011flant\u0131 dizeleri, JWT gizli anahtarlar\u0131, API anahtarlar\u0131 vb.) do\u011frudan kod i\u00e7ine yaz\u0131lmamal\u0131d\u0131r. Bunun yerine, bu bilgileri ortam de\u011fi\u015fkenleri olarak saklamal\u0131 ve uygulaman\u0131z\u0131n \u00e7al\u0131\u015ft\u0131\u011f\u0131 ortama g\u00f6re dinamik olarak y\u00fcklemelisiniz. <code>dotenv<\/code> k\u00fct\u00fcphanesi, bu i\u015flemi Node.js uygulamalar\u0131 i\u00e7in basitle\u015ftirir.<\/p>\n<pre><code class=\"language-bash\">\nnpm install dotenv\n<\/pre>\n<p><\/code><\/p>\n<p>Projenizin k\u00f6k dizininde <code>.env<\/code> ad\u0131nda bir dosya olu\u015fturun ve hassas bilgilerinizi buraya yaz\u0131n:<\/p>\n<pre><code class=\"language-text\">\nPORT=3000\nMONGODB_URI=mongodb:\/\/localhost:27017\/myapi_db_prod\nJWT_SECRET=cok_daha_guclu_ve_rastgele_bir_anahtar_buraya\n<\/pre>\n<p><\/code><\/p>\n<p>Ard\u0131ndan, <code>app.js<\/code> dosyan\u0131z\u0131n en ba\u015f\u0131na (di\u011fer <code>require<\/code> \u00e7a\u011fr\u0131lar\u0131ndan \u00f6nce) <code>dotenv<\/code>'i y\u00fckleyin:<\/p>\n<pre><code class=\"language-javascript\">\nrequire('dotenv').config(); \/\/ En \u00fcste ekleyin\n\nconst express = require('express');\n\/\/ ...\n\nconst port = process.env.PORT || 3000;\nconst dbURI = process.env.MONGODB_URI || 'mongodb:\/\/localhost:27017\/myapi_db_dev';\nconst JWT_SECRET = process.env.JWT_SECRET || 'cokgizli_bir_anahtar'; \n\nmongoose.connect(dbURI, { \/* ... *\/ });\n\/\/ ...\n<\/pre>\n<p><\/code><\/p>\n<p>B\u00f6ylece, farkl\u0131 ortamlarda (geli\u015ftirme, test, \u00fcretim) farkl\u0131 yap\u0131land\u0131rmalar kullanabilir ve hassas bilgilerinizi versiyon kontrol sistemine (Git) dahil etmezsiniz. <strong><code>.env<\/code> dosyas\u0131n\u0131 <code>.gitignore<\/code> dosyan\u0131za eklemeyi unutmay\u0131n!<\/strong><\/p>\n<h3>2. Performans \u0130yile\u015ftirmeleri ve G\u00fcvenlik G\u00fc\u00e7lendirmeleri<\/h3>\n<ul>\n<li><strong>S\u0131k\u0131\u015ft\u0131rma (Compression):<\/strong> API yan\u0131tlar\u0131n\u0131n boyutunu k\u00fc\u00e7\u00fcltmek ve a\u011f trafi\u011fini azaltmak i\u00e7in s\u0131k\u0131\u015ft\u0131rma middleware'i kullan\u0131n. <code>compression<\/code> paketi bunun i\u00e7in idealdir:<\/li>\n<pre><code class=\"language-bash\">\nnpm install compression\n    <\/pre>\n<p><\/code><\/p>\n<pre><code class=\"language-javascript\"><\/pre>\n<p><\/code><br \/>\nconst compression = require('compression');<br \/>\napp.use(compression()); \/\/ T\u00fcm yan\u0131tlar\u0131 s\u0131k\u0131\u015ft\u0131r<br \/>\n    <\/code><\/p>\n<li><strong>G\u00fcvenlik Ba\u015fl\u0131klar\u0131 (Helmet):<\/strong> HTTP ba\u015fl\u0131klar\u0131n\u0131 ayarlayarak API'nizi yayg\u0131n web zay\u0131fl\u0131klar\u0131na kar\u015f\u0131 koruyun. <code>helmet<\/code> k\u00fct\u00fcphanesi bunun i\u00e7in bir dizi g\u00fcvenlik middleware'i sa\u011flar:<\/li>\n<pre><code class=\"language-bash\">\nnpm install helmet\n    <\/pre>\n<p><\/code><\/p>\n<pre><code class=\"language-javascript\"><\/pre>\n<p><\/code><br \/>\nconst helmet = require('helmet');<br \/>\napp.use(helmet()); \/\/ \u00c7e\u015fitli g\u00fcvenlik ba\u015fl\u0131klar\u0131n\u0131 ayarlar<br \/>\n    <\/code><\/p>\n<li><strong>CORS (Cross-Origin Resource Sharing):<\/strong> Farkl\u0131 bir alandan (\u00f6rne\u011fin, <code>frontend.com<\/code>) gelen isteklerin API'nize eri\u015fmesine izin vermek i\u00e7in CORS'u yap\u0131land\u0131rman\u0131z gerekebilir.<\/li>\n<pre><code class=\"language-bash\">\nnpm install cors\n    <\/pre>\n<p><\/code><\/p>\n<pre><code class=\"language-javascript\"><\/pre>\n<p><\/code><br \/>\nconst cors = require('cors');<br \/>\napp.use(cors()); \/\/ T\u00fcm kaynaklardan gelen isteklere izin verir (\u00fcretimde daha spesifik olmal\u0131)<br \/>\n\/\/ app.use(cors({ origin: 'https:\/\/www.guvenli-alan.com' })); \/\/ Sadece belirli bir alana izin ver<br \/>\n    <\/code>\n<\/ul>\n<h3>3. S\u00fcre\u00e7 Y\u00f6netimi (PM2)<\/h3>\n<p>Node.js uygulamalar\u0131 tek i\u015f par\u00e7ac\u0131kl\u0131 oldu\u011fundan, bir hata olu\u015ftu\u011funda uygulama tamamen \u00e7\u00f6kebilir. Ayr\u0131ca, sunucunuzun t\u00fcm CPU \u00e7ekirdeklerinden faydalanmak ve uygulamay\u0131 s\u00fcrekli \u00e7al\u0131\u015f\u0131r durumda tutmak i\u00e7in bir s\u00fcre\u00e7 y\u00f6neticisine (process manager) ihtiyac\u0131n\u0131z vard\u0131r. <strong>PM2<\/strong>, Node.js uygulamalar\u0131 i\u00e7in pop\u00fcler bir s\u00fcre\u00e7 y\u00f6neticisidir:<\/p>\n<pre><code class=\"language-bash\">\nnpm install -g pm2 # Global olarak kur\n<\/pre>\n<p><\/code><\/p>\n<p>Uygulaman\u0131z\u0131 ba\u015flatmak i\u00e7in:<\/p>\n<pre><code class=\"language-bash\">\npm2 start app.js -i max # T\u00fcm CPU \u00e7ekirdeklerini kullanacak \u015fekilde ba\u015flat\n<\/pre>\n<p><\/code><\/p>\n<p><code>-i max<\/code> bayra\u011f\u0131, PM2'nin CPU \u00e7ekirde\u011fi say\u0131n\u0131z kadar uygulaman\u0131z\u0131n kopyalar\u0131n\u0131 (cluster) \u00e7al\u0131\u015ft\u0131rmas\u0131n\u0131 sa\u011flar, b\u00f6ylece uygulaman\u0131z daha fazla iste\u011fi paralel olarak i\u015fleyebilir ve bir \u00f6rnek \u00e7\u00f6kerse di\u011ferleri \u00e7al\u0131\u015fmaya devam eder.<\/p>\n<h3>4. Bulut Platformlar\u0131 ile Da\u011f\u0131t\u0131m (Deployment)<\/h3>\n<p>API'nizi \u00fcretim ortam\u0131na ta\u015f\u0131mak i\u00e7in \u00e7e\u015fitli bulut platformlar\u0131 kullanabilirsiniz:<\/p>\n<ul>\n<li><strong>PaaS (Platform as a Service) \u00c7\u00f6z\u00fcmleri (Heroku, Vercel, Render):<\/strong> Bu platformlar, uygulaman\u0131z\u0131 da\u011f\u0131t\u0131m\u0131 i\u00e7in altyap\u0131y\u0131 y\u00f6netir. Git deponuza ba\u011flar, otomatik da\u011f\u0131t\u0131m yapar ve genellikle \u00fccretsiz katmanlar sunar. H\u0131zl\u0131 ba\u015flang\u0131\u00e7lar ve daha az altyap\u0131 y\u00f6netimi isteyen ekipler i\u00e7in idealdir.<\/li>\n<li><strong>IaaS (Infrastructure as a Service) \u00c7\u00f6z\u00fcmleri (AWS EC2, Google Cloud Compute Engine, Azure Virtual Machines):<\/strong> Sanal sunucular\u0131 do\u011frudan kontrol edersiniz. Daha fazla esneklik ve kontrol sa\u011flar ancak altyap\u0131 y\u00f6netimi (OS g\u00fcncellemeleri, g\u00fcvenlik yamalar\u0131 vb.) tamamen size aittir. PM2 gibi ara\u00e7lar\u0131 bu sunuculara kurarak uygulaman\u0131z\u0131 \u00e7al\u0131\u015ft\u0131rabilirsiniz.<\/li>\n<li><strong>Konteynerizasyon (Docker):<\/strong> Uygulaman\u0131z\u0131 ve t\u00fcm ba\u011f\u0131ml\u0131l\u0131klar\u0131n\u0131 izole bir konteyner i\u00e7inde paketlemek, \"benim makinemde \u00e7al\u0131\u015f\u0131yor\" sorununu ortadan kald\u0131r\u0131r. Docker ile uygulaman\u0131z her ortamda tutarl\u0131 bir \u015fekilde \u00e7al\u0131\u015f\u0131r. AWS ECS, Google Kubernetes Engine gibi platformlar Docker konteynerlerini \u00f6l\u00e7ekli olarak y\u00f6netmek i\u00e7in kullan\u0131l\u0131r.<\/li>\n<\/ul>\n<p>\u00d6rne\u011fin, bir Heroku da\u011f\u0131t\u0131m\u0131 i\u00e7in sadece projenizi bir Git deposuna g\u00f6ndermeniz ve Heroku CLI \u00fczerinden <code>git push heroku master<\/code> komutunu \u00e7al\u0131\u015ft\u0131rman\u0131z yeterli olabilir (Heroku'nun Node.js buildpack'i PM2 veya Procfile'daki komutunuzu otomatik olarak \u00e7al\u0131\u015ft\u0131racakt\u0131r).<\/p>\n<h3>5. Mobil Uyumluluk ve API Kullan\u0131m\u0131<\/h3>\n<p>API'niz herhangi bir istemci (web sitesi, mobil uygulama, masa\u00fcst\u00fc uygulama) taraf\u0131ndan t\u00fcketilebilir. Bu ba\u011flamda, API'nizin kendisi mobil uyumlu olmazken, API'yi t\u00fcketen web sitelerinin mobil uyumlu olmas\u0131 \u00f6nemlidir. Bir web sitesi, API'nizden ald\u0131\u011f\u0131 veriyi g\u00f6sterirken, k\u00fc\u00e7\u00fck ekranlara ve dokunmatik aray\u00fczlere uygun bir \u015fekilde kendini d\u00fczenlemelidir. Bu genellikle CSS medya sorgular\u0131 ve duyarl\u0131 tasar\u0131m teknikleri kullan\u0131larak yap\u0131l\u0131r. \u00d6rne\u011fin:<\/p>\n<pre><code class=\"language-html\">\n<!DOCTYPE html>\n<html lang=\"tr\">\n<head>\n    <meta charset=\"UTF-8\">\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n    <title>Mobil Uyumlu API T\u00fcketicisi<\/title>\n    <style>\n        \/* Varsay\u0131lan stil: geni\u015f ekranlar i\u00e7in *\/\n        body { font-family: Arial, sans-serif; margin: 20px; }\n        .container { display: grid; grid-template-columns: repeat(3, 1fr); gap: 20px; }\n        .card { border: 1px solid #ccc; padding: 15px; border-radius: 8px; }\n\n        \/* Mobil ekranlar i\u00e7in medya sorgusu *\/\n        @media (max-width: 768px) {\n            .container {\n                grid-template-columns: 1fr; \/* Tek s\u00fctunlu d\u00fczen *\/\n            }\n            .card {\n                margin-bottom: 15px;\n            }\n        }\n    <\/style>\n<\/head>\n<body>\n    <h1>API Verileri<\/h1>\n    <div id=\"data-container\" class=\"container\">\n        <!-- API'den gelen veriler buraya y\u00fcklenecek -->\n        <div class=\"card\">\n            <h2>\u00d6\u011fe 1<\/h2>\n            <p>Bu bir API \u00f6\u011fesidir.<\/p>\n        <\/div>\n        <div class=\"card\">\n            <h2>\u00d6\u011fe 2<\/h2>\n            <p>Bu da ba\u015fka bir API \u00f6\u011fesidir.<\/p>\n        <\/div>\n    <\/div>\n    <script>\n        \/\/ fetch('http:\/\/localhost:3000\/api\/items')\n        \/\/     .then(response => response.json())\n        \/\/     .then(data => {\n        \/\/         const container = document.getElementById('data-container');\n        \/\/         container.innerHTML = ''; \/\/ Mevcut \u00f6rnekleri temizle\n        \/\/         data.forEach(item => {\n        \/\/             const card = <code>\/\/                 <div class=\"card\">\n        \/\/                     <h2>${item.name}<\/h2>\n        \/\/                     <p>${item.description}<\/p>\n        \/\/                 <\/div>\n        \/\/<\/code>;\n        \/\/             container.innerHTML += card;\n        \/\/         });\n        \/\/     })\n        \/\/     .catch(error => console.error('Error fetching data:', error));\n    <\/script>\n<\/body>\n<\/html>\n<\/pre>\n<p><\/code><\/p>\n<p>Bu HTML yap\u0131s\u0131, temel bir meta viewport etiketi ve bir medya sorgusu i\u00e7erir. Bu sayede, API'nizden gelen veriler, farkl\u0131 ekran boyutlar\u0131na sahip cihazlarda okunabilir ve kullan\u0131labilir bir \u015fekilde g\u00f6sterilebilir. API'nizin kendisi sadece veriyi sunar, bu verinin istemcide nas\u0131l d\u00fczenlenece\u011fi istemcinin sorumlulu\u011fundad\u0131r. Da\u011f\u0131t\u0131m ve \u00f6l\u00e7eklendirme, API'nizin sadece \u00e7al\u0131\u015fmas\u0131n\u0131 de\u011fil, ayn\u0131 zamanda g\u00fcvenilir, performansl\u0131 ve s\u00fcrd\u00fcr\u00fclebilir olmas\u0131n\u0131 sa\u011flamak i\u00e7in kritik ad\u0131mlard\u0131r. \u00d6rne\u011fin, Black Friday gibi yo\u011fun d\u00f6nemlerde bir e-ticaret API'sinin trafi\u011fi sorunsuz bir \u015fekilde kald\u0131rabilmesi i\u00e7in bu ad\u0131mlar olmazsa olmazd\u0131r.<\/p>\n<h2>Sonu\u00e7: REST API Yolculu\u011funuzda Bir Sonraki Ad\u0131mlar\u0131n\u0131z Neler Olmal\u0131?<\/h2>\n<p>Bu kapsaml\u0131 rehber boyunca, Node.js ve Express kullanarak s\u0131f\u0131rdan \u00fcretime haz\u0131r bir REST API olu\u015fturman\u0131n temel ad\u0131mlar\u0131n\u0131 derinlemesine inceledik. \u0130lk \"Hello World\" endpoint'inden ba\u015flayarak, MongoDB ile veritaban\u0131 entegrasyonu, JWT ile g\u00fcvenlik ve kimlik do\u011frulama, sa\u011flam hata y\u00f6netimi ve giri\u015f do\u011frulama teknikleri, API belgelendirme ile geli\u015ftirici deneyimini iyile\u015ftirme ve son olarak API'yi \u00fcretim ortam\u0131na da\u011f\u0131tma ve \u00f6l\u00e7eklendirme stratejilerini ele ald\u0131k. Art\u0131k kendi REST API'lerinizi geli\u015ftirmek ve modern web uygulamalar\u0131n\u0131n arka y\u00fcz\u00fcn\u00fc olu\u015fturmak i\u00e7in sa\u011flam bir bilgi birikimine ve pratik yeteneklere sahipsiniz.<\/p>\n<p>Ancak, teknoloji d\u00fcnyas\u0131 s\u00fcrekli geli\u015fiyor ve \u00f6\u011frenme yolculu\u011funuz burada bitmiyor. Bir sonraki ad\u0131mlar\u0131n\u0131zda ke\u015ffedebilece\u011finiz baz\u0131 ileri d\u00fczey konular ve teknolojiler \u015funlar olabilir:<\/p>\n<ul>\n<li><strong>GraphQL:<\/strong> REST API'lere bir alternatif olarak ortaya \u00e7\u0131kan GraphQL, istemcilerin tam olarak ihtiya\u00e7 duyduklar\u0131 veriyi tek bir istekte almalar\u0131n\u0131 sa\u011flar, bu da a\u015f\u0131r\u0131 veya eksik veri \u00e7ekme sorunlar\u0131n\u0131 \u00e7\u00f6zer.<\/li>\n<li><strong>Mikroservis Mimarileri:<\/strong> B\u00fcy\u00fck uygulamalar\u0131 daha k\u00fc\u00e7\u00fck, ba\u011f\u0131ms\u0131z ve birbirleriyle ileti\u015fim kuran servisler halinde b\u00f6lmek, \u00f6l\u00e7eklenebilirli\u011fi ve bak\u0131m kolayl\u0131\u011f\u0131n\u0131 art\u0131r\u0131r. Node.js mikroservisler i\u00e7in pop\u00fcler bir se\u00e7imdir.<\/li>\n<li><strong>WebSockets:<\/strong> Ger\u00e7ek zamanl\u0131 uygulamalar (chat uygulamalar\u0131, canl\u0131 bildirimler) geli\u015ftirmek i\u00e7in sunucu ile istemci aras\u0131nda kal\u0131c\u0131, \u00e7ift y\u00f6nl\u00fc bir ileti\u015fim kanal\u0131 sa\u011flar.<\/li>\n<li><strong>Caching (\u00d6nbellekleme):<\/strong> Redis veya Memcached gibi in-memory veritabanlar\u0131 kullanarak s\u0131k eri\u015filen verileri \u00f6nbelle\u011fe almak, API performans\u0131n\u0131 \u00f6nemli \u00f6l\u00e7\u00fcde art\u0131rabilir.<\/li>\n<li><strong>API Gateway'ler:<\/strong> Mikroservis mimarilerinde, istemcilerin birden fazla servise do\u011frudan eri\u015fmesini engellemek ve merkezi kimlik do\u011frulama, y\u00fck dengeleme gibi i\u015flevleri sa\u011flamak i\u00e7in kullan\u0131l\u0131r.<\/li>\n<li><strong>Sunucusuz (Serverless) Fonksiyonlar:<\/strong> AWS Lambda, Google Cloud Functions gibi platformlar, API endpoint'lerinizi sunucu y\u00f6netimi derdi olmadan \u00e7al\u0131\u015ft\u0131rman\u0131za olanak tan\u0131r ve maliyeti kullan\u0131m ba\u015f\u0131na d\u00fc\u015f\u00fcr\u00fcr.<\/li>\n<\/ul>\n<p>Bu konular\u0131 ke\u015ffederek, Node.js ve Express ile geli\u015ftirme yeteneklerinizi bir \u00fcst seviyeye ta\u015f\u0131yabilir ve daha karma\u015f\u0131k, \u00f6l\u00e7eklenebilir ve dayan\u0131kl\u0131 sistemler in\u015fa edebilirsiniz. Unutmay\u0131n, en iyi \u00f6\u011frenme y\u00f6ntemi pratik yapmakt\u0131r. Bu rehberde \u00f6\u011frendiklerinizi kullanarak kendi projelerinizi geli\u015ftirmeye devam edin ve yeni teknolojileri deneyimlemekten \u00e7ekinmeyin. Ba\u015far\u0131lar dileriz!<\/p>\n<h3>S\u0131k\u00e7a Sorulan Sorular (SSS)<\/h3>\n<p><strong>1. Node.js ve Express kullanmak yerine neden ba\u015fka bir dil veya framework se\u00e7meyeyim?<\/strong><\/p>\n<p><strong>Cevap:<\/strong> Node.js ve Express, JavaScript'i hem \u00f6n u\u00e7ta hem de arka u\u00e7ta kullanabilme avantaj\u0131 sunar, bu da geli\u015ftirme h\u0131z\u0131n\u0131 art\u0131r\u0131r ve ekip i\u00e7inde dil tutarl\u0131l\u0131\u011f\u0131 sa\u011flar. Node.js'in asenkron, engellemeyen G\/\u00c7 modeli, y\u00fcksek performansl\u0131 ve \u00f6l\u00e7eklenebilir API'ler i\u00e7in olduk\u00e7a etkilidir. Ayr\u0131ca, geni\u015f ve aktif bir toplulu\u011fa ve zengin bir npm paket ekosistemine sahiptir. Ancak, Ruby on Rails, Django (Python), Spring Boot (Java) gibi ba\u015fka diller ve framework'ler de kendi avantajlar\u0131na sahiptir ve projenizin \u00f6zel gereksinimlerine g\u00f6re en uygun olan\u0131 se\u00e7melisiniz.<\/p>\n<p><strong>2. MongoDB yerine ba\u015fka bir veritaban\u0131 kullanabilir miyim?<\/strong><\/p>\n<p><strong>Cevap:<\/strong> Kesinlikle! MongoDB, esnek yap\u0131s\u0131 nedeniyle Node.js ile pop\u00fcler bir se\u00e7im olsa da, projenizin ihtiya\u00e7lar\u0131na g\u00f6re PostgreSQL, MySQL (ili\u015fkisel veritabanlar\u0131), Redis (bellek i\u00e7i \u00f6nbellek\/veritaban\u0131) veya Cassandra (geni\u015f s\u00fctunlu NoSQL) gibi farkl\u0131 veritabanlar\u0131n\u0131 tercih edebilirsiniz. Mongoose yerine bu veritabanlar\u0131 i\u00e7in uygun ORM (Object-Relational Mapper) veya ODM (Object-Document Mapper) k\u00fct\u00fcphanelerini kullanman\u0131z gerekecektir (\u00f6rne\u011fin, PostgreSQL i\u00e7in Sequelize veya Prisma).<\/p>\n<p><strong>3. API g\u00fcvenli\u011fini art\u0131rmak i\u00e7in ba\u015fka neler yapabilirim?<\/strong><\/p>\n<p><strong>Cevap:<\/strong> Bu rehberde JWT ile temel kimlik do\u011frulamas\u0131n\u0131 ele ald\u0131k. G\u00fcvenli\u011fi daha da art\u0131rmak i\u00e7in HTTPS kullanmak (SSL\/TLS sertifikalar\u0131 ile), rate limiting (API'ye yap\u0131lan istek say\u0131s\u0131n\u0131 s\u0131n\u0131rlama), CSRF (Cross-Site Request Forgery) ve XSS (Cross-Site Scripting) sald\u0131r\u0131lar\u0131na kar\u015f\u0131 \u00f6nlemler almak, g\u00fcvenlik a\u00e7\u0131klar\u0131n\u0131 tarayan ara\u00e7lar kullanmak ve d\u00fczenli g\u00fcvenlik denetimleri yapmak gibi ek ad\u0131mlar atabilirsiniz. Ayr\u0131ca, hassas verileri \u015fifreleyerek depolamak ve g\u00fcvenlik yamalar\u0131n\u0131 d\u00fczenli olarak uygulamak da \u00f6nemlidir.<\/p>\n<p><strong>4. API'mi mobil uygulamalarla nas\u0131l entegre ederim?<\/strong><\/p>\n<p><strong>Cevap:<\/strong> Mobil uygulamalar, API'nizle genellikle HTTP istekleri (GET, POST vb.) yaparak ileti\u015fim kurar. Android i\u00e7in Retrofit (Java\/Kotlin), iOS i\u00e7in Alamofire (Swift) veya platformlar aras\u0131 (cross-platform) geli\u015ftirme i\u00e7in React Native'de Fetch API\/Axios gibi k\u00fct\u00fcphaneler kullan\u0131l\u0131r. Mobil uygulamalar\u0131n API'nizle g\u00fcvenli bir \u015fekilde ileti\u015fim kurabilmesi i\u00e7in HTTPS ve JWT gibi kimlik do\u011frulama mekanizmalar\u0131n\u0131 do\u011fru bir \u015fekilde uygulad\u0131\u011f\u0131n\u0131zdan emin olun.<\/p>\n<p><strong>5. API'mde ne zaman \u00f6nbellekleme kullanmal\u0131y\u0131m?<\/strong><\/p>\n<p><strong>Cevap:<\/strong> \u00d6nbellekleme, API'nizdeki s\u0131k eri\u015filen ancak nadiren de\u011fi\u015fen veriler i\u00e7in m\u00fckemmel bir performans iyile\u015ftirme y\u00f6ntemidir. \u00d6rne\u011fin, bir e-ticaret sitesindeki \u00fcr\u00fcn kategorileri, pop\u00fcler makaleler veya hava durumu verileri gibi statik veya yar\u0131 statik veriler \u00f6nbelle\u011fe al\u0131nabilir. Veritaban\u0131ndan her seferinde ayn\u0131 veriyi \u00e7ekmek yerine, \u00f6nbellekten sunarak yan\u0131t s\u00fcrelerini \u00f6nemli \u00f6l\u00e7\u00fcde k\u0131saltabilirsiniz. Redis veya Memcached gibi ara\u00e7lar, Node.js ile kolayca entegre edilebilir.<\/p>\n<p><\/body><\/p>\n","protected":false},"excerpt":{"rendered":"Node.js ve Express kullanarak s\u0131f\u0131rdan g\u00fcvenli, \u00f6l\u00e7eklenebilir bir REST API nas\u0131l olu\u015fturulur? Temel kavramlardan da\u011f\u0131t\u0131ma uzanan bu kapsaml\u0131&hellip;","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-30938","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>Node.js ve Express ile REST API: S\u0131f\u0131rdan \u00dcretime Tam K\u0131lavuz<\/title>\n<meta name=\"description\" content=\"Node.js ve Express kullanarak s\u0131f\u0131rdan g\u00fcvenli, \u00f6l\u00e7eklenebilir bir REST API nas\u0131l olu\u015fturulur? Temel kavramlardan da\u011f\u0131t\u0131ma uzanan bu kapsaml\u0131 rehberle kendi API&#039;nizi geli\u015ftirin ve modern web uygulamalar\u0131n\u0131n g\u00fcc\u00fcn\u00fc ke\u015ffedin.\" \/>\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\/node-js-ve-express-ile-rest-api-sifirdan-uretime-tam-kilavuz\/\" \/>\n<meta property=\"og:locale\" content=\"tr_TR\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Node.js ve Express ile REST API: S\u0131f\u0131rdan \u00dcretime Tam K\u0131lavuz\" \/>\n<meta property=\"og:description\" content=\"Node.js ve Express kullanarak s\u0131f\u0131rdan g\u00fcvenli, \u00f6l\u00e7eklenebilir bir REST API nas\u0131l olu\u015fturulur? Temel kavramlardan da\u011f\u0131t\u0131ma uzanan bu kapsaml\u0131 rehberle kendi API&#039;nizi geli\u015ftirin ve modern web uygulamalar\u0131n\u0131n g\u00fcc\u00fcn\u00fc ke\u015ffedin.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/fatihsoysal.com\/blog\/node-js-ve-express-ile-rest-api-sifirdan-uretime-tam-kilavuz\/\" \/>\n<meta property=\"og:site_name\" content=\"Kodlar\u0131n Gizemli D\u00fcnyas\u0131\" \/>\n<meta property=\"article:published_time\" content=\"2025-10-03T16:03:09+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=\"44 dakika\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/fatihsoysal.com\/blog\/node-js-ve-express-ile-rest-api-sifirdan-uretime-tam-kilavuz\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/fatihsoysal.com\/blog\/node-js-ve-express-ile-rest-api-sifirdan-uretime-tam-kilavuz\/\"},\"author\":{\"name\":\"Fatih Soysal\",\"@id\":\"https:\/\/fatihsoysal.com\/blog\/#\/schema\/person\/002a254750921dcfd568a99e48240dd1\"},\"headline\":\"Node.js ve Express ile REST API: S\u0131f\u0131rdan \u00dcretime Tam K\u0131lavuz\",\"datePublished\":\"2025-10-03T16:03:09+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/fatihsoysal.com\/blog\/node-js-ve-express-ile-rest-api-sifirdan-uretime-tam-kilavuz\/\"},\"wordCount\":6313,\"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\/node-js-ve-express-ile-rest-api-sifirdan-uretime-tam-kilavuz\/#respond\"]}],\"copyrightYear\":\"2025\",\"copyrightHolder\":{\"@id\":\"https:\/\/fatihsoysal.com\/blog\/#organization\"}},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/fatihsoysal.com\/blog\/node-js-ve-express-ile-rest-api-sifirdan-uretime-tam-kilavuz\/\",\"url\":\"https:\/\/fatihsoysal.com\/blog\/node-js-ve-express-ile-rest-api-sifirdan-uretime-tam-kilavuz\/\",\"name\":\"Node.js ve Express ile REST API: S\u0131f\u0131rdan \u00dcretime Tam K\u0131lavuz\",\"isPartOf\":{\"@id\":\"https:\/\/fatihsoysal.com\/blog\/#website\"},\"datePublished\":\"2025-10-03T16:03:09+00:00\",\"description\":\"Node.js ve Express kullanarak s\u0131f\u0131rdan g\u00fcvenli, \u00f6l\u00e7eklenebilir bir REST API nas\u0131l olu\u015fturulur? Temel kavramlardan da\u011f\u0131t\u0131ma uzanan bu kapsaml\u0131 rehberle kendi API'nizi geli\u015ftirin ve modern web uygulamalar\u0131n\u0131n g\u00fcc\u00fcn\u00fc ke\u015ffedin.\",\"breadcrumb\":{\"@id\":\"https:\/\/fatihsoysal.com\/blog\/node-js-ve-express-ile-rest-api-sifirdan-uretime-tam-kilavuz\/#breadcrumb\"},\"inLanguage\":\"tr\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/fatihsoysal.com\/blog\/node-js-ve-express-ile-rest-api-sifirdan-uretime-tam-kilavuz\/\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/fatihsoysal.com\/blog\/node-js-ve-express-ile-rest-api-sifirdan-uretime-tam-kilavuz\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Anasayfa\",\"item\":\"https:\/\/fatihsoysal.com\/blog\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Node.js ve Express ile REST API: S\u0131f\u0131rdan \u00dcretime Tam K\u0131lavuz\"}]},{\"@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":"Node.js ve Express ile REST API: S\u0131f\u0131rdan \u00dcretime Tam K\u0131lavuz","description":"Node.js ve Express kullanarak s\u0131f\u0131rdan g\u00fcvenli, \u00f6l\u00e7eklenebilir bir REST API nas\u0131l olu\u015fturulur? Temel kavramlardan da\u011f\u0131t\u0131ma uzanan bu kapsaml\u0131 rehberle kendi API'nizi geli\u015ftirin ve modern web uygulamalar\u0131n\u0131n g\u00fcc\u00fcn\u00fc ke\u015ffedin.","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\/node-js-ve-express-ile-rest-api-sifirdan-uretime-tam-kilavuz\/","og_locale":"tr_TR","og_type":"article","og_title":"Node.js ve Express ile REST API: S\u0131f\u0131rdan \u00dcretime Tam K\u0131lavuz","og_description":"Node.js ve Express kullanarak s\u0131f\u0131rdan g\u00fcvenli, \u00f6l\u00e7eklenebilir bir REST API nas\u0131l olu\u015fturulur? Temel kavramlardan da\u011f\u0131t\u0131ma uzanan bu kapsaml\u0131 rehberle kendi API'nizi geli\u015ftirin ve modern web uygulamalar\u0131n\u0131n g\u00fcc\u00fcn\u00fc ke\u015ffedin.","og_url":"https:\/\/fatihsoysal.com\/blog\/node-js-ve-express-ile-rest-api-sifirdan-uretime-tam-kilavuz\/","og_site_name":"Kodlar\u0131n Gizemli D\u00fcnyas\u0131","article_published_time":"2025-10-03T16:03:09+00:00","author":"Fatih Soysal","twitter_card":"summary_large_image","twitter_misc":{"Yazan:":"Fatih Soysal","Tahmini okuma s\u00fcresi":"44 dakika"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/fatihsoysal.com\/blog\/node-js-ve-express-ile-rest-api-sifirdan-uretime-tam-kilavuz\/#article","isPartOf":{"@id":"https:\/\/fatihsoysal.com\/blog\/node-js-ve-express-ile-rest-api-sifirdan-uretime-tam-kilavuz\/"},"author":{"name":"Fatih Soysal","@id":"https:\/\/fatihsoysal.com\/blog\/#\/schema\/person\/002a254750921dcfd568a99e48240dd1"},"headline":"Node.js ve Express ile REST API: S\u0131f\u0131rdan \u00dcretime Tam K\u0131lavuz","datePublished":"2025-10-03T16:03:09+00:00","mainEntityOfPage":{"@id":"https:\/\/fatihsoysal.com\/blog\/node-js-ve-express-ile-rest-api-sifirdan-uretime-tam-kilavuz\/"},"wordCount":6313,"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\/node-js-ve-express-ile-rest-api-sifirdan-uretime-tam-kilavuz\/#respond"]}],"copyrightYear":"2025","copyrightHolder":{"@id":"https:\/\/fatihsoysal.com\/blog\/#organization"}},{"@type":"WebPage","@id":"https:\/\/fatihsoysal.com\/blog\/node-js-ve-express-ile-rest-api-sifirdan-uretime-tam-kilavuz\/","url":"https:\/\/fatihsoysal.com\/blog\/node-js-ve-express-ile-rest-api-sifirdan-uretime-tam-kilavuz\/","name":"Node.js ve Express ile REST API: S\u0131f\u0131rdan \u00dcretime Tam K\u0131lavuz","isPartOf":{"@id":"https:\/\/fatihsoysal.com\/blog\/#website"},"datePublished":"2025-10-03T16:03:09+00:00","description":"Node.js ve Express kullanarak s\u0131f\u0131rdan g\u00fcvenli, \u00f6l\u00e7eklenebilir bir REST API nas\u0131l olu\u015fturulur? Temel kavramlardan da\u011f\u0131t\u0131ma uzanan bu kapsaml\u0131 rehberle kendi API'nizi geli\u015ftirin ve modern web uygulamalar\u0131n\u0131n g\u00fcc\u00fcn\u00fc ke\u015ffedin.","breadcrumb":{"@id":"https:\/\/fatihsoysal.com\/blog\/node-js-ve-express-ile-rest-api-sifirdan-uretime-tam-kilavuz\/#breadcrumb"},"inLanguage":"tr","potentialAction":[{"@type":"ReadAction","target":["https:\/\/fatihsoysal.com\/blog\/node-js-ve-express-ile-rest-api-sifirdan-uretime-tam-kilavuz\/"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/fatihsoysal.com\/blog\/node-js-ve-express-ile-rest-api-sifirdan-uretime-tam-kilavuz\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Anasayfa","item":"https:\/\/fatihsoysal.com\/blog\/"},{"@type":"ListItem","position":2,"name":"Node.js ve Express ile REST API: S\u0131f\u0131rdan \u00dcretime Tam K\u0131lavuz"}]},{"@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\/30938","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=30938"}],"version-history":[{"count":0,"href":"https:\/\/fatihsoysal.com\/blog\/wp-json\/wp\/v2\/posts\/30938\/revisions"}],"wp:attachment":[{"href":"https:\/\/fatihsoysal.com\/blog\/wp-json\/wp\/v2\/media?parent=30938"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/fatihsoysal.com\/blog\/wp-json\/wp\/v2\/categories?post=30938"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/fatihsoysal.com\/blog\/wp-json\/wp\/v2\/tags?post=30938"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}