{"id":35169,"date":"2025-11-26T13:40:46","date_gmt":"2025-11-26T10:40:46","guid":{"rendered":"https:\/\/fatihsoysal.com\/blog\/?p=35169"},"modified":"2025-11-26T13:40:46","modified_gmt":"2025-11-26T10:40:46","slug":"gelismis-fotograf-yukleme-islevselligini-node-js-ve-express-ile-entegre-etme","status":"publish","type":"post","link":"https:\/\/fatihsoysal.com\/blog\/gelismis-fotograf-yukleme-islevselligini-node-js-ve-express-ile-entegre-etme\/","title":{"rendered":"Geli\u015fmi\u015f Foto\u011fraf Y\u00fckleme \u0130\u015flevselli\u011fini Node.js ve Express ile Entegre Etme"},"content":{"rendered":"<p><body><\/p>\n<h2>Geli\u015fmi\u015f Foto\u011fraf Y\u00fckleme \u0130\u015flevselli\u011fini Node.js ve Express ile Entegre Etme<\/h2>\n<p>Foto\u011fraf y\u00fckleme, modern web uygulamalar\u0131n\u0131n vazge\u00e7ilmez bir par\u00e7as\u0131d\u0131r. Sosyal medya platformlar\u0131ndan e-ticaret sitelerine, i\u00e7erik y\u00f6netim sistemlerinden ki\u015fisel portf\u00f6ylere kadar bir\u00e7ok uygulamada kullan\u0131c\u0131lar\u0131n g\u00f6rsel i\u00e7eriklerini payla\u015fmas\u0131na olanak tan\u0131r. Ancak basit bir dosya y\u00fckleme mekanizmas\u0131 kurmakla, geli\u015fmi\u015f, g\u00fcvenli, performansl\u0131 ve kullan\u0131c\u0131 dostu bir foto\u011fraf y\u00fckleme sistemi olu\u015fturmak aras\u0131nda b\u00fcy\u00fck farklar vard\u0131r. Bu makalede, Node.js ve Express kullanarak geli\u015fmi\u015f foto\u011fraf y\u00fckleme i\u015flevselli\u011fini nas\u0131l entegre edece\u011fimizi ad\u0131m ad\u0131m inceleyece\u011fiz.<\/p>\n<h3>Neden Geli\u015fmi\u015f Foto\u011fraf Y\u00fcklemeleri?<\/h3>\n<p>Basit bir dosya y\u00fckleme, genellikle kullan\u0131c\u0131n\u0131n se\u00e7ti\u011fi bir dosyay\u0131 sunucuya kaydetmekten ibarettir. Ancak bu yakla\u015f\u0131m, ger\u00e7ek d\u00fcnya senaryolar\u0131nda yetersiz kal\u0131r ve bir\u00e7ok soruna yol a\u00e7abilir:<\/p>\n<p>*   <strong>Performans Sorunlar\u0131:<\/strong> Y\u00fcksek \u00e7\u00f6z\u00fcn\u00fcrl\u00fckl\u00fc veya b\u00fcy\u00fck boyutlu dosyalar\u0131n do\u011frudan sunucuya y\u00fcklenmesi, a\u011f bant geni\u015fli\u011fini t\u00fcketir ve sunucu kaynaklar\u0131n\u0131 yorar. Bu da kullan\u0131c\u0131 deneyimini olumsuz etkiler.<br \/>\n*   <strong>Depolama ve \u00d6l\u00e7eklenebilirlik:<\/strong> Sunucu diskinde depolama alan\u0131 s\u0131n\u0131rl\u0131d\u0131r. Uygulama b\u00fcy\u00fcd\u00fck\u00e7e ve kullan\u0131c\u0131 say\u0131s\u0131 artt\u0131k\u00e7a, bu depolama maliyetli ve y\u00f6netilmesi zor hale gelir.<br \/>\n*   <strong>G\u00fcvenlik A\u00e7\u0131klar\u0131:<\/strong> Dosya t\u00fcr\u00fc, boyutu veya i\u00e7eri\u011fi do\u011frulanmadan yap\u0131lan y\u00fcklemeler, zararl\u0131 yaz\u0131l\u0131m, sistem istismar\u0131 veya hizmet reddi (DoS) sald\u0131r\u0131lar\u0131na kap\u0131 aralayabilir.<br \/>\n*   <strong>Kullan\u0131c\u0131 Deneyimi:<\/strong> Kullan\u0131c\u0131lar, y\u00fckleme ilerlemesini g\u00f6rmek, hatalar\u0131 anlamak, birden fazla dosya y\u00fcklemek veya g\u00f6rsellerini \u00f6nizlemek isterler. Basit y\u00fcklemeler bu esnekli\u011fi sunmaz.<br \/>\n*   <strong>G\u00f6rsel Optimizasyonu:<\/strong> Web i\u00e7in g\u00f6rsellerin optimize edilmesi (boyutland\u0131rma, s\u0131k\u0131\u015ft\u0131rma, format d\u00f6n\u00fc\u015ft\u00fcrme) hem performans hem de depolama a\u00e7\u0131s\u0131ndan kritiktir.<\/p>\n<p>Geli\u015fmi\u015f foto\u011fraf y\u00fcklemeleri, bu sorunlar\u0131 \u00e7\u00f6zmek i\u00e7in \u00e7e\u015fitli ara\u00e7lar ve teknikler kullan\u0131r. Bu makalede, Multer ile dosya i\u015fleme, Sharp ile g\u00f6rsel manip\u00fclasyon ve AWS S3 gibi bulut depolama \u00e7\u00f6z\u00fcmleriyle entegrasyonu ele alaca\u011f\u0131z.<\/p>\n<h3>Temel Dosya Y\u00fckleme Mekanizmas\u0131 ve Zorluklar\u0131<\/h3>\n<p>Bir web uygulamas\u0131nda dosya y\u00fckleme, genellikle bir HTML formu arac\u0131l\u0131\u011f\u0131yla ger\u00e7ekle\u015fir:<\/p>\n<pre><code class=\"language-html\"><form action=\"\/upload\" method=\"POST\" enctype=\"multipart\/form-data\">\n  <input type=\"file\" name=\"myImage\" \/>\n  <button type=\"submit\">Y\u00fckle<\/button>\n<\/form><\/code><\/pre>\n<p>Burada kritik olan <code>enctype=\"multipart\/form-data\"<\/code> \u00f6zelli\u011fidir. Bu \u00f6zellik olmadan, taray\u0131c\u0131 dosya i\u00e7eri\u011fini g\u00f6ndermez. Sunucu taraf\u0131nda, Express varsay\u0131lan olarak <code>multipart\/form-data<\/code> isteklerini i\u015fleyemez. <code>body-parser<\/code> gibi middleware&#8217;ler yaln\u0131zca URL kodlu veya JSON g\u00f6vdelerini i\u015fleyebilir. Bu nedenle, dosya y\u00fcklemelerini y\u00f6netmek i\u00e7in \u00f6zel bir middleware&#8217;e ihtiya\u00e7 duyar\u0131z.<\/p>\n<p>Temel zorluklar \u015funlard\u0131r:<\/p>\n<p>*   <strong><code>multipart\/form-data<\/code> \u0130\u015fleme:<\/strong> Express&#8217;in bu t\u00fcr istekleri ayr\u0131\u015ft\u0131rmas\u0131 i\u00e7in bir k\u00fct\u00fcphane gereklidir.<br \/>\n*   <strong>Ge\u00e7ici Depolama:<\/strong> Y\u00fcklenen dosyan\u0131n sunucu taraf\u0131nda ge\u00e7ici olarak nereye kaydedilece\u011fi.<br \/>\n*   <strong>Dosya Do\u011frulama:<\/strong> Dosyan\u0131n t\u00fcr\u00fc, boyutu ve ad\u0131n\u0131n do\u011frulanmas\u0131.<br \/>\n*   <strong>Hata Y\u00f6netimi:<\/strong> Y\u00fckleme s\u0131ras\u0131nda olu\u015fabilecek hatalar\u0131n (dosya boyutu a\u015f\u0131ld\u0131, ge\u00e7ersiz dosya t\u00fcr\u00fc vb.) kullan\u0131c\u0131ya bildirilmesi.<br \/>\n*   <strong>Birden Fazla Dosya:<\/strong> Ayn\u0131 anda birden fazla dosya y\u00fckleme ihtiyac\u0131.<\/p>\n<p>Bu zorluklar\u0131n \u00fcstesinden gelmek i\u00e7in Multer gibi g\u00fc\u00e7l\u00fc bir k\u00fct\u00fcphane devreye girer.<\/p>\n<h3>Geli\u015fmi\u015f Y\u00fckleme \u0130\u00e7in Gerekli Ara\u00e7lar ve K\u00fct\u00fcphaneler<\/h3>\n<p>Geli\u015fmi\u015f foto\u011fraf y\u00fckleme i\u015flevselli\u011fi olu\u015fturmak i\u00e7in birka\u00e7 temel ara\u00e7 ve k\u00fct\u00fcphane kullanaca\u011f\u0131z:<\/p>\n<h4>Multer: Express \u0130\u00e7in <code>multipart\/form-data<\/code> Middleware&#8217;i<\/h4>\n<p>Multer, Node.js i\u00e7in <code>multipart\/form-data<\/code>&#8216;y\u0131 i\u015fleyen bir middleware&#8217;dir ve Express ile birlikte kullan\u0131m\u0131 kolayd\u0131r. Dosya y\u00fcklemelerini disk \u00fczerine veya belle\u011fe kaydedebilir.<\/p>\n<p>*   <strong>Neden Multer?<\/strong><br \/>\n    *   <code>multipart\/form-data<\/code> isteklerini kolayca ayr\u0131\u015ft\u0131r\u0131r.<br \/>\n    *   Disk veya bellek depolama se\u00e7enekleri sunar.<br \/>\n    *   Dosya filtreleme (t\u00fcr\u00fcne g\u00f6re) ve boyut s\u0131n\u0131rlamalar\u0131 gibi do\u011frulama \u00f6zellikleri vard\u0131r.<br \/>\n    *   Tek dosya, birden fazla dosya veya karma form alanlar\u0131n\u0131 destekler.<\/p>\n<p>*   <strong>Temel Kullan\u0131m\u0131:<\/strong><\/p>\n<pre><code class=\"language-javascript\">const multer = require('multer');\n    const upload = multer({ dest: 'uploads\/' }); \/\/ Dosyalar\u0131 'uploads' klas\u00f6r\u00fcne kaydeder\n\n    \/\/ Tek dosya y\u00fckleme\n    app.post('\/upload-single', upload.single('myImage'), (req, res) => {\n      res.send('Dosya y\u00fcklendi: ' + req.file.filename);\n    });\n\n    \/\/ Birden fazla dosya y\u00fckleme (array)\n    app.post('\/upload-multiple', upload.array('myImages', 10), (req, res) => {\n      res.send('Dosyalar y\u00fcklendi: ' + req.files.length);\n    });<\/code><\/pre>\n<p>*   <strong><code>diskStorage<\/code> vs. <code>memoryStorage<\/code>:<\/strong><br \/>\n    *   <strong><code>diskStorage<\/code>:<\/strong> Dosyalar\u0131 do\u011frudan sunucunun diskine kaydeder. B\u00fcy\u00fck dosyalar i\u00e7in daha uygundur. Ancak sunucu diskinde kal\u0131c\u0131 depolama gerektirir ve g\u00f6rsel i\u015fleme yap\u0131lacaksa, i\u015fleme sonras\u0131 orijinal dosyay\u0131 silmek gerekebilir.<br \/>\n    *   <strong><code>memoryStorage<\/code>:<\/strong> Dosyalar\u0131 bellekte (Buffer olarak) tutar. G\u00f6rsel i\u015fleme k\u00fct\u00fcphaneleriyle (Sharp gibi) do\u011frudan \u00e7al\u0131\u015fmak i\u00e7in idealdir, \u00e7\u00fcnk\u00fc dosya diskten okunmak zorunda kalmaz. Ancak \u00e7ok b\u00fcy\u00fck dosyalar veya \u00e7ok say\u0131da dosya i\u00e7in bellek t\u00fcketimi sorun olabilir. Geli\u015fmi\u015f y\u00fcklemelerde, g\u00f6rsel i\u015fleme ve ard\u0131ndan buluta y\u00fckleme i\u00e7in <code>memoryStorage<\/code> genellikle tercih edilir.<\/p>\n<p>*   <strong><code>fileFilter<\/code> ve <code>limits<\/code>:<\/strong><br \/>\n    *   <strong><code>fileFilter<\/code>:<\/strong> Y\u00fcklemeye izin verilen dosya t\u00fcrlerini belirlemek i\u00e7in kullan\u0131l\u0131r.<\/p>\n<pre><code class=\"language-javascript\">const fileFilter = (req, file, cb) => {\n          if (file.mimetype.startsWith('image\/')) {\n            cb(null, true); \/\/ Kabul et\n          } else {\n            cb(new Error('Sadece g\u00f6rsel dosyalar\u0131 y\u00fcklenebilir!'), false); \/\/ Reddet\n          }\n        };\n        const upload = multer({ fileFilter: fileFilter });<\/code><\/pre>\n<p>    *   <strong><code>limits<\/code>:<\/strong> Dosya boyutunu s\u0131n\u0131rlamak i\u00e7in kullan\u0131l\u0131r.<\/p>\n<pre><code class=\"language-javascript\">const upload = multer({\n          limits: { fileSize: 1024 <em> 1024 <\/em> 5 } \/\/ 5 MB limit\n        });<\/code><\/pre>\n<h4>Cloud Depolama \u00c7\u00f6z\u00fcmleri (AWS S3, Cloudinary)<\/h4>\n<p>Bulut depolama hizmetleri, \u00f6l\u00e7eklenebilirlik, yedeklilik, performans (CDN entegrasyonu sayesinde) ve maliyet etkinli\u011fi a\u00e7\u0131s\u0131ndan on-premise depolamaya g\u00f6re \u00f6nemli avantajlar sunar.<\/p>\n<p>*   <strong>Neden Bulut Depolama?<\/strong><br \/>\n    *   <strong>\u00d6l\u00e7eklenebilirlik:<\/strong> Uygulaman\u0131z b\u00fcy\u00fcd\u00fck\u00e7e depolama alan\u0131n\u0131 kolayca art\u0131rabilirsiniz.<br \/>\n    *   <strong>Yedeklilik ve G\u00fcvenilirlik:<\/strong> Verileriniz birden fazla konumda yedeklenir, veri kayb\u0131 riski azal\u0131r.<br \/>\n    *   <strong>Performans:<\/strong> Co\u011frafi olarak da\u011f\u0131t\u0131lm\u0131\u015f sunucular (CDN) sayesinde kullan\u0131c\u0131lara daha h\u0131zl\u0131 teslimat.<br \/>\n    *   <strong>Y\u00f6netim Kolayl\u0131\u011f\u0131:<\/strong> Altyap\u0131 y\u00f6netimi y\u00fck\u00fcn\u00fc ortadan kald\u0131r\u0131r.<\/p>\n<p>*   <strong>AWS S3 Entegrasyonu:<\/strong> Amazon S3 (Simple Storage Service), nesne depolama i\u00e7in end\u00fcstri standard\u0131d\u0131r. Node.js SDK&#8217;s\u0131 ile kolayca entegre edilebilir.<\/p>\n<pre><code class=\"language-javascript\">const AWS = require('aws-sdk');\n    const s3 = new AWS.S3({\n      accessKeyId: process.env.AWS_ACCESS_KEY_ID,\n      secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY,\n      region: process.env.AWS_REGION\n    });\n\n    \/\/ Y\u00fckleme fonksiyonu \u00f6rne\u011fi\n    const uploadToS3 = async (fileBuffer, fileName, mimetype) => {\n      const params = {\n        Bucket: process.env.AWS_BUCKET_NAME,\n        Key: fileName,\n        Body: fileBuffer,\n        ContentType: mimetype,\n        ACL: 'public-read' \/\/ Genel eri\u015fime a\u00e7\u0131k olmas\u0131 i\u00e7in\n      };\n      return s3.upload(params).promise();\n    };<\/code><\/pre>\n<p>*   <strong>Cloudinary:<\/strong> G\u00f6rsel ve video y\u00f6netimi i\u00e7in \u00f6zel olarak tasarlanm\u0131\u015f bir bulut hizmetidir. Y\u00fckleme, depolama, g\u00f6rsel i\u015fleme (boyutland\u0131rma, filtreleme, optimizasyon) ve CDN teslimat\u0131n\u0131 tek bir platformda birle\u015ftirir. \u00d6zellikle g\u00f6rsel manip\u00fclasyonu yo\u011fun olan uygulamalar i\u00e7in \u00e7ok g\u00fc\u00e7l\u00fc bir \u00e7\u00f6z\u00fcmd\u00fcr.<\/p>\n<h4>G\u00f6rsel \u0130\u015fleme K\u00fct\u00fcphaneleri (Sharp, Jimp)<\/h4>\n<p>Y\u00fcklenen g\u00f6rsellerin web i\u00e7in optimize edilmesi, kullan\u0131c\u0131 deneyimi ve performans a\u00e7\u0131s\u0131ndan hayati \u00f6neme sahiptir.<\/p>\n<p>*   <strong>Neden G\u00f6rsel \u0130\u015fleme?<\/strong><br \/>\n    *   <strong>Boyutland\u0131rma:<\/strong> Farkl\u0131 ekran boyutlar\u0131 ve kullan\u0131m senaryolar\u0131 i\u00e7in (thumbnail, orta, b\u00fcy\u00fck) g\u00f6rsellerin yeniden boyutland\u0131r\u0131lmas\u0131.<br \/>\n    *   <strong>S\u0131k\u0131\u015ft\u0131rma:<\/strong> Dosya boyutunu d\u00fc\u015f\u00fcrerek y\u00fckleme s\u00fcrelerini k\u0131saltma.<br \/>\n    *   <strong>Format D\u00f6n\u00fc\u015ft\u00fcrme:<\/strong> WebP gibi modern ve verimli formatlara d\u00f6n\u00fc\u015ft\u00fcrme.<br \/>\n    *   <strong>Filigran Ekleme:<\/strong> Telif hakk\u0131 korumas\u0131 veya marka bilinirli\u011fi i\u00e7in.<br \/>\n    *   <strong>K\u0131rpma, D\u00f6nd\u00fcrme vb.<\/strong><\/p>\n<p>*   <strong>Sharp:<\/strong> Node.js i\u00e7in y\u00fcksek performansl\u0131 bir g\u00f6rsel i\u015fleme k\u00fct\u00fcphanesidir. Libvips k\u00fct\u00fcphanesi \u00fczerine in\u015fa edilmi\u015ftir ve \u00e7ok h\u0131zl\u0131d\u0131r. \u00d6zellikle bellek \u00fczerinde (Multer <code>memoryStorage<\/code> ile gelen buffer&#8217;lar \u00fczerinde) i\u015flem yapabilmesi b\u00fcy\u00fck bir avantajd\u0131r.<\/p>\n<pre><code class=\"language-javascript\">const sharp = require('sharp');\n\n    const processImage = async (buffer) => {\n      const metadata = await sharp(buffer).metadata();\n      const resizedBuffer = await sharp(buffer)\n        .resize({ width: 800, withoutEnlargement: true }) \/\/ Geni\u015fli\u011fi 800px yap, b\u00fcy\u00fctme\n        .webp({ quality: 80 }) \/\/ WebP format\u0131na d\u00f6n\u00fc\u015ft\u00fcr, kalite %80\n        .toBuffer();\n      return resizedBuffer;\n    };<\/code><\/pre>\n<p>*   <strong>Jimp:<\/strong> Tamamen JavaScript ile yaz\u0131lm\u0131\u015f bir g\u00f6rsel i\u015fleme k\u00fct\u00fcphanesidir. Sharp kadar performansl\u0131 olmasa da, daha basit projeler veya sadece JavaScript ba\u011f\u0131ml\u0131l\u0131\u011f\u0131 istenen durumlar i\u00e7in iyi bir alternatiftir.<\/p>\n<h3>Ad\u0131m Ad\u0131m Geli\u015fmi\u015f Foto\u011fraf Y\u00fckleme Uygulamas\u0131<\/h3>\n<p>\u015eimdi t\u00fcm bu ara\u00e7lar\u0131 bir araya getirerek geli\u015fmi\u015f bir foto\u011fraf y\u00fckleme uygulamas\u0131 olu\u015ftural\u0131m. Bu \u00f6rnekte AWS S3 ve Sharp kullanaca\u011f\u0131z.<\/p>\n<h4>1. Proje Kurulumu ve Ba\u011f\u0131ml\u0131l\u0131klar<\/h4>\n<p>Yeni bir Node.js projesi olu\u015ftural\u0131m ve gerekli paketleri kural\u0131m:<\/p>\n<pre><code class=\"language-bash\">mkdir advanced-photo-upload\ncd advanced-photo-upload\nnpm init -y\nnpm install express multer aws-sdk sharp dotenv<\/code><\/pre>\n<p><code>.env<\/code> dosyas\u0131n\u0131 kullanarak AWS kimlik bilgilerini ve S3 bucket ad\u0131n\u0131 saklayaca\u011f\u0131z.<\/p>\n<pre><code class=\"language-\"># .env\nAWS_ACCESS_KEY_ID=YOUR_AWS_ACCESS_KEY_ID\nAWS_SECRET_ACCESS_KEY=YOUR_AWS_SECRET_ACCESS_KEY\nAWS_REGION=YOUR_AWS_REGION # \u00f6rn: eu-central-1\nAWS_BUCKET_NAME=YOUR_S3_BUCKET_NAME<\/code><\/pre>\n<h4>2. Express Uygulamas\u0131n\u0131n Temeli<\/h4>\n<p><code>server.js<\/code> dosyas\u0131n\u0131 olu\u015ftural\u0131m:<\/p>\n<pre><code class=\"language-javascript\">require('dotenv').config(); \/\/ .env dosyas\u0131n\u0131 y\u00fckle\n\nconst express = require('express');\nconst app = express();\nconst PORT = process.env.PORT || 3000;\n\napp.use(express.json()); \/\/ JSON body parsing\napp.use(express.static('public')); \/\/ Statik dosyalar i\u00e7in 'public' klas\u00f6r\u00fc\n\napp.get('\/', (req, res) => {\n  res.sendFile(__dirname + '\/public\/index.html');\n});\n\napp.listen(PORT, () => {\n  console.log(<code>Server ${PORT} portunda \u00e7al\u0131\u015f\u0131yor.<\/code>);\n});<\/code><\/pre>\n<p><code>public\/index.html<\/code> basit bir y\u00fckleme formu i\u00e7erecek:<\/p>\n<pre><code class=\"language-html\"><!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n    <title>Geli\u015fmi\u015f Foto\u011fraf Y\u00fckleme<\/title>\n    <style>\n        body { font-family: sans-serif; margin: 20px; }\n        .container { max-width: 600px; margin: auto; padding: 20px; border: 1px solid #ddd; border-radius: 8px; }\n        input[type=\"file\"] { display: block; margin-bottom: 15px; }\n        button { padding: 10px 20px; background-color: #007bff; color: white; border: none; border-radius: 5px; cursor: pointer; }\n        button:hover { background-color: #0056b3; }\n        #message { margin-top: 20px; color: green; }\n        #error { margin-top: 20px; color: red; }\n        #preview { margin-top: 20px; max-width: 100%; height: auto; display: block; }\n    <\/style>\n<\/head>\n<body>\n    <div class=\"container\">\n        <h2>Foto\u011fraf Y\u00fckle<\/h2>\n        <form id=\"uploadForm\" enctype=\"multipart\/form-data\">\n            <input type=\"file\" name=\"image\" id=\"imageInput\" accept=\"image\/*\" multiple>\n            <button type=\"submit\">Y\u00fckle<\/button>\n        <\/form>\n        <p id=\"message\"><\/p>\n        <p id=\"error\"><\/p>\n        <img decoding=\"async\" id=\"preview\" src=\"#\" alt=\"Y\u00fcklenen G\u00f6rsel \u00d6nizlemesi\" style=\"display: none;\">\n    <\/div>\n\n    <script>\n        const uploadForm = document.getElementById('uploadForm');\n        const imageInput = document.getElementById('imageInput');\n        const messageDiv = document.getElementById('message');\n        const errorDiv = document.getElementById('error');\n        const previewImg = document.getElementById('preview');\n\n        uploadForm.addEventListener('submit', async (e) => {\n            e.preventDefault();\n            messageDiv.textContent = '';\n            errorDiv.textContent = '';\n            previewImg.style.display = 'none';\n\n            const formData = new FormData();\n            \/\/ Birden fazla dosya se\u00e7ildiyse her birini FormData'ya ekle\n            for (const file of imageInput.files) {\n                formData.append('image', file);\n            }\n\n            if (imageInput.files.length === 0) {\n                errorDiv.textContent = 'L\u00fctfen bir dosya se\u00e7in.';\n                return;\n            }\n\n            try {\n                const response = await fetch('\/upload', {\n                    method: 'POST',\n                    body: formData,\n                });\n\n                const data = await response.json();\n\n                if (response.ok) {\n                    messageDiv.textContent = data.message;\n                    if (data.urls && data.urls.length > 0) {\n                        \/\/ Sadece ilk g\u00f6rseli \u00f6nizleyelim\n                        previewImg.src = data.urls[0];\n                        previewImg.style.display = 'block';\n                    }\n                } else {\n                    errorDiv.textContent = data.error || 'Y\u00fckleme ba\u015far\u0131s\u0131z oldu.';\n                }\n            } catch (err) {\n                errorDiv.textContent = 'Bir hata olu\u015ftu: ' + err.message;\n            }\n        });\n    <\/script>\n<\/body>\n<\/html><\/code><\/pre>\n<h4>3. Multer ve AWS S3 Yap\u0131land\u0131rmas\u0131<\/h4>\n<p><code>server.js<\/code> dosyas\u0131n\u0131 g\u00fcncelleyelim. Multer&#8217;\u0131 <code>memoryStorage<\/code> ile yap\u0131land\u0131raca\u011f\u0131z, b\u00f6ylece Sharp ile kolayca g\u00f6rsel i\u015fleme yapabiliriz.<\/p>\n<pre><code class=\"language-javascript\">\/\/ ... (ba\u015flang\u0131\u00e7taki require ve app tan\u0131mlamalar\u0131)\n\nconst multer = require('multer');\nconst AWS = require('aws-sdk');\nconst sharp = require('sharp');\nconst { v4: uuidv4 } = require('uuid'); \/\/ Benzersiz dosya adlar\u0131 i\u00e7in\n\n\/\/ AWS S3 yap\u0131land\u0131rmas\u0131\nconst s3 = new AWS.S3({\n  accessKeyId: process.env.AWS_ACCESS_KEY_ID,\n  secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY,\n  region: process.env.AWS_REGION\n});\n\n\/\/ Multer yap\u0131land\u0131rmas\u0131: Dosyalar\u0131 bellekte tut\nconst upload = multer({\n  storage: multer.memoryStorage(), \/\/ Dosyalar\u0131 bellekte buffer olarak sakla\n  limits: { fileSize: 1024 <em> 1024 <\/em> 10 }, \/\/ Maksimum 10 MB dosya boyutu\n  fileFilter: (req, file, cb) => {\n    \/\/ Sadece g\u00f6rsel dosyalar\u0131na izin ver\n    if (file.mimetype.startsWith('image\/')) {\n      cb(null, true);\n    } else {\n      cb(new Error('Sadece g\u00f6rsel dosyalar\u0131 y\u00fcklenebilir!'), false);\n    }\n  }\n});\n\n\/\/ ... (app.get ve app.listen)<\/code><\/pre>\n<h4>4. Y\u00fckleme Rotas\u0131 ve \u0130\u015fleme Mant\u0131\u011f\u0131<\/h4>\n<p>\u015eimdi <code>\/upload<\/code> rotas\u0131n\u0131 tan\u0131mlayal\u0131m. Bu rotada Multer ile dosyay\u0131 alacak, Sharp ile i\u015fleyecek ve S3&#8217;e y\u00fckleyece\u011fiz.<\/p>\n<pre><code class=\"language-javascript\">\/\/ ... (\u00f6nceki kodlar)\n\napp.post('\/upload', upload.array('image', 5), async (req, res) => { \/\/ 'image' alan\u0131, en fazla 5 dosya\n  if (!req.files || req.files.length === 0) {\n    return res.status(400).json({ error: 'Dosya se\u00e7ilmedi.' });\n  }\n\n  const uploadedUrls = [];\n  const errors = [];\n\n  for (const file of req.files) {\n    try {\n      \/\/ 1. G\u00f6rsel \u0130\u015fleme (Sharp ile)\n      \/\/ Orijinal g\u00f6rseli de kaydetmek isteyebiliriz, veya sadece i\u015flenmi\u015f halini.\n      \/\/ Bu \u00f6rnekte sadece i\u015flenmi\u015f (k\u00fc\u00e7\u00fclt\u00fclm\u00fc\u015f ve WebP) halini y\u00fckl\u00fcyoruz.\n      const processedBuffer = await sharp(file.buffer)\n        .resize({ width: 1200, height: 1200, fit: 'inside', withoutEnlargement: true }) \/\/ Maks 1200px geni\u015flik\/y\u00fckseklik\n        .webp({ quality: 80 }) \/\/ WebP format\u0131na d\u00f6n\u00fc\u015ft\u00fcr, kalite %80\n        .toBuffer();\n\n      \/\/ 2. Benzersiz Dosya Ad\u0131 Olu\u015fturma\n      const uniqueFileName = <code>${uuidv4()}.webp<\/code>; \/\/ WebP format\u0131na d\u00f6n\u00fc\u015ft\u00fcrd\u00fc\u011f\u00fcm\u00fcz i\u00e7in uzant\u0131y\u0131 .webp yap\u0131yoruz\n\n      \/\/ 3. S3'e Y\u00fckleme\n      const params = {\n        Bucket: process.env.AWS_BUCKET_NAME,\n        Key: <code>images\/${uniqueFileName}<\/code>, \/\/ S3'te 'images' klas\u00f6r\u00fc alt\u0131na kaydet\n        Body: processedBuffer,\n        ContentType: 'image\/webp', \/\/ WebP olarak y\u00fcklendi\u011fi i\u00e7in Content-Type'\u0131 ayarla\n        ACL: 'public-read' \/\/ Genel eri\u015fime a\u00e7\u0131k olmas\u0131 i\u00e7in\n      };\n\n      const s3UploadResult = await s3.upload(params).promise();\n      uploadedUrls.push(s3UploadResult.Location); \/\/ Y\u00fcklenen dosyan\u0131n URL'sini kaydet\n\n    } catch (err) {\n      console.error('Dosya i\u015flenirken veya S3\\'e y\u00fcklenirken hata olu\u015ftu:', err);\n      errors.push(<code>Dosya \"${file.originalname}\" y\u00fcklenemedi: ${err.message}<\/code>);\n    }\n  }\n\n  if (errors.length > 0) {\n    return res.status(500).json({\n      error: 'Baz\u0131 dosyalar y\u00fcklenirken hata olu\u015ftu.',\n      details: errors,\n      uploadedUrls: uploadedUrls \/\/ Ba\u015far\u0131l\u0131 y\u00fcklenenleri de d\u00f6nd\u00fcrebiliriz\n    });\n  }\n\n  res.status(200).json({\n    message: <code>${uploadedUrls.length} dosya ba\u015far\u0131yla y\u00fcklendi.<\/code>,\n    urls: uploadedUrls\n  });\n});\n\n\/\/ ... (app.listen)<\/code><\/pre>\n<p><strong>A\u00e7\u0131klama:<\/strong><\/p>\n<p>*   <code>upload.array('image', 5)<\/code>: \u0130stemciden <code>name=\"image\"<\/code> ile gelen birden fazla dosyay\u0131 (en fazla 5 tane) kabul eder. Dosyalar <code>req.files<\/code> dizisinde buffer olarak bulunur.<br \/>\n*   <strong>G\u00f6rsel \u0130\u015fleme:<\/strong> <code>sharp(file.buffer)<\/code> ile bellekteki dosya buffer&#8217;\u0131n\u0131 al\u0131p <code>resize<\/code> ile boyutland\u0131r\u0131yor ve <code>webp<\/code> ile WebP format\u0131na d\u00f6n\u00fc\u015ft\u00fcrerek kalitesini optimize ediyoruz. <code>toBuffer()<\/code> ile i\u015flenmi\u015f g\u00f6rseli tekrar bir buffer olarak al\u0131yoruz.<br \/>\n*   <strong>Benzersiz Adland\u0131rma:<\/strong> <code>uuidv4()<\/code> kullanarak her dosya i\u00e7in benzersiz bir ad olu\u015fturuyoruz. Bu, dosya \u00e7ak\u0131\u015fmalar\u0131n\u0131 \u00f6nler ve g\u00fcvenlik a\u00e7\u0131s\u0131ndan da \u00f6nemlidir.<br \/>\n*   <strong>S3 Y\u00fckleme:<\/strong> <code>s3.upload(params).promise()<\/code> ile i\u015flenmi\u015f buffer&#8217;\u0131 S3&#8217;e y\u00fckl\u00fcyoruz. <code>Key<\/code> parametresi S3&#8217;teki dosya yolunu belirler. <code>ACL: 'public-read'<\/code> ile dosyan\u0131n herkes taraf\u0131ndan eri\u015filebilir olmas\u0131n\u0131 sa\u011fl\u0131yoruz.<br \/>\n*   <strong>Hata Y\u00f6netimi:<\/strong> Her dosya i\u00e7in ayr\u0131 ayr\u0131 <code>try-catch<\/code> bloklar\u0131 kullanarak hatalar\u0131 yakal\u0131yor ve kullan\u0131c\u0131ya uygun geri bildirim sa\u011fl\u0131yoruz.<\/p>\n<h4>5. Veritaban\u0131 Entegrasyonu (Opsiyonel ama \u00d6nemli)<\/h4>\n<p>Y\u00fcklenen g\u00f6rsellerin URL&#8217;lerini ve di\u011fer meta verilerini (kim y\u00fckledi, ne zaman y\u00fcklendi, orijinal ad\u0131, boyut vb.) bir veritaban\u0131na kaydetmek \u00f6nemlidir. Bu, g\u00f6rselleri daha sonra y\u00f6netmek, listelemek veya silmek i\u00e7in gereklidir.<\/p>\n<p><strong>\u00d6rnek Mongoose (MongoDB) Modeli:<\/strong><\/p>\n<pre><code class=\"language-javascript\">\/\/ models\/Image.js\nconst mongoose = require('mongoose');\n\nconst imageSchema = new mongoose.Schema({\n  userId: { type: mongoose.Schema.Types.ObjectId, ref: 'User' }, \/\/ Opsiyonel: Kullan\u0131c\u0131 ID'si\n  url: { type: String, required: true },\n  thumbnailUrl: String, \/\/ Opsiyonel: Thumbnail URL'si\n  originalName: String,\n  fileName: String, \/\/ S3'teki dosya ad\u0131\n  mimetype: String,\n  size: Number, \/\/ byte cinsinden\n  uploadDate: { type: Date, default: Date.now }\n});\n\nmodule.exports = mongoose.model('Image', imageSchema);<\/code><\/pre>\n<p>Y\u00fckleme rotas\u0131nda, S3&#8217;e ba\u015far\u0131l\u0131 y\u00fckleme sonras\u0131 bu veritaban\u0131 modelini kullanarak yeni bir kay\u0131t olu\u015fturabiliriz:<\/p>\n<pre><code class=\"language-javascript\">\/\/ ... (s3UploadResult sat\u0131r\u0131ndan sonra)\nconst Image = require('.\/models\/Image'); \/\/ Model dosyas\u0131n\u0131 import et\n\n\/\/ ...\nconst s3UploadResult = await s3.upload(params).promise();\nuploadedUrls.push(s3UploadResult.Location);\n\n\/\/ Veritaban\u0131na kaydet\nconst newImage = new Image({\n  \/\/ userId: req.user.id, \/\/ E\u011fer kullan\u0131c\u0131 giri\u015fi varsa\n  url: s3UploadResult.Location,\n  originalName: file.originalname,\n  fileName: uniqueFileName,\n  mimetype: 'image\/webp', \/\/ \u0130\u015flenmi\u015f format\n  size: processedBuffer.length \/\/ \u0130\u015flenmi\u015f dosyan\u0131n boyutu\n});\nawait newImage.save();\n\/\/ ...<\/code><\/pre>\n<h3>G\u00fcvenlik ve Performans Konular\u0131<\/h3>\n<p>Geli\u015fmi\u015f foto\u011fraf y\u00fckleme sistemleri kurarken g\u00fcvenlik ve performans\u0131 g\u00f6z ard\u0131 etmemek gerekir.<\/p>\n<h4>G\u00fcvenlik<\/h4>\n<p>*   <strong>Dosya T\u00fcr\u00fc Do\u011frulama (MIME Type):<\/strong> Hem istemci taraf\u0131nda (HTML <code>accept<\/code> \u00f6zniteli\u011fi, JavaScript kontrol\u00fc) hem de sunucu taraf\u0131nda (Multer <code>fileFilter<\/code>) dosya t\u00fcr\u00fcn\u00fc kontrol edin. Sadece beklenen t\u00fcrlere izin verin.<br \/>\n*   <strong>Boyut Limitleri:<\/strong> Sunucuya y\u00fcklenebilecek maksimum dosya boyutunu belirleyin (Multer <code>limits<\/code>). Bu, DoS sald\u0131r\u0131lar\u0131n\u0131 ve gereksiz depolama kullan\u0131m\u0131n\u0131 \u00f6nler.<br \/>\n*   <strong>Zararl\u0131 Dosya Y\u00fcklemeleri:<\/strong> G\u00f6rsel olarak g\u00f6r\u00fcnen ancak zararl\u0131 kod i\u00e7eren dosyalar (\u00f6rne\u011fin, PHP kodlu <code>.jpg<\/code> dosyalar\u0131) potansiyel bir tehdittir. G\u00f6rsel i\u015fleme k\u00fct\u00fcphaneleri (Sharp gibi) bu t\u00fcr dosyalar\u0131 genellikle temizler veya yeniden kaydeder. Ancak ek g\u00fcvenlik i\u00e7in dosya i\u00e7eri\u011fini analiz eden \u00e7\u00f6z\u00fcmler d\u00fc\u015f\u00fcn\u00fclebilir.<br \/>\n*   <strong>Dosya Adland\u0131rma:<\/strong> Kullan\u0131c\u0131 taraf\u0131ndan sa\u011flanan dosya adlar\u0131n\u0131 do\u011frudan kullanmaktan ka\u00e7\u0131n\u0131n. Bunun yerine UUID gibi benzersiz adlar olu\u015fturun. Bu, dizin ge\u00e7i\u015fi (path traversal) sald\u0131r\u0131lar\u0131n\u0131 ve dosya \u00e7ak\u0131\u015fmalar\u0131n\u0131 \u00f6nler.<br \/>\n*   <strong>Kimlik Do\u011frulama ve Yetkilendirme:<\/strong> Y\u00fckleme rotas\u0131n\u0131 sadece yetkili kullan\u0131c\u0131lar\u0131n eri\u015fimine a\u00e7\u0131n. Kullan\u0131c\u0131lar kendi foto\u011fraflar\u0131n\u0131 m\u0131 y\u00fckl\u00fcyor, yoksa ba\u015fkalar\u0131n\u0131n foto\u011fraflar\u0131n\u0131 m\u0131 de\u011fi\u015ftirmeye \u00e7al\u0131\u015f\u0131yor?<br \/>\n*   <strong>S3 Bucket Politikalar\u0131:<\/strong> S3 bucket&#8217;\u0131n\u0131z i\u00e7in uygun eri\u015fim politikalar\u0131 ayarlay\u0131n. Sadece uygulaman\u0131z\u0131n ihtiya\u00e7 duydu\u011fu minimum izinleri verin. \u00d6rne\u011fin, sadece belirli bir IP aral\u0131\u011f\u0131ndan veya IAM rol\u00fcnden y\u00fcklemeye izin verin.<\/p>\n<h4>Performans<\/h4>\n<p>*   <strong>G\u00f6rsel Optimizasyonu:<\/strong> Sharp gibi k\u00fct\u00fcphanelerle g\u00f6rselleri boyutland\u0131r\u0131n, s\u0131k\u0131\u015ft\u0131r\u0131n ve modern formatlara (WebP) d\u00f6n\u00fc\u015ft\u00fcr\u00fcn. Bu, dosya boyutunu \u00f6nemli \u00f6l\u00e7\u00fcde azalt\u0131r ve y\u00fckleme s\u00fcrelerini h\u0131zland\u0131r\u0131r.<br \/>\n*   <strong>CDN Kullan\u0131m\u0131:<\/strong> Bulut depolama hizmetleri genellikle CDN (Content Delivery Network) entegrasyonu sunar. G\u00f6rselleri CDN \u00fczerinden sunmak, kullan\u0131c\u0131lara co\u011frafi olarak daha yak\u0131n sunuculardan teslim edilmesini sa\u011flayarak y\u00fckleme s\u00fcrelerini k\u0131salt\u0131r.<br \/>\n*   <strong>Asenkron Y\u00fckleme:<\/strong> \u0130stemci taraf\u0131nda AJAX veya Fetch API kullanarak dosyalar\u0131 asenkron olarak y\u00fckleyin. Bu, sayfan\u0131n yenilenmesini engeller ve kullan\u0131c\u0131 deneyimini iyile\u015ftirir.<br \/>\n*   <strong>Y\u00fckleme \u0130lerlemesi:<\/strong> \u0130stemcide y\u00fckleme ilerlemesini g\u00f6steren bir g\u00f6sterge (progress bar) eklemek, b\u00fcy\u00fck dosyalar\u0131n y\u00fcklenmesi s\u0131ras\u0131nda kullan\u0131c\u0131n\u0131n bekleme s\u00fcresini daha katlan\u0131labilir hale getirir.<br \/>\n*   <strong>Lazy Loading:<\/strong> G\u00f6rselleri sayfa y\u00fcklendi\u011finde de\u011fil, kullan\u0131c\u0131n\u0131n ekran\u0131nda g\u00f6r\u00fcn\u00fcr hale geldiklerinde y\u00fcklemek (lazy loading), sayfan\u0131n ilk y\u00fcklenme h\u0131z\u0131n\u0131 art\u0131r\u0131r.<br \/>\n*   <strong>Bellek Y\u00f6netimi:<\/strong> Multer <code>memoryStorage<\/code> kullan\u0131yorsan\u0131z, i\u015flem sonras\u0131 buffer&#8217;lar\u0131 temizlemek i\u00e7in dikkatli olun. Node.js&#8217;in \u00e7\u00f6p toplay\u0131c\u0131s\u0131 genellikle bunu halleder, ancak \u00e7ok yo\u011fun y\u00fckleme senaryolar\u0131nda bellek s\u0131z\u0131nt\u0131lar\u0131n\u0131 \u00f6nlemek i\u00e7in ek \u00f6nlemler gerekebilir.<\/p>\n<h3>Sonu\u00e7<\/h3>\n<p>Node.js ve Express ile geli\u015fmi\u015f foto\u011fraf y\u00fckleme i\u015flevselli\u011fi olu\u015fturmak, Multer gibi g\u00fc\u00e7l\u00fc middleware&#8217;ler, Sharp gibi g\u00f6rsel i\u015fleme k\u00fct\u00fcphaneleri ve AWS S3 gibi bulut depolama hizmetlerinin birle\u015fimiyle m\u00fcmk\u00fcnd\u00fcr. Bu yakla\u015f\u0131m, sadece dosya y\u00fcklemekle kalmay\u0131p, ayn\u0131 zamanda performans\u0131 optimize edilmi\u015f, g\u00fcvenli ve kullan\u0131c\u0131 dostu bir deneyim sunan bir sistem in\u015fa etmenizi sa\u011flar.<\/p>\n<p>Bu makalede ele ald\u0131\u011f\u0131m\u0131z ad\u0131mlar ve ara\u00e7lar, temel bir geli\u015fmi\u015f y\u00fckleme sistemi i\u00e7in sa\u011flam bir temel olu\u015fturur. Uygulaman\u0131z\u0131n ihtiya\u00e7lar\u0131na g\u00f6re daha fazla \u00f6zellik (s\u00fcr\u00fckle-b\u0131rak, \u00e7oklu s\u00fcr\u00fcm y\u00f6netimi, video y\u00fckleme, AI tabanl\u0131 etiketleme vb.) ekleyerek bu sistemi daha da geli\u015ftirebilirsiniz. Unutmay\u0131n ki, her bile\u015fenin do\u011fru yap\u0131land\u0131r\u0131lmas\u0131 ve g\u00fcvenlik en iyi uygulamalar\u0131n\u0131n takip edilmesi, uygulaman\u0131z\u0131n uzun \u00f6m\u00fcrl\u00fc ve sorunsuz \u00e7al\u0131\u015fmas\u0131n\u0131 sa\u011flayacakt\u0131r.<\/body><\/p>\n","protected":false},"excerpt":{"rendered":"Geli\u015fmi\u015f Foto\u011fraf Y\u00fckleme \u0130\u015flevselli\u011fini Node.js ve Express ile Entegre Etme\nFoto\u011fraf y\u00fckleme, modern web uygulamalar\u0131n\u0131n vazge\u00e7ilmez bir","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-35169","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>Geli\u015fmi\u015f Foto\u011fraf Y\u00fckleme \u0130\u015flevselli\u011fini Node.js ve Express ile Entegre Etme - Kodlar\u0131n Gizemli D\u00fcnyas\u0131<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/fatihsoysal.com\/blog\/gelismis-fotograf-yukleme-islevselligini-node-js-ve-express-ile-entegre-etme\/\" \/>\n<meta property=\"og:locale\" content=\"tr_TR\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Geli\u015fmi\u015f Foto\u011fraf Y\u00fckleme \u0130\u015flevselli\u011fini Node.js ve Express ile Entegre Etme\" \/>\n<meta property=\"og:description\" content=\"Geli\u015fmi\u015f Foto\u011fraf Y\u00fckleme \u0130\u015flevselli\u011fini Node.js ve Express ile Entegre Etme Foto\u011fraf y\u00fckleme, modern web uygulamalar\u0131n\u0131n vazge\u00e7ilmez bir\" \/>\n<meta property=\"og:url\" content=\"https:\/\/fatihsoysal.com\/blog\/gelismis-fotograf-yukleme-islevselligini-node-js-ve-express-ile-entegre-etme\/\" \/>\n<meta property=\"og:site_name\" content=\"Kodlar\u0131n Gizemli D\u00fcnyas\u0131\" \/>\n<meta property=\"article:published_time\" content=\"2025-11-26T10:40:46+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=\"15 dakika\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/fatihsoysal.com\/blog\/gelismis-fotograf-yukleme-islevselligini-node-js-ve-express-ile-entegre-etme\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/fatihsoysal.com\/blog\/gelismis-fotograf-yukleme-islevselligini-node-js-ve-express-ile-entegre-etme\/\"},\"author\":{\"name\":\"Fatih Soysal\",\"@id\":\"https:\/\/fatihsoysal.com\/blog\/#\/schema\/person\/002a254750921dcfd568a99e48240dd1\"},\"headline\":\"Geli\u015fmi\u015f Foto\u011fraf Y\u00fckleme \u0130\u015flevselli\u011fini Node.js ve Express ile Entegre Etme\",\"datePublished\":\"2025-11-26T10:40:46+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/fatihsoysal.com\/blog\/gelismis-fotograf-yukleme-islevselligini-node-js-ve-express-ile-entegre-etme\/\"},\"wordCount\":2187,\"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\/gelismis-fotograf-yukleme-islevselligini-node-js-ve-express-ile-entegre-etme\/#respond\"]}],\"copyrightYear\":\"2025\",\"copyrightHolder\":{\"@id\":\"https:\/\/fatihsoysal.com\/blog\/#organization\"}},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/fatihsoysal.com\/blog\/gelismis-fotograf-yukleme-islevselligini-node-js-ve-express-ile-entegre-etme\/\",\"url\":\"https:\/\/fatihsoysal.com\/blog\/gelismis-fotograf-yukleme-islevselligini-node-js-ve-express-ile-entegre-etme\/\",\"name\":\"Geli\u015fmi\u015f Foto\u011fraf Y\u00fckleme \u0130\u015flevselli\u011fini Node.js ve Express ile Entegre Etme - Kodlar\u0131n Gizemli D\u00fcnyas\u0131\",\"isPartOf\":{\"@id\":\"https:\/\/fatihsoysal.com\/blog\/#website\"},\"datePublished\":\"2025-11-26T10:40:46+00:00\",\"breadcrumb\":{\"@id\":\"https:\/\/fatihsoysal.com\/blog\/gelismis-fotograf-yukleme-islevselligini-node-js-ve-express-ile-entegre-etme\/#breadcrumb\"},\"inLanguage\":\"tr\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/fatihsoysal.com\/blog\/gelismis-fotograf-yukleme-islevselligini-node-js-ve-express-ile-entegre-etme\/\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/fatihsoysal.com\/blog\/gelismis-fotograf-yukleme-islevselligini-node-js-ve-express-ile-entegre-etme\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Anasayfa\",\"item\":\"https:\/\/fatihsoysal.com\/blog\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Geli\u015fmi\u015f Foto\u011fraf Y\u00fckleme \u0130\u015flevselli\u011fini Node.js ve Express ile Entegre Etme\"}]},{\"@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":"Geli\u015fmi\u015f Foto\u011fraf Y\u00fckleme \u0130\u015flevselli\u011fini Node.js ve Express ile Entegre Etme - Kodlar\u0131n Gizemli D\u00fcnyas\u0131","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/fatihsoysal.com\/blog\/gelismis-fotograf-yukleme-islevselligini-node-js-ve-express-ile-entegre-etme\/","og_locale":"tr_TR","og_type":"article","og_title":"Geli\u015fmi\u015f Foto\u011fraf Y\u00fckleme \u0130\u015flevselli\u011fini Node.js ve Express ile Entegre Etme","og_description":"Geli\u015fmi\u015f Foto\u011fraf Y\u00fckleme \u0130\u015flevselli\u011fini Node.js ve Express ile Entegre Etme Foto\u011fraf y\u00fckleme, modern web uygulamalar\u0131n\u0131n vazge\u00e7ilmez bir","og_url":"https:\/\/fatihsoysal.com\/blog\/gelismis-fotograf-yukleme-islevselligini-node-js-ve-express-ile-entegre-etme\/","og_site_name":"Kodlar\u0131n Gizemli D\u00fcnyas\u0131","article_published_time":"2025-11-26T10:40:46+00:00","author":"Fatih Soysal","twitter_card":"summary_large_image","twitter_misc":{"Yazan:":"Fatih Soysal","Tahmini okuma s\u00fcresi":"15 dakika"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/fatihsoysal.com\/blog\/gelismis-fotograf-yukleme-islevselligini-node-js-ve-express-ile-entegre-etme\/#article","isPartOf":{"@id":"https:\/\/fatihsoysal.com\/blog\/gelismis-fotograf-yukleme-islevselligini-node-js-ve-express-ile-entegre-etme\/"},"author":{"name":"Fatih Soysal","@id":"https:\/\/fatihsoysal.com\/blog\/#\/schema\/person\/002a254750921dcfd568a99e48240dd1"},"headline":"Geli\u015fmi\u015f Foto\u011fraf Y\u00fckleme \u0130\u015flevselli\u011fini Node.js ve Express ile Entegre Etme","datePublished":"2025-11-26T10:40:46+00:00","mainEntityOfPage":{"@id":"https:\/\/fatihsoysal.com\/blog\/gelismis-fotograf-yukleme-islevselligini-node-js-ve-express-ile-entegre-etme\/"},"wordCount":2187,"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\/gelismis-fotograf-yukleme-islevselligini-node-js-ve-express-ile-entegre-etme\/#respond"]}],"copyrightYear":"2025","copyrightHolder":{"@id":"https:\/\/fatihsoysal.com\/blog\/#organization"}},{"@type":"WebPage","@id":"https:\/\/fatihsoysal.com\/blog\/gelismis-fotograf-yukleme-islevselligini-node-js-ve-express-ile-entegre-etme\/","url":"https:\/\/fatihsoysal.com\/blog\/gelismis-fotograf-yukleme-islevselligini-node-js-ve-express-ile-entegre-etme\/","name":"Geli\u015fmi\u015f Foto\u011fraf Y\u00fckleme \u0130\u015flevselli\u011fini Node.js ve Express ile Entegre Etme - Kodlar\u0131n Gizemli D\u00fcnyas\u0131","isPartOf":{"@id":"https:\/\/fatihsoysal.com\/blog\/#website"},"datePublished":"2025-11-26T10:40:46+00:00","breadcrumb":{"@id":"https:\/\/fatihsoysal.com\/blog\/gelismis-fotograf-yukleme-islevselligini-node-js-ve-express-ile-entegre-etme\/#breadcrumb"},"inLanguage":"tr","potentialAction":[{"@type":"ReadAction","target":["https:\/\/fatihsoysal.com\/blog\/gelismis-fotograf-yukleme-islevselligini-node-js-ve-express-ile-entegre-etme\/"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/fatihsoysal.com\/blog\/gelismis-fotograf-yukleme-islevselligini-node-js-ve-express-ile-entegre-etme\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Anasayfa","item":"https:\/\/fatihsoysal.com\/blog\/"},{"@type":"ListItem","position":2,"name":"Geli\u015fmi\u015f Foto\u011fraf Y\u00fckleme \u0130\u015flevselli\u011fini Node.js ve Express ile Entegre Etme"}]},{"@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\/35169","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=35169"}],"version-history":[{"count":1,"href":"https:\/\/fatihsoysal.com\/blog\/wp-json\/wp\/v2\/posts\/35169\/revisions"}],"predecessor-version":[{"id":35170,"href":"https:\/\/fatihsoysal.com\/blog\/wp-json\/wp\/v2\/posts\/35169\/revisions\/35170"}],"wp:attachment":[{"href":"https:\/\/fatihsoysal.com\/blog\/wp-json\/wp\/v2\/media?parent=35169"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/fatihsoysal.com\/blog\/wp-json\/wp\/v2\/categories?post=35169"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/fatihsoysal.com\/blog\/wp-json\/wp\/v2\/tags?post=35169"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}