Gönderdiğiniz müfredat dosyasını inceledim. İçerik oldukça kapsamlı olduğu ve her konunun derinlemesine, bol örnek ve uygulamalarla açıklanmasını istediğiniz için bu eğitimi bölümlere ayırarak parça parça ele alacağız.

Bu ilk aşamada, talep ettiğiniz üzere öncelikle "Öğrenecekleriniz" bölümünü detaylıca açıklayacak, ardından müfredatın ilk kısımlarını (Node.js Temelleri, Express ve API Dünyası) satır satır işleyerek gerçek dünya örnekleri ve kod uygulamalarıyla tasarlayacağız.


🌟 "Öğrenecekleriniz" Bölümünün Detaylı Açıklaması

Bu kurs, modern bir arka plan (back-end) yazılımcısının bilmesi gereken tüm temel ve ileri düzey becerileri uygulamalı olarak kazandırmayı hedeflemektedir. Maddelerin sektörel karşılıkları ve anlamları şunlardır:


🛠 BÖLÜM 1: Giriş & Node.js Kurulumu ve Proje Yapılandırması

➡️ Node.js ve VS Code Kurulumu

Node.js, JavaScript kodlarımızı bilgisayarımızda veya sunucuda doğrudan çalıştıran bir çalışma ortamıdır (runtime). VS Code ise bu kodları en verimli şekilde yazacağımız editördür.

➡️ Yeni Bir Node Projesi Oluşturma & package.json Mantığı

Her Node.js projesi bir klasör ve o klasörün kimlik kartı olan package.json dosyası ile başlar.

Uygulama: Terminali açıp aşağıdaki komutu yazdığımızda projemiz canlanır:

npm init -y

Bu komut projemize kök dizinde bir package.json dosyası kazandırır. Bu dosya, projenin adını, versiyonunu ve projemizde kullanacağımız dış paketlerin (kütüphanelerin) listesini tutar.

➡️ NPM ile Paket Yönetimi (Ekleme ve Çıkarma)

NPM (Node Package Manager), başkalarının yazdığı kod kütüphanelerini projemize dahil etmemizi sağlar.


🛠 BÖLÜM 2: Node.js Esasları (Express, MongoDB ve Yapılandırma)

➡️ Express Framework

Node.js'in yalın haliyle web sunucusu yapmak çok uzun kodlar gerektirir. Express, HTTP isteklerini (GET, POST vb.) kolayca yönetmemizi sağlayan, Node.js üzerindeki en popüler web çatısıdır.

Kod Örneği (İlk Sunucumuz):

const express = require('express');

const app = express();

const PORT = 3000;

 

// Get Routes: Tarayıcıdan bir istek geldiğinde yanıt dönme

app.get('/', (req, res) => {

    res.send('Node.js Dünyasına Hoş Geldiniz!');

});

 

app.listen(PORT, () => {

    console.log(`Sunucu ${PORT} portunda başarıyla çalışıyor.`);

});

➡️ Nodemon Kullanımı

Normal şartlarda kodumuzda bir değişiklik yaptığımızda sunucuyu kapatıp (CTRL + C) tekrar açmamız gerekir. Nodemon paketi, biz kodu kaydettiğimiz anda sunucuyu otomatik olarak yeniden başlatır.
Kurulum:
npm install -g nodemon ya da proje içine npm install --save-dev nodemon.

➡️ Ortam Değişkenleri (dotenv) ve .gitignore

Uygulama (.env dosyası):

PORT=5000

MONGO_URI=mongodb+srv://kullanici:sifre@cluster.mongodb.net/testDB

Uygulama (Kod içinde çağırma):

require('dotenv').config();

console.log(process.env.PORT); // Çıktı: 5000

➡️ Veri Tabanı Bağlantısı: Mongo & Mongoose

MongoDB, verileri esnek (JSON benzeri) dökümanlar halinde tutan modern bir NoSQL veri tabanıdır. Mongoose ise bu veri tabanına bağlanmamızı ve verilerin belirli bir şablona (Model) uymasını sağlayan köprü kütüphanedir.


🛠 BÖLÜM 3: API'ler ve Veri Tabanı İle Çalışma (CRUD İşlemleri)

Bu bölümde gerçek bir "Kitaplık Yönetim API'si" tasarlayarak CRUD işlemlerini, modelleri ayırmayı ve Postman testlerini simüle edeceğiz.

➡️ Modeli Ayırma (Separate Model)

Veri tabanındaki koleksiyonlarımızın şemasını bağımsız dosyalarda tutarız.

Uygulama: models/Book.js

const mongoose = require('mongoose');

 

const BookSchema = new mongoose.Schema({

    title: { type: String, required: true },

    author: { type: String, required: true },

    pages: Number,

    createdAt: { type: Date, default: Date.now }

});

 

// MongoDB'deki nesnelerin default gelen "_id" alanını temiz bir "id" olarak döndürme ayarı

BookSchema.virtual('id').get(function(){

    return this._id.toHexString();

});

BookSchema.set('toJSON', { virtuals: true });

 

module.exports = mongoose.model('Book', BookSchema);

➡️ Rotaları Ayırma ve CRUD Operasyonları (Separate Route & Try Catch)

Tüm HTTP isteklerini ana dosyada toplamak yerine iş kollarına göre rotalara böleriz. Hataları yakalamak ve sunucunun çökmesini önlemek için mutlaka try-catch blokları kullanırız.

Uygulama: routes/bookRoutes.js

const express = require('express');

const router = express.Router();

const Book = require('../models/Book');

 

// 1. CREATE: Yeni Kitap Ekleme (POST)

router.post('/', async (req, res) => {

    try {

        const newBook = new Book(req.body);

        const savedBook = await newBook.save(); // Veri tabanına kaydeder

        res.status(211).json(savedBook); // 211: Http Status Code - Created

    } catch (error) {

        res.status(500).json({ message: "Veri kaydedilirken hata oluştu." });

    }

});

 

// 2. READ: Tüm Kitapları Listeleme (GET)

router.get('/', async (req, res) => {

    try {

        const books = await Book.find();

        res.status(200).json(books); // 200: OK

    } catch (error) {

        res.status(500).json({ message: error.message });

    }

});

 

// 3. READ BY ID: Belirli Bir Kitabı Detaylı Getirme (GET By ID)

router.get('/:id', async (req, res) => {

    try {

        const book = await Book.findById(req.params.id);

        if (!book) return res.status(404).json({ message: "Kitap bulunamadı." });

        res.status(200).json(book);

    } catch (error) {

        res.status(500).json({ message: "Geçersiz ID formatı." });

    }

});

 

// 4. UPDATE: Kitap Bilgilerini Güncelleme (PUT)

router.put('/:id', async (req, res) => {

    try {

        const updatedBook = await Book.findByIdAndUpdate(

            req.params.id,

            req.body,

            { new: true } // Güncellenmiş yeni veriyi geri döndürür

        );

        res.status(200).json(updatedBook);

    } catch (error) {

        res.status(500).json({ message: error.message });

    }

});

 

// 5. DELETE: Veri Tabanından Kitap Silme (DELETE)

router.delete('/:id', async (req, res) => {

    try {

        await Book.findByIdAndDelete(req.params.id);

        res.status(200).json({ message: "Kitap başarıyla silindi." });

    } catch (error) {

        res.status(500).json({ message: error.message });

    }

});

 

module.exports = router;

➡️ Postman & HTTP Durum Kodları (Status Codes)

Yazdığımız bu API rotalarını test etmek için tarayıcı yetersiz kalır (çünkü tarayıcılar doğrudan sadece GET isteği atabilir). Bu noktada Postman programını kullanırız. Testlerimizi yaparken dönen yanıtların standartlara uygun olması için doğru HTTP durum kodlarını seçeriz:


 

Harika, kaldığımız yerden devam ediyoruz! Bir önceki bölümde temel CRUD mimarisini kurmuştuk. Şimdi ise projemizi profesyonel seviyeye taşıyacak olan Veri Doğrulama (Body Validation) ve Uluslararasılaştırma (Localization) mekanizmalarını kuracağız. Ardından devasa E-Ticaret Uygulaması bölümünün ilk yarısını inşa etmeye başlayacağız.


🛠 BÖLÜM 4: Body Validation (Gelen Verilerin Doğrulanması)

Kullanıcıların veri tabanımıza rastgele, hatalı ya da zararlı veriler göndermesini engellemek için express-validator kütüphanesini kullanırız. Örneğin bir kitabın adı boş bırakılamaz veya sayfa sayısı eksi bir değer olamaz.

➡️ express-validator Kurulumu ve Kullanımı

Kurulum: npm install express-validator

➡️ Rotaları Temiz Tutma (Refactor Code) & ID Parametre Doğrulaması

Doğrulama kurallarını doğrudan rota (route) dosyalarının içine yazmak kod kirliliğine sebep olur. Bu yüzden kuralları ara yazılım (middleware) olarak dışarıya taşırız. Ayrıca MongoDB'nin kendine has ObjectId yapısını (req.params.id) kontrol eden bir doğrulama da ekleriz.

Uygulama: middleware/validateBook.js

const { body, param, validationResult } = require('express-validator');

 

// Kitap ekleme ve güncelleme için doğrulama kuralları

const bookValidationRules = () => {

    return [

        body('title')

            .notEmpty().withMessage('Kitap adı boş bırakılamaz.')

            .isLength({ min: 2 }).withMessage('Kitap adı en az 2 karakter olmalıdır.'),

        body('author')

            .notEmpty().withMessage('Yazar adı boş bırakılamaz.'),

        body('pages')

            .optional()

            .isInt({ min: 1 }).withMessage('Sayfa sayısı 1den küçük olamaz.')

    ];

};

 

// URL'den gelen ID'nin geçerli bir MongoDB ObjectId olup olmadığını kontrol eder

const idParamValidationRules = () => {

    return [

        param('id').isMongoId().withMessage('Geçersiz veri tabanı ID formatı.')

    ];

};

 

// Hataları yakalayıp istemciye dönen ortak ara yazılım

const validate = (req, res, next) => {

    const errors = validationResult(req);

    if (errors.isEmpty()) {

        return next(); // Hata yoksa bir sonraki fonksiyona/işleme geç

    }

   

    // Hataları temiz bir liste halinde döndürür

    const extractedErrors = [];

    errors.array().map(err => extractedErrors.push({ [err.path]: err.msg }));

 

    return res.status(400).json({

        errors: extractedErrors

    });

};

 

module.exports = {

    bookValidationRules,

    idParamValidationRules,

    validate

};

Uygulama: routes/bookRoutes.js İçinde Kullanımı

const express = require('express');

const router = express.Router();

const { bookValidationRules, idParamValidationRules, validate } = require('../middleware/validateBook');

const Book = require('../models/Book');

 

// Yeni kitap eklerken önce kuralları çalıştır, sonra doğrula, hata yoksa kaydet

router.post('/', bookValidationRules(), validate, async (req, res) => {

    try {

        const newBook = new Book(req.body);

        await newBook.save();

        res.status(201).json(newBook);

    } catch (error) {

        res.status(500).json({ message: error.message });

    }

});

 

// Detay getirirken önce ID biçimini doğrula

router.get('/:id', idParamValidationRules(), validate, async (req, res) => {

    try {

        const book = await Book.findById(req.params.id);

        if (!book) return res.status(404).json({ message: "Kitap bulunamadı." });

        res.status(200).json(book);

    } catch (error) {

        res.status(500).json({ message: error.message });

    }

});


🛠 BÖLÜM 5: Localization (Çoklu Dil ve Yerelleştirme Desteği)

Global bir projede, API'den dönen hata mesajlarının veya başarılı işlem yanıtlarının kullanıcının diline göre (İngilizce, Almanca, Arapça vb.) dinamik olarak değişmesi istenir. Bunun için standart ISO 639-1 dil kodlarını (en, tr, de, ar) kullanırız.

➡️ Klasör Yapısı ve Dil Dosyaları

Uygulama: locales/tr.json

{

  "BOOK_TITLE_REQUIRED": "Kitap adı zorunludur.",

  "BOOK_NOT_FOUND": "Aradığınız kitap sistemde bulunamadı."

}

Uygulama: locales/de.json (Almanca)

{

  "BOOK_TITLE_REQUIRED": "Buchtitel ist erforderlich.",

  "BOOK_NOT_FOUND": "Das gesuchte Buch wurde herkunft nicht gefunden."

}

➡️ Dil Ara Yazılımı (Localization Middleware)

Gelen isteğin başlığından (Accept-Language header) kullanıcının hangi dili tercih ettiğini okuruz ve mesajları ona göre seçeriz.

// Basit bir dil yönetim fonksiyonu mantığı

const i18n = (req, res, next) => {

    const lang = req.headers['accept-language'] || 'tr'; // Varsayılan Türkçe

    const locales = {

        tr: require('../locales/tr.json'),

        de: require('../locales/de.json')

    };

   

    // İstek nesnesine (req) dile özel çeviri fonksiyonu ekliyoruz

    req.translate = (key) => {

        return locales[lang]?.[key] || locales['tr'][key] || key;

    };

    next();

};


🛠 BÖLÜM 6: Büyük Proje - E-Ticaret Uygulaması (Aşama 1: Altyapı ve Kullanıcı Yönetimi)

Müfredatın en büyük bölümü olan bu e-ticaret uygulamasını adım adım, modüller halinde inşa edeceğiz. Bu aşamada Kategori Yönetimi, Kullanıcı Modeli, Şifre Güvenliği ve JWT (JSON Web Token) ile Kimlik Doğrulama mekanizmalarını tasarlayacağız.

➡️ Kategori Yönetimi (Category Model & CRUD)

E-ticaret sistemindeki ürünlerin gruplanması için dinamik bir kategori yapısı kuruyoruz.

Uygulama: models/Category.js

const mongoose = require('mongoose');

 

const CategorySchema = new mongoose.Schema({

    name: { type: String, required: true, unique: true },

    description: String

});

 

module.exports = mongoose.model('Category', CategorySchema);

➡️ Kullanıcı Yönetimi ve Şifre Güvenliği (Password Hashing)

Kullanıcıların şifreleri asla veri tabanına düz metin ("123456") olarak kaydedilmez. Siber saldırılara karşı bu şifreleri tek yönlü algoritmalardan geçiren bcrypt kütüphanesi ile şifreleriz (hashing).

Uygulama: models/User.js

const mongoose = require('mongoose');

const bcrypt = require('bcrypt');

 

const UserSchema = new mongoose.Schema({

    name: { type: String, required: true },

    email: { type: String, required: true, unique: true },

    password: { type: String, required: true },

    role: { type: String, enum: ['user', 'admin'], default: 'user' }, // Rol tabanlı yetkilendirme altyapısı

    addresses: [{

        title: String,

        city: String,

        zip: String

    }]

});

 

// Veri tabanına kaydedilmeden hemen önce (Pre-save hook) şifreyi otomatik tuzla ve şifrele

UserSchema.pre('save', async function(next) {

    if (!this.isModified('password')) return next();

    try {

        const salt = await bcrypt.genSalt(10); // Güvenlik katmanı derecesi

        this.password = await bcrypt.hash(this.password, salt);

        next();

    } catch (error) {

        next(error);

    }

});

 

// Giriş yapılırken gelen şifre ile veri tabanındaki şifreli yapıyı karşılaştırma metodu

UserSchema.methods.comparePassword = async function(candidatePassword) {

    return await bcrypt.compare(candidatePassword, this.password);

};

 

module.exports = mongoose.model('User', UserSchema);

➡️ JWT (Token) Üretimi ve Kimlik Doğrulama Middleware (Auth Middleware)

Kullanıcı giriş yaptıktan sonra sunucu ona geçici bir kimlik kartı (JWT Token) verir. Kullanıcı sonraki isteklerinde (profilini görme, sipariş verme vb.) bu kartı sunarak kendini kanıtlar.

Kurulum: npm install jsonwebtoken

Uygulama: middleware/auth.js

const jwt = require('jsonwebtoken');

 

const authMiddleware = (req, res, next) => {

    // İstek başlığından (Header) Token'ı yakala (Format: Bearer <TOKEN>)

    const authHeader = req.headers['authorization'];

    const token = authHeader && authHeader.split(' ')[1];

 

    if (!token) {

        return res.status(401).json({ message: 'Erişim engellendi. Token bulunamadı.' });

    }

 

    try {

        // Token'ın doğruluğunu ve süresini gizli anahtarımızla (.env dosyasından gelen) kontrol et

        const verified = jwt.verify(token, process.env.JWT_SECRET);

        req.user = verified; // Token içindeki kullanıcı bilgilerini (id, rol) istek nesnesine ekle

        next();

    } catch (error) {

        res.status(403).json({ message: 'Geçersiz veya süresi dolmuş token.' });

    }

};

 

// Sadece yöneticilerin erişebileceği rotaları koruma yazılımı

const authorizeRoles = (...roles) => {

    return (req, res, next) => {

        if (!roles.includes(req.user.role)) {

            return res.status(403).json({ message: 'Bu işlem için yetkiniz bulunmamaktadır.' });

        }

        next();

    };

};

 

module.exports = { authMiddleware, authorizeRoles };

➡️ Kullanıcı Kayıt (Register) ve Giriş (Login) Rotaları

Şimdi tüm bu öğrendiklerimizi birleştirerek kullanıcı giriş ve kayıt mekanizmasını tamamlayalım.

Uygulama: routes/authRoutes.js

const express = require('express');

const router = express.Router();

const User = require('../models/User');

const jwt = require('jsonwebtoken');

 

// KULLANICI KAYIT

router.post('/register', async (req, res) => {

    try {

        const { name, email, password } = req.body;

       

        // E-posta adresi sistemde zaten var mı?

        const existingUser = await User.findOne({ email });

        if (existingUser) return res.status(400).json({ message: 'Bu e-posta zaten kullanımda.' });

 

        const newUser = new User({ name, email, password });

        await newUser.save();

       

        res.status(201).json({ message: 'Kullanıcı başarıyla oluşturuldu.' });

    } catch (error) {

        res.status(500).json({ message: error.message });

    }

});

 

// KULLANICI GİRİŞİ

router.post('/login', async (req, res) => {

    try {

        const { email, password } = req.body;

 

        // Kullanıcıyı bul

        const user = await User.findOne({ email });

        if (!user) return res.status(404).json({ message: 'Kullanıcı bulunamadı.' });

 

        // Şifreyi doğrula

        const isMatch = await user.comparePassword(password);

        if (!isMatch) return res.status(400).json({ message: 'Hatalı şifre.' });

 

        // Bilgiler doğruysa JWT Token üret (Ömrü 1 Gün)

        const token = jwt.sign(

            { id: user._id, role: user.role },

            process.env.JWT_SECRET,

            { expiresIn: '1d' }

        );

 

        res.status(200).json({

            message: 'Giriş başarılı',

            token: token,

            user: { id: user._id, name: user.name, role: user.role }

        });

    } catch (error) {

        res.status(500).json({ message: error.message });

    }

});

 

module.exports = router;


E-Ticaret projemizin en kritik altyapı adımlarına geçiyoruz. Bu aşamada Ürün Yönetimi, Gelişmiş Arama/Filtreleme/Sayfalama algoritması, Multer ile sunucuya dosya yükleme, Cloudinary entegrasyonu ile buluta görsel taşıma ve Sipariş Yönetimi modüllerini satır satır kodlayarak tasarlayacağız.


🛠 BÖLÜM 7: E-Ticaret Uygulaması (Aşama 2: Ürünler, Gelişmiş Filtreleme ve Multer)

➡️ Ürün Modeli (Product Model)

Bir e-ticaret sisteminde ürünlerin adı, açıklaması, fiyatı, stok adedi, kategorisi ve resim yollarını tutacak esnek bir yapı kuruyoruz.

Uygulama: models/Product.js

const mongoose = require('mongoose');

 

const ProductSchema = new mongoose.Schema({

    name: { type: String, required: true, trim: true },

    description: { type: String, required: true },

    price: { type: Number, required: true, min: 0 },

    category: { type: mongoose.Schema.Types.ObjectId, ref: 'Category', required: true },

    stock: { type: Number, required: true, min: 0, default: 0 },

    images: [{ type: String }], // Resimlerin URL adresleri tutulur

    createdAt: { type: Date, default: Date.now }

});

 

module.exports = mongoose.model('Product', ProductSchema);

➡️ Multer ile Sunucuya Yerel Dosya Yükleme

Kullanıcıların veya adminlerin ürün resimlerini yükleyebilmesi için multer ara yazılımını (middleware) kullanırız. Gelen dosyaları sunucudaki uploads/ klasörüne kaydederiz.

Kurulum: npm install multer

Uygulama: middleware/upload.js

const multer = require('multer');

const path = require('path');

 

// Dosyanın sunucuda nereye ve hangi isimle kaydedileceğini belirliyoruz

const storage = multer.diskStorage({

    destination: function (req, file, cb) {

        cb(null, 'uploads/'); // Dosyaların yükleneceği klasör adı

    },

    filename: function (req, file, cb) {

        // Dosya isminin çakışmaması için benzersiz bir zaman damgası ekliyoruz

        const uniqueSuffix = Date.now() + '-' + Math.round(Math.random() * 1E9);

        cb(null, file.fieldname + '-' + uniqueSuffix + path.extname(file.originalname));

    }

});

 

// Sadece görsel formatlarına (PNG, JPG, JPEG) izin veren güvenlik filtresi

const fileFilter = (req, file, cb) => {

    if (file.mimetype.startsWith('image/')) {

        cb(null, true);

    } else {

        cb(new Error('Yalnızca resim dosyası yükleyebilirsiniz!'), false);

    }

};

 

const upload = multer({

    storage: storage,

    fileFilter: fileFilter,

    limits: { fileSize: 1024 * 1024 * 5 } // Maksimum 5 MB limit

});

 

module.exports = upload;

➡️ Gelişmiş Ürün Arama, Filtreleme ve Sayfalama (Pagination) API Yapısı

Performanslı bir API için yüzlerce ürünü tek seferde göndermek yerine; kelime araması yapan, fiyata veya kategoriye göre filtreleyen ve veriyi sayfa sayfa bölen gelişmiş bir rota yazarız.

Uygulama: routes/productRoutes.js

const express = require('express');

const router = express.Router();

const Product = require('../models/Product');

const upload = require('../middleware/upload');

const { authMiddleware, authorizeRoles } = require('../middleware/auth');

 

// 1. ÜRÜN EKLEME (Sadece Adminler Yapabilir - Çoklu Resim Yükleme Desteği)

router.post('/', authMiddleware, authorizeRoles('admin'), upload.array('images', 5), async (req, res) => {

    try {

        const { name, description, price, category, stock } = req.body;

       

        // Yüklenen dosyaların yollarını diziye çeviriyoruz

        const imagePaths = req.files ? req.files.map(file => `/uploads/${file.filename}`) : [];

 

        const newProduct = new Product({

            name, description, price, category, stock,

            images: imagePaths

        });

 

        await newProduct.save();

        res.status(201).json(newProduct);

    } catch (error) {

        res.status(500).json({ message: error.message });

    }

});

 

// 2. GELİŞMİŞ LİSTELEME: Arama, Filtreleme ve Sayfalama (Herkese Açık)

router.get('/', async (req, res) => {

    try {

        // Query parametrelerini alıyoruz (Örn: /products?search=ayakkabi&minPrice=100&page=1&limit=10)

        const { search, category, minPrice, maxPrice, page = 1, limit = 10 } = req.query;

       

        // Dinamik filtre nesnesi oluşturuyoruz

        let queryObj = {};

 

        // İsme göre Regex (Büyük/Küçük harf duyarsız) arama

        if (search) {

            queryObj.name = { $regex: search, $options: 'i' };

        }

 

        // Kategoriye göre filtreleme

        if (category) {

            queryObj.category = category;

        }

 

        // Fiyat aralığı filtreleme

        if (minPrice || maxPrice) {

            queryObj.price = {};

            if (minPrice) queryObj.price.$gte = Number(minPrice); // ...'den büyük veya eşit

            if (maxPrice) queryObj.price.$lte = Number(maxPrice); // ...'den küçük veya eşit

        }

 

        // Sayfalama (Pagination) Matematiği

        const skip = (Number(page) - 1) * Number(limit);

        const totalProducts = await Product.countDocuments(queryObj);

 

        // Veri tabanından ilişkili Kategori bilgisini de çekerek (populate) getiriyoruz

        const products = await Product.find(queryObj)

            .populate('category', 'name')

            .skip(skip)

            .limit(Number(limit))

            .sort({ createdAt: -1 }); // En yeni eklenen en üstte

 

        res.status(200).json({

            meta: {

                totalItems: totalProducts,

                totalPages: Math.ceil(totalProducts / Number(limit)),

                currentPage: Number(page),

                perPage: Number(limit)

            },

            data: products

        });

    } catch (error) {

        res.status(500).json({ message: error.message });

    }

});

 

module.exports = router;


🛠 BÖLÜM 8: Cloudinary Entegrasyonu (Görselleri Buluta Taşımak)

Sunucunun kendi yerel diskine resim kaydetmek, proje büyüdükçe disk alanının dolmasına ve sunucu performansının düşmesine neden olur. Bu yüzden profesyonel projelerde resimler Cloudinary gibi bir Bulut Depolama (Cloud Storage) servisine yüklenir.

Kurulum: npm install cloudinary

Uygulama: services/cloudinaryService.js

const cloudinary = require('cloudinary').v2;

const fs = require('fs');

 

// Cloudinary kimlik bilgileri yapılandırması

cloudinary.config({

    cloud_name: process.env.CLOUDINARY_CLOUD_NAME,

    api_key: process.env.CLOUDINARY_API_KEY,

    api_secret: process.env.CLOUDINARY_API_SECRET

});

 

// Yerel diskteki resmi Cloudinary bulutuna yükleyen fonksiyon

const uploadToCloudinary = async (localFilePath) => {

    try {

        const result = await cloudinary.uploader.upload(localFilePath, {

            folder: 'eticaret_urunler' // Buluttaki klasör adı

        });

       

        // Buluta başarıyla yüklendikten sonra sunucumuzdaki geçici yerel dosyayı siliyoruz

        fs.unlinkSync(localFilePath);

       

        return result.secure_url; // Ürünün internet ortamındaki güvenli URL'ini döner

    } catch (error) {

        // Hata durumunda da sunucuda dosya kalıntısı bırakmıyoruz

        if (fs.existsSync(localFilePath)) {

            fs.unlinkSync(localFilePath);

        }

        throw new Error('Cloudinary yükleme hatası: ' + error.message);

    }

};

 

module.exports = { uploadToCloudinary };


🛠 BÖLÜM 9: Sipariş Yönetimi (Order Model & Stok Kontrolü)

Kullanıcıların sepetindeki ürünleri satın alabilmesi, fiyatların arka planda doğrulanması ve her başarılı siparişte ürünün stok adedinin otomatik azaltılması (stoktan düşme) işlemlerini yöneten mimaridir.

➡️ Sipariş Modeli (Order Model)

Uygulama: models/Order.js

const mongoose = require('mongoose');

 

const OrderSchema = new mongoose.Schema({

    user: { type: mongoose.Schema.Types.ObjectId, ref: 'User', required: true },

    items: [{

        product: { type: mongoose.Schema.Types.ObjectId, ref: 'Product', required: true },

        quantity: { type: Number, required: true, min: 1 },

        price: { type: Number, required: true } // Satın alındığı andaki sabit fiyatı

    }],

    totalPrice: { type: Number, required: true },

    status: { type: String, enum: ['Beklemede', 'Hazırlanıyor', 'Kargoda', 'Teslim Edildi'], default: 'Beklemede' },

    createdAt: { type: Date, default: Date.now }

});

 

module.exports = mongoose.model('Order', OrderSchema);

➡️ Sipariş Oluşturma ve Veri Tabanı Validasyonu (Stok Azaltma İşlemi)

Uygulama: routes/orderRoutes.js

const express = require('express');

const router = express.Router();

const Order = require('../models/Order');

const Product = require('../models/Product');

const { authMiddleware } = require('../middleware/auth');

 

router.post('/', authMiddleware, async (req, res) => {

    try {

        const { items } = req.body; // Gelen veri: [{ product: "ID", quantity: 2 }]

        let calculatedTotalPrice = 0;

        let finalOrderItems = [];

 

        // Her bir ürünü tek tek kontrol edip, fiyat doğrulama ve stok kontrolü yapıyoruz

        for (let item of items) {

            const product = await Product.findById(item.product);

            if (!product) {

                return res.status(404).json({ message: `Ürün bulunamadı ID: ${item.product}` });

            }

 

            // Stok yeterli mi kontrolü

            if (product.stock < item.quantity) {

                return res.status(400).json({ message: `${product.name} için yetersiz stok. Mevcut: ${product.stock}` });

            }

 

            // Arka planda güvenli fiyat hesaplama (Ön yüzden gelen fiyata asla güvenilmez!)

            calculatedTotalPrice += product.price * item.quantity;

 

            finalOrderItems.push({

                product: product._id,

                quantity: item.quantity,

                price: product.price

            });

 

            // Ürünün stok miktarını azaltıp güncelliyoruz

            product.stock -= item.quantity;

            await product.save();

        }

 

        // Siparişi kaydet

        const newOrder = new Order({

            user: req.user.id, // Auth middleware'den gelen giriş yapmış kullanıcı ID'si

            items: finalOrderItems,

            totalPrice: calculatedTotalPrice

        });

 

        await newOrder.save();

        res.status(201).json(newOrder);

 

    } catch (error) {

        res.status(500).json({ message: error.message });

    }

});

 

module.exports = router;


 

Müfredatımızın en yenilikçi ve popüler konularına geldik! Bu aşamada, projelere otomatik e-posta bildirim yeteneği kazandıran Node Mailer servisini kuracak, ardından yapay zekanın gücünü arkamıza alarak OpenAI ve Hugging Face modelleri ile entegre çalışan bir AI Chat API'si inşa edeceğiz.


🛠 BÖLÜM 10: Real-World Services (Node Mailer ile E-Posta Servisi)

E-ticaret sisteminde yeni bir sipariş verildiğinde veya bir kullanıcı kayıt olduğunda arka planda otomatik e-posta göndermek için nodemailer kütüphanesini kullanırız.

Kurulum: npm install nodemailer

Uygulama: services/emailService.js

const nodemailer = require('nodemailer');

 

// E-posta gönderimini sağlayan SMTP sunucu yapılandırması

const transporter = nodemailer.createTransport({

    host: process.env.EMAIL_HOST,     // Örn: ://gmail.com

    port: process.env.EMAIL_PORT,     // Örn: 465 veya 587

    secure: true,                     // 465 portu için true, 587 için false

    auth: {

        user: process.env.EMAIL_USER, // Gönderici e-posta adresi

        pass: process.env.EMAIL_PASS  // E-posta şifresi veya uygulama şifresi

    }

});

 

// Dinamik e-posta gönderme fonksiyonu

const sendWelcomeEmail = async (userEmail, userName) => {

    try {

        const mailOptions = {

            from: `"Modern E-Ticaret" <${process.env.EMAIL_USER}>`,

            to: userEmail,

            subject: 'Sistemimize Hoş Geldiniz! 🎉',

            // HTML şablonu kullanarak şık bir e-posta tasarımı gönderiyoruz

            html: `

                <div style="font-family: Arial, sans-serif; padding: 20px; border: 1px solid #eee;">

                    <h2 style="color: #4CAF50;">Merhaba ${userName},</h2>

                    <p>Node.js E-Ticaret dünyasına başarıyla adım attınız. Hesabınız aktif edilmiştir.</p>

                    <br>

                    <p>Keyifli alışverişler dileriz,<br>Sosyal Destek Ekibi</p>

                </div>

            `

        };

 

        const info = await transporter.sendMail(mailOptions);

        console.log('E-posta başarıyla gönderildi: %s', info.messageId);

        return true;

    } catch (error) {

        console.error('E-posta gönderim hatası:', error);

        return false;

    }

};

 

module.exports = { sendWelcomeEmail };


🛠 BÖLÜM 11: Proje 3 - AI Chat App (Yapay Zeka Destekli Chatbot API)

Bu projede, Node.js sunucumuz üzerinden hem popüler OpenAI (GPT) modellerine istek atacağız hem de Hugging Face platformundaki tamamen ücretsiz ve açık kaynak kodlu yapay zeka modellerini projemize entegre edeceğiz.

Kurulum: npm install openai @huggingface/inference

➡️ OpenAI Entegrasyonu

OpenAI platformundan aldığımız API anahtarı (process.env.OPENAI_API_KEY) ile kullanıcılardan gelen soruları yapay zekaya sorup yanıt üreten bir rota tasarlıyoruz.

Uygulama: routes/aiRoutes.js (OpenAI Bölümü)

const express = require('express');

const router = express.Router();

const { OpenAI } = require('openai');

const { HfInference } = require('@huggingface/inference');

 

// OpenAI İstemcisini başlatma

const openai = new OpenAI({

    apiKey: process.env.OPENAI_API_KEY

});

 

// OpenAI ile Chat Bot Rotası

router.post('/chat-openai', async (req, res) => {

    try {

        const { message } = req.body; // Kullanıcının bota yazdığı mesaj

 

        if (!message) {

            return res.status(400).json({ message: 'Lütfen bir mesaj içeriği gönderin.' });

        }

 

        // OpenAI API'sine chat tamamlama isteği gönderiyoruz

        const response = await openai.chat.completions.create({

            model: "gpt-4o-mini", // İstediğiniz güncel modeli seçebilirsiniz

            messages: [

                { role: "system", content: "Sen yardımsever ve profesyonel bir yazılım asistanısın." },

                { role: "user", content: message }

            ],

            max_tokens: 500

        });

 

        // Üretilen cevabı istemciye geri dönüyoruz

        res.status(200).json({

            reply: response.choices[0].message.content

        });

 

    } catch (error) {

        res.status(500).json({ message: 'OpenAI Servis Hatası: ' + error.message });

    }

});

➡️ Hugging Face Entegrasyonu (Ücretsiz Açık Kaynak Modeller)

Açık kaynak dünyasındaki güçlü modelleri (Örn: Meta'nın Llama modelleri veya Mistral) Hugging Face Inference API aracılığıyla projemize tamamen ücretsiz bağlayabiliriz.

Uygulama: routes/aiRoutes.js (Hugging Face Bölümü - Devamı)

// Hugging Face İstemcisini başlatma (Erişim jetonunu .env içinden alır)

const hf = new HfInference(process.env.HF_ACCESS_TOKEN);

 

router.post('/chat-opensource', async (req, res) => {

    try {

        const { message } = req.body;

 

        if (!message) {

            return res.status(400).json({ message: 'Lütfen bir mesaj içeriği gönderin.' });

        }

 

        // Hugging Face üzerindeki güncel bir metin üretme modelini çağırıyoruz

        const response = await hf.textGeneration({

            model: 'mistralai/Mistral-7B-Instruct-v0.2', // Açık kaynak popüler model

            inputs: `<s>[INST] ${message} [/INST]`,

            parameters: {

                max_new_tokens: 300,

                temperature: 0.7

            }

        });

 

        res.status(200).json({

            reply: response.generated_text

        });

 

    } catch (error) {

        res.status(500).json({ message: 'Hugging Face Servis Hatası: ' + error.message });

    }

});

 

module.exports = router;


🛠 BÖLÜM 12: Gelecek Adımlar & JavaScript Hızlı Tekrar (Bonus)

Müfredatımızın teknik back-end konularını eksiksiz olarak tamamladık. Son iki küçük bölümde ise şu vizyon adımları yer almaktadır:


 

Yüklediğiniz müfredat dosyası oldukça geniş ve kapsamlı bir Node.js uzmanlık eğitimine ait. Bu içeriği en yüksek verimle inceleyebilmeniz için, yönergeleriniz doğrultusunda dakika/saniye bilgilerini, önizleme yazılarını, ders sayılarını ve anlamsız satırları temizleyerek tamamen konu odaklı bir yapı kurdum.

İçeriğin derinliği nedeniyle bu planı parça parça ele alacağız. İlk olarak talep ettiğiniz üzere kursun en başındaki "Öğrenecekleriniz" bölümünün detaylı mantığını ve backend dünyasındaki karşılığını açıklayarak başlıyoruz.


🌟 "Öğrenecekleriniz" Bölümünün Detaylı Açıklaması

Bu kurs, katılımcıyı sıradan bir script yazıcısından alıp büyük ölçekli (enterprise) mimarileri yönetebilen bir Kıdemli (Senior) Arka Plan (Backend) Geliştiricisine dönüştürmeyi hedefler. Müfredatta vadedilen yetkinliklerin teknik açılımları şu şekildedir:


🛠 BÖLÜM 1: Node.js Temelleri (Giriş, İç Yapı ve Modüller)

Şimdi müfredatın ilk büyük bloğunu oluşturan temel ve iç yapı konularını derinlemesine inceleyelim, örnekler ve uygulamalarla somutlaştıralım.

1. Node.js Çalışma Zamanı (Runtime) ve Ortam Kurulumu

Node.js bir programlama dili değildir; JavaScript kodlarının tarayıcı dışında, doğrudan bilgisayarınızda veya bir sunucuda çalışmasını sağlayan bir çalışma ortamıdır (runtime). Gücünü Google Chrome'un da kalbi olan V8 JavaScript Motoru'ndan alır.

💻 Uygulama / Örnek: İlk Node.js Kodunuz

Terminalinizi veya komut satırınızı açıp node yazarak REPL ortamına girin ve şu kodu test edin:

// Global nesnesini inceleme ve ilk çıktı

global.console.log("Merhaba Backend Dünyası!");

 

// Ortam kontrolü

if (global.process) {

    console.log(`Çalışan Node sürümü: ${process.version}`);

}


2. Node.js İç Yapısı (Internals Deep Dive & Libuv)

Node.js'i performanslı kılan şey arka plandaki mimarisidir. JavaScript doğası gereği tek iş parçacıklıdır (Single-Threaded), yani aynı anda yalnızca bir işlem yapabilir. Ancak Node.js, ağır I/O (Giriş/Çıkış) işlemlerini arka planda asenkron olarak yürütebilir.

💡 Analoji ve Örnek

Bir restorandasınız. Blocking (Senkron) sistemde garson siparişinizi aşçıya götürür, yemek pişene kadar mutfağın kapısında bekler ve o sırada başka masalara bakamaz. Non-Blocking (Asenkron) sistemde ise garson siparişi aşçıya verir, masanıza bir çağrı cihazı (callback) koyar ve hemen diğer masaların siparişini almaya gider. Yemek pişince cihaz titrer (Event Loop tetiklenir) ve garson yemeği getirir.

const fs = require('fs');

 

console.log("1. Sipariş alındı.");

 

// Dosya okuma işlemi asenkron (Non-blocking) olarak başlar

fs.readFile('menu.txt', 'utf8', (err, data) => {

    if (err) throw err;

    console.log("3. Yemek pişti, içerik: " + data);

});

 

console.log("2. Garson diğer masaya geçti.");

Çıktı Sıralaması: 1 -> 2 -> 3 olacaktır. Sunucu dosyanın okunmasını beklemeden 2. satırı çalıştırmıştır.


3. Modül Sistemi (Module System) ve Paket Yönetimi (NPM)

Büyük projeleri tek bir dosyada yazmak imkansızdır. Node.js kodu mantıksal parçalara (modüllere) ayırmamızı sağlar.

💻 Uygulama: Kendi Modülünü Yaz ve Çalıştır

Matematik Modülü (math.js):

function topla(a, b) {

    return a + b;

}

// CommonJS standardı ile dışa aktarma

module.exports = { topla };

Ana Uygulama (app.js):

// Modülü içe aktarma

const matematik = require('./math');

 

const sonuc = matematik.topla(15, 25);

console.log(`Hesaplama Sonucu: ${sonuc}`);


🚀 BÖLÜM 2: Veri Akışları ve Web Sunucuları (File I/O, Streams & HTTP)

Bu bölümde ham veriyi işlemeyi ve harici dünyaya açılan ilk kapı olan web sunucularını tasarlamayı inceleyeceğiz.

1. Node.js Dosya I/O ve Akışlar (Streams)

Büyük boyutlu verileri (örneğin gigabaytlarca süren Kepler uzay teleskobu verilerini) tek seferde hafızaya (RAM) yüklemeye çalışırsanız sunucunuz kilitlenir. Node.js bunun önüne geçmek için Streams (Akışlar) yapısını kullanır.

💻 Uygulama: Büyük Bir CSV Dosyasını Parça Parça Okuma

Aşağıdaki örnek, binlerce satırlık bir gezegen veri listesini belleği yormadan asenkron olarak nasıl işleyebileceğimizi gösterir.

const fs = require('fs');

 

// Dosyayı bir akış (stream) olarak açıyoruz

const okumaAkisi = fs.createReadStream('uzay_verileri.csv', 'utf8');

 

okumaAkisi.on('data', (parca) => {

    console.log('--- Yeni bir veri parçası (chunk) geldi ---');

    console.log(parca.substring(0, 100)); // Gelen parçanın ilk 100 karakteri

});

 

okumaAkisi.on('end', () => {

    console.log('Tüm dosya başarıyla işlendi.');

});


2. Saf Node.js ile Web Sunucusu Oluşturmak

Herhangi bir kütüphane (Express vb.) kullanmadan, Node.js'in yerleşik http modülü ile gelen istekleri (Requests) dinleyen ve cevap (Response) dönen bir web sunucusu inşa edebiliriz.

💻 Uygulama: İlk HTTP Web Sunucunuz

const http = require('http');

 

const sunucu = http.createServer((req, res) => {

    // CORS Başlıkları ekleniyor

    res.setHeader('Access-Control-Allow-Origin', '*');

    res.setHeader('Content-Type', 'application/json');

 

    // Basit Yönlendirme (Routing)

    if (req.url === '/api/durum' && req.method === 'GET') {

        res.writeHead(200);

        res.end(JSON.stringify({ mesaj: "Sunucu ayakta ve çalışıyor" }));

    } else if (req.url === '/api/veri' && req.method === 'POST') {

        let govde = '';

        req.on('data', chunk => { govde += chunk; });

        req.on('end', () => {

            res.writeHead(201);

            res.end(JSON.stringify({ mesaj: "Veri alındı", gelen: JSON.parse(govde) }));

        });

    } else {

        res.writeHead(404);

        res.end(JSON.stringify({ hata: "Sayfa bulunamadı" }));

    }

});

 

sunucu.listen(3000, () => {

    console.log("Sunucu 3000 portunda çalışmaya başladı...");

});


 

Harika, kaldığımız yerden devam ediyoruz! Müfredatın bir sonraki devasa bloğu olan Express.js, kurumsal mimariye adım attığımız NASA Projesi, API Testleri ve Node.js sunucularının performans sınırlarını zorlayan Çoklu Süreç (Clustering/Worker) Yönetimi konularını derinlemesine, bol pratikle ele alalım.


🚀 BÖLÜM 3: Gelişmiş API Geliştirme (Express.js & MVC Mimarisi)

Yerleşik http modülüyle sunucu yazmak esneklik sağlasa da, büyük projelerde rota (route) yönetimi ve ara yazılımlar (middleware) karmaşıklaşır. Sektör standardı olan Express.js bu karmaşayı çözer.

💻 Uygulama: Express.js ile MVC Yapısında RESTful API

1. Veri Katmanı (models/GezegenlerModel.js)

// Basit bir bellek içi (in-memory) veri modeli

const gezegenler = [

    { id: 1, isim: "Kepler-452b", yasamaUygun: true },

    { id: 2, isim: "Mars", yasamaUygun: false }

];

 

function tumGezegenleriGetir() {

    return gezegenler;

}

 

function yeniGezegenEkle(gezegen) {

    gezegenler.push(gezegen);

    return gezegen;

}

 

module.exports = { tumGezegenleriGetir, yeniGezegenEkle };

2. İş Mantığı Katmanı (controllers/GezegenlerController.js)

const model = require('../models/GezegenlerModel');

 

function httpTumGezegenler(req, res) {

    return res.status(200).json(model.tumGezegenleriGetir());

}

 

function httpYeniGezegen(req, res) {

    const { isim, yasamaUygun } = req.body;

 

    // Basit Validasyon (Doğrulama)

    if (!isim || yasamaUygun === undefined) {

        return res.status(400).json({ hata: "Eksik parametre gönderdiniz." });

    }

 

    const eklenecek = { id: Date.now(), isim, yasamaUygun };

    const sonuc = model.yeniGezegenEkle(eklenecek);

    return res.status(201).json(sonuc);

}

 

module.exports = { httpTumGezegenler, httpYeniGezegen };

3. Sunucu ve Rota Yapılandırması (server.js)

const express = require('express');

const controller = require('./controllers/GezegenlerController');

 

const app = express();

 

// Yerleşik Middleware: Gelen JSON isteklerini ayrıştırır (parse)

app.use(express.json());

 

// Özel Loglama Middleware'i

app.use((req, res, next) => {

    console.log(`[${new Date().toISOString()}] ${req.method} isteği yapıldı: ${req.url}`);

    next(); // Bir sonraki middleware veya rotaya geçişi sağlar

});

 

// Tanımlanan REST API Rotaları

app.get('/api/gezegenler', controller.httpTumGezegenler);

app.post('/api/gezegenler', controller.httpYeniGezegen);

 

app.listen(8000, () => {

    console.log("Express API 8000 portunda hazır!");

});


🧪 BÖLÜM 4: API Test Stratejileri (Jest & Supertest)

Kurumsal düzeyde kod yazarken projenin doğruluğunu elle test etmek (Postman/Insomnia üzerinden sürekli istek atmak) sürdürülebilir değildir. Kod kalitesini korumak ve güncellemelerde mevcut sistemin bozulmadığından emin olmak için otomatik testler yazarız.

💻 Uygulama: API Uç Noktalarının Test Edilmesi

Yukarıda yazdığımız /api/gezegenler rotasını test eden bir dosya tasarlayalım (gezegenler.test.js):

const request = require('supertest');

const express = require('express');

const controller = require('./controllers/GezegenlerController');

 

// Test için geçici bir express uygulaması simüle ediyoruz

const app = express();

app.use(express.json());

app.get('/api/gezegenler', controller.httpTumGezegenler);

app.post('/api/gezegenler', controller.httpYeniGezegen);

 

describe('Gezegenler API Test Senaryoları', () => {

   

    // 1. Başarılı GET İsteği Testi

    test('GET /api/gezegenler 200 dönmeli ve dizi içeriği içermeli', async () => {

        const response = await request(app)

            .get('/api/gezegenler')

            .expect('Content-Type', /json/)

            .expect(200);

           

        expect(Array.isArray(response.body)).toBe(true);

    });

 

    // 2. Hatalı POST İsteği Validasyon Testi

    test('POST /api/gezegenler eksik veriyle 400 hatası vermeli', async () => {

        const hataliVeri = { isim: "Yeni Dünya" }; // yasamaUygun alanı eksik

       

        const response = await request(app)

            .post('/api/gezegenler')

            .send(hataliVeri)

            .expect(400);

 

        expect(response.body.hata).toBe("Eksik parametre gönderdiniz.");

    });

});


⚡ BÖLÜM 5: Node.js Performans ve Ölçekleme (Cluster & Worker Threads)

Node.js tek bir çekirdekte (Single Thread) çalışır demiştik. Eğer sunucunuz 8 çekirdekli güçlü bir makinede bulunuyorsa, varsayılan ayarlarda Node.js yalnızca 1 çekirdeği tam kapasite kullanır, diğer 7 çekirdek boşa bekler. Sunucu performansını maksimize etmek için iki yöntem kullanılır:

  1. Cluster Modülü (Çoklu Süreç / Multi-Process): Uygulamanın ana çekirdeğini (Master) kopyalayarak birden fazla alt süreç (Worker Process) oluşturur. Her süreç farklı bir CPU çekirdeğinde çalışır ve aynı portu dinler. Gelen trafik bu süreçlere Load Balancing (Yük Dengeleme) algoritmasıyla dağıtılır. Gerçek dünyada bu yönetimi otomatikleştirmek için PM2 aracı kullanılır.
  2. Worker Threads (İş Parçacıkları): Ağır matematiksel veya kriptografik işlemler (örneğin resim işleme, büyük veri analizi, şifre kırma) ana Event Loop'u tıkar (blocking). Bu tür yoğun CPU gerektiren işleri, aynı süreç içinde yeni bir alt iş parçacığına (thread) devretmek için kullanılır.

💻 Uygulama: Yoğun CPU Yükünü Worker Threads ile Çözmek

Ana sunucumuzda şifreleme veya ağır bir döngü döndüğünü hayal edelim. Bunu ana iş parçacığında yaparsak sunucu kilitlenir.

Ağır İşi Yapan Dosya (agirIsYuku.js):

const { parentPort } = require('worker_threads');

 

// Ağır matematiksel işlem simülasyonu

let sayac = 0;

for (let i = 0; i < 5000000000; i++) {

    sayac++;

}

 

// Sonucu ana sunucuya geri gönder

parentPort.postMessage(sayac);

Ana Sunucu Dosyası (sunucu.js):

const express = require('express');

const { Worker } = require('worker_threads');

const app = express();

 

// Bloklayan Rota (Worker olmadan - Sunucuyu kilitler)

app.get('/bloklayan-is', (req, res) => {

    let sayac = 0;

    for (let i = 0; i < 5000000000; i++) { sayac++; }

    res.send(`İşlem bitti: ${sayac}`);

});

 

// Performanslı Rota (Worker Kullanarak - Sunucu kilitlenmez)

app.get('/performansli-is', (req, res) => {

    // Ağır iş yükünü arka plana fırlatıyoruz

    const worker = new Worker('./agirIsYuku.js');

 

    worker.on('message', (sonuc) => {

        res.send(`Arka planda tamamlanan işlem sonucu: ${sonuc}`);

    });

 

    worker.on('error', (hata) => {

        res.status(500).send(`Hata oluştu: ${hata.message}`);

    });

});

 

app.get('/ziyaret et', (req, res) => {

    res.send("Ben ana event loop'u bloklamadığım için anında cevap verebiliyorum!");

});

 

app.listen(9000, () => console.log("Performans sunucusu 9000 portunda aktif!"));

Farkı Anlamak İçin: /bloklayan-is rotasına tarayıcıdan istek attığınızda o sekme yüklenirken, yan sekmede açacağınız /ziyaret-et rotası da yanıt vermez, donar. Ancak /performansli-is rotasına istek attığınızda ağır yük arka thread'e geçtiği için /ziyaret-et rotası anında açılmaya devam eder.


 

Harika, hız kesmeden devam ediyoruz! Müfredatın kurumsal mimaride en çok zaman alan ve profesyonelliği belirleyen kritik aşamalarına geldik.

Bu bölümde Veritabanı Tasarımı (MongoDB & SQL), harici servislerle haberleştiğimiz SpaceX API Entegrasyonu ve sistemlerin güvenliğini sağlayan Kimlik Doğrulama (Authentication & Security) konularını derinlemesine pratik örneklerle ele alacağız.


🗄️ BÖLÜM 6: Kalıcı Veri Yönetimi (SQL vs NoSQL ve MongoDB/Mongoose)

Verileri RAM'de (bellekte) tutmak kalıcı bir çözüm değildir; sunucu kapandığında tüm veriler uçar. Gerçek dünya uygulamalarında verileri kalıcı hale getirmek için İlişkisel (SQL) veya Döküman Tabanlı (NoSQL) veritabanları kullanılır.

💻 Uygulama: Mongoose ile Şema Tasarımı ve Veri Kaydı

1. Veritabanı Şeması Tasarlama (models/FirlatmaSema.js)

const mongoose = require('mongoose');

 

const firlatmaSemasi = new mongoose.Schema({

    ucusNumarasi: {

        type: Number,

        required: true,

        default: 100

    },

    gorevIsmi: {

        type: String,

        required: true

    },

    roketTipi: {

        type: String,

        required: true

    },

    firlatmaTarihi: {

        type: Date,

        required: true

    },

    basariliMi: {

        type: Boolean,

        required: true,

        default: true

    }

});

 

// Şemayı modele dönüştürüp dışa aktarıyoruz

module.exports = mongoose.model('Firlatma', firlatmaSemasi);

2. Veritabanı Bağlantısı ve Upsert İşlemi (veritabaniServis.js)

const mongoose = require('mongoose');

const Firlatma = require('./models/FirlatmaSema');

 

// MongoDB Atlas veya yerel veritabanına bağlanma

const MONGO_URL = 'mongodb://localhost:27017/nasa_projesi';

 

async function veritabaninaBaglan() {

    await mongoose.connect(MONGO_URL);

    console.log('MongoDB Bağlantısı Başarılı!');

}

 

async function firlatmaVerisiniKaydet(firlatmaVerisi) {

    // UPSERT Operasyonu: ucusNumarasi kontrol edilir.

    // Varsa güncellenir, yoksa yeni kayıt (insert) atılır.

    await Firlatma.updateOne(

        { ucusNumarasi: firlatmaVerisi.ucusNumarasi }, // Filtre kriteri

        firlatmaVerisi,                               // Güncellenecek/Eklenecek Veri

        { upsert: true }                               // Upsert özelliğini aktif etme

    );

    console.log(`Uçuş #${firlatmaVerisi.ucusNumarasi} veritabanına işlendi.`);

}

 

// Senaryo Çalıştırma

async function calistir() {

    await veritabaninaBaglan();

   

    await firlatmaVerisiniKaydet({

        ucusNumarasi: 101,

        gorevIsmi: "Falcon Heavy Test",

        roketTipi: "Falcon Heavy",

        firlatmaTarihi: new Date()

    });

}

calistir();


🛰️ BÖLÜM 7: Harici API Entegrasyonu ve Sayfalama (SpaceX Projesi)

Kendi veritabanımızı yönetmenin yanı sıra, üçüncü parti servislerin (SpaceX API gibi) verilerini de kendi sistemimize senkronize etmemiz gerekir.

💻 Uygulama: Sayfalama (Pagination) Altyapısı Tasarlama

Kendi API uç noktalarımızda sorgu parametrelerine (?sayfa=1&limit=10) göre dinamik sayfalama yapan bir fonksiyon tasarlayalım.

// queryServis.js - Gelen istek parametrelerini MongoDB formatına çevirir

const VARSAYILAN_SAYFA_LIMITI = 50;

const VARSAYILAN_SAYFA_NUMARASI = 1;

 

function sayfalamaAyarlariniAl(query) {

    // Sayfa numarasını mutlak sayıya çeviriyoruz (Örn: "2" -> 2)

    const sayfa = Math.abs(query.sayfa) || VARSAYILAN_SAYFA_NUMARASI;

    const limit = Math.abs(query.limit) || VARSAYILAN_SAYFA_LIMITI;

   

    // Kaç adet kaydın atlanacağını hesaplama

    // Sayfa 1 ise: (1 - 1) * 10 = 0 kayıt atla

    // Sayfa 2 ise: (2 - 1) * 10 = 10 kayıt atla

    const skip = (sayfa - 1) * limit;

 

    return {

        skip,

        limit

    };

}

 

module.exports = { sayfalamaAyarlariniAl };

Controller İçinde Kullanımı:

const Firlatma = require('./models/FirlatmaSema');

const { sayfalamaAyarlariniAl } = require('./queryServis');

 

async function httpTumFirlatmalar(req, res) {

    // req.query: gelen URL parametrelerini taşır (?sayfa=2&limit=5 gibi)

    const { skip, limit } = sayfalamaAyarlariniAl(req.query);

   

    // MongoDB'den verileri sıralı ve sayfalanmış olarak çekiyoruz

    const firlatmalar = await Firlatma.find({}, { '_id': 0, '__v': 0 })

        .sort({ ucusNumarasi: 1 }) // Uçuş numarasına göre artan sıralama

        .skip(skip)

        .limit(limit);

 

    return res.status(200).json(firlatmalar);

}


🔒 BÖLÜM 8: Sunucu Güvenliği ve Kimlik Doğrulama (Security, JWT & OAuth)

Bir backend geliştiricisinin en öncelikli görevi projenin güvenliğidir. Sistemimize kimlerin erişebileceğini doğrulamak (Authentication) ve yetkilerini belirlemek (Authorization) zorundayız.

💻 Uygulama: JWT ile Güvenli Rota Koruması (Middleware)

Kullanıcının sadece geçerli bir token'a sahip olduğunda erişebileceği gizli bir rota mekanizması kuralım.

const jwt = require('jsonwebtoken');

const GIZLI_ANAHTAR = 'nasa_cok_gizli_anahtar_123'; // Gerçek dünyada .env dosyasında tutulur

 

// 1. Kimlik Doğrulama Ara Yazılımı (Authentication Middleware)

function kimlikDogrula(req, res, next) {

    // İstemciden token genellikle 'Authorization: Bearer <TOKEN>' formatında gelir

    const authHeader = req.headers['authorization'];

    const token = authHeader && authHeader.split(' ')[1];

 

    if (!token) {

        return res.status(401).json({ hata: "Erişim engellendi. Token bulunamadı." });

    }

 

    try {

        // Token'ı çöz ve doğruluğunu kontrol et

        const dogrulanmisKullanici = jwt.verify(token, GIZLI_ANAHTAR);

        req.kullanici = dogrulanmisKullanici; // Kullanıcı verisini isteğe ekle

        next(); // Başarılıysa bir sonraki rotaya/fonksiyona geç

    } catch (hata) {

        return res.status(403).json({ hata: "Geçersiz veya süresi dolmuş token." });

    }

}

 

// 2. Sunucu Üzerinde Kullanımı

const express = require('express');

const helmet = require('helmet');

const app = express();

 

app.use(helmet()); // Temel HTTP güvenlik başlıklarını aktif et

app.use(express.json());

 

// Herkese açık rota

app.get('/api/genel', (req, res) => {

    res.send("Bu veriye herkes erişebilir.");

});

 

// Sadece giriş yapmış kullanıcılara özel korumalı rota

app.get('/api/nasa-gizli-kodlar', kimlikDogrula, (req, res) => {

    res.json({

        mesaj: `Hoş geldin ${req.kullanici.isim}. İşte gizli veriler...`,

        veriler: ["Mars Koloni Planları V1", "Kepler Sinyal Analizleri"]

    });

});

 

app.listen(5000, () => console.log("Güvenli sunucu 5000 portunda!"));


 

Müfredatımızın kurumsal backend dünyasındaki son ve en heyecan verici adımlarına geldik. Bu bölümde, yazdığımız projelerin tüm dünyaya kesintisiz hizmet vermesini sağlayan DevOps Süreçlerini (Docker, CI/CD, AWS) ve modern iletişim protokolleri olan GraphQL ile WebSockets (Socket.io) teknolojilerini derinlemesine, pratik uygulamalarla ele alacağız.


🌐 BÖLÜM 9: DevOps, Konteynerizasyon ve Bulut Dağıtımı (Docker & AWS)

Bir backend geliştiricisi olarak harika kod yazabilirsiniz, ancak bu kod kendi bilgisayarınız dışında çalışmadığı sürece bir değeri yoktur. Kurumsal sistemlerde "Benim bilgisayarımda çalışıyordu!" sorununu çözmek için altyapıyı standartlaştırır ve buluta taşırız.

💻 Uygulama: Node.js Projesi İçin Kurumsal Dockerfile Tasarımı

Projemizin kök dizinine ekleyeceğimiz bir Dockerfile ile uygulamamızı nasıl paketleyeceğimizi katmanlı mimari (layering) kurallarına göre tasarlayalım:

# 1. Aşama: Resmi hafif Node.js imajını taban alıyoruz

FROM node:18-alpine

 

# 2. Aşama: Konteyner içinde uygulamanın çalışacağı dizini oluşturuyoruz

WORKDIR /app

 

# 3. Aşama: Bağımlılıkları kopyalıyoruz (Katman önbellekleme performansı için önce package.json)

COPY package*.json ./

 

# 4. Aşama: Sadece üretim (production) paketlerini kuruyoruz, geliştirme araçlarını eliyoruz

RUN npm install --only=production

 

# 5. Aşama: Kalan tüm proje kodlarını konteyner içine kopyalıyoruz

COPY . .

 

# 6. Aşama: Uygulamanın dış dünyaya açılacağı portu belirtiyoruz

EXPOSE 8000

 

# 7. Aşama: Uygulamayı başlatacak ana komut

CMD ["npm", "start"]


📊 BÖLÜM 10: Modern Veri Sorgulama (GraphQL)

Geleneksel REST API tasarımlarında iki büyük problem yaşarız: Over-fetching (Kullanıcının ihtiyacından çok daha fazla veri göndermek) ve Under-fetching (İhtiyacı karşılamak için ardı ardına 3-4 farklı API uç noktasına istek atmak). GraphQL, istemcinin tam olarak neye ihtiyacı varsa sunucudan sadece o veriyi tek bir istekte talep etmesini sağlar.

💻 Uygulama: Apollo Server ve Node.js ile Basit E-Ticaret GraphQL API

const { ApolloServer, gql } = require('apollo-server');

 

// 1. Tip Tanımlamaları (Schema)

const typeDefs = gql`

    type Urun {

        id: ID!

        isim: String!

        fiyat: Float!

        stoktaVarMi: Boolean!

    }

 

    # Kullanıcıların atabileceği GET istekleri (Sorgular)

    type Query {

        urunler: [Urun]

        urunGetir(id: ID!): Urun

    }

`;

 

// 2. Mock (Geçici) Veritabanı

const urunlerListesi = [

    { id: "1", isim: "Kablosuz Kulaklık", fiyat: 1250.0, stoktaVarMi: true },

    { id: "2", isim: "Mekanik Klavye", fiyat: 2100.0, stoktaVarMi: false }

];

 

// 3. Çözümleyiciler (Resolvers)

const resolvers = {

    Query: {

        urunler: () => urunlerListesi,

        urunGetir: (parent, args) => urunlerListesi.find(u => u.id === args.id)

    }

};

 

// 4. Sunucunun Başlatılması

const sunucu = new ApolloServer({ typeDefs, resolvers });

 

sunucu.listen({ port: 4000 }).then(({ url }) => {

    console.log(`GraphQL Sunucusu ${url} adresinde hazır!`);

});

İstemci Tarafından Atılabilecek Örnek Sorgu (Sadece isim ve fiyat istenir, stok bilgisi ağ üzerinden taşınmaz):

query {

  urunGetir(id: "1") {

    isim

    fiyat

  }

}


🔄 BÖLÜM 11: Gerçek Zamanlı İletişim (Sockets & Socket.io)

HTTP protokolü "İstek-Cevap" (Request-Response) mantığıyla çalışır. Sunucu durduk yere istemciye veri gönderemez, illa istemcinin bir istek tetiklemesi gerekir. Ancak canlı chat uygulamaları, borsa grafikleri veya çok oyunculu (multiplayer) oyunlarda sunucunun anlık olarak veriyi istemcilere itmesi (push) gerekir. Burada devreye WebSockets girer. Socket.io, bağlantı kopsa bile otomatik yeniden bağlanma gibi yetenekleri olan gelişmiş bir WebSocket kütüphanesidir.

💻 Uygulama: Socket.io ile Canlı Mesajlaşma Odası Tasarımı

const express = require('express');

const http = require('http');

const { Server } = require('socket.io');

 

const app = express();

const sunucu = http.createServer(app);

// CORS ayarlarıyla Soket sunucusunu başlatıyoruz

const io = new Server(sunucu, {

    cors: { origin: "*" }

});

 

// Soket Bağlantı Dinleyicisi

io.on('connection', (socket) => {

    console.log(`Yeni bir kullanıcı bağlandı: ${socket.id}`);

 

    // Kullanıcıyı belirli bir odaya alma (Room)

    socket.on('odaya_katil', (odaIsmi) => {

        socket.join(odaIsmi);

        console.log(`${socket.id} isimli kullanıcı [${odaIsmi}] odasına girdi.`);

    });

 

    // Odadakilere mesaj gönderme olayı

    socket.on('yeni_mesaj', (veri) => {

        // veri: { oda: "uzay-odasi", mesaj: "Merhaba Mars!" }

        // Mesajı gönderen kişi hariç odadaki herkese (broadcast) mesajı ilet

        socket.to(veri.oda).emit('mesaj_al', {

            gonderen: socket.id,

            mesaj: veri.mesaj

        });

    });

 

    // Bağlantı koptuğunda tetiklenir

    socket.on('disconnect', () => {

        console.log(`Kullanıcı ayrıldı: ${socket.id}`);

    });

});

 

sunucu.listen(3050, () => {

    console.log("Real-time Soket Sunucusu 3050 portunda aktif!");

});


📝 BÖLÜM 12: Ek Teknolojiler ve JavaScript Altyapısı (Deno & JS Engine)

Müfredatın son ek kısımları, bir backend geliştiricisinin entelektüel ve teknik derinliğini artırmayı hedefler.


Yüklediğiniz kurumsal Node.js müfredatında yer alan kritik mimarilerin yerel bilgisayarınızda (localhost) sıfırdan kurulup ayağa kaldırılması için gereken teknik rehberi ve ardından kıdemli backend mülakatlarında karşılaşabileceğiniz seçici soruları cevaplarıyla birlikte aşağıda hazırladım.


🛠️ BÖLÜM 1: Kurumsal Mimarileri Yerelde Sıfırdan Ayağa Kaldırma Rehberi

Uygulamalara başlamadan önce bilgisayarınızda Node.js (v18+) ve Docker Desktop yazılımlarının kurulu olduğundan emin olun.

1. Proje Altyapısının Hazırlanması (Ortak Adım)

Tüm mimarileri tek bir çatı altında veya ayrı klasörlerde denemek için temiz bir terminal açın ve şu komutları sırasıyla çalıştırın:

# Proje klasörü oluşturun ve içine girin

mkdir node-uzmanlik-serisi && cd node-uzmanlik-serisi

 

# Bağımlılıkları yöneteceğimiz package.json dosyasını varsayılan ayarlarla oluşturun

npm init -y

 

# Gerekli tüm kurumsal paketleri tek seferde kurun

npm install express mongoose apollo-server graphql socket.io jsonwebtoken helmet

 

# Geliştirme aşamasında kod değiştikçe sunucuyu otomatik yenilemesi için nodemon paketini kurun

npm install --save-dev nodemon

package.json dosyanızı açın ve "scripts" bölümüne şu satırı ekleyin:

"start": "nodemon server.js"


2. Veritabanı ve Güvenlik Katmanı (MongoDB & JWT & Helmet)

Veritabanını bilgisayarınıza kurmakla uğraşmamak için en pratik ve kurumsal yol Docker kullanmaktır.

Adım A: MongoDB'yi Docker ile Başlatma

Terminalinizde şu komutu çalıştırarak arka planda çalışan izole bir MongoDB ayağa kaldırın:

docker run -d --name lokal-mongo -p 27017:27017 mongo:latest

Adım B: Kod Altyapısı

Proje kök dizininde server.js dosyası oluşturun ve aşağıdaki entegre yapıyı yapıştırın:

const express = require('express');

const mongoose = require('mongoose');

const helmet = require('helmet');

const jwt = require('jsonwebtoken');

 

const app = express();

const GIZLI_ANAHTAR = 'mülakat_sırrı_123';

 

// Güvenlik ve veri işleme ara yazılımları (Middleware)

app.use(helmet());

app.use(express.json());

 

// MongoDB Bağlantısı

mongoose.connect('mongodb://localhost:27017/uzmanlik_db')

    .then(() => console.log('🍃 MongoDB Bağlantısı Başarılı!'))

    .catch(err => console.error('MongoDB Bağlantı Hatası:', err));

 

// Test için JWT Üreten Rota (Login simülasyonu)

app.get('/auth/login', (req, res) => {

    const token = jwt.sign({ user: 'Ahmet', rol: 'Senior' }, GIZLI_ANAHTAR, { expiresIn: '1h' });

    res.json({ token });

});

 

// Korunan Rota Kontrolü (Middleware)

const kimlikKontrol = (req, res, next) => {

    const authHeader = req.headers['authorization'];

    const token = authHeader && authHeader.split(' ')[1];

    if (!token) return res.status(401).json({ hata: 'Token eksik' });

   

    jwt.verify(token, GIZLI_ANAHTAR, (err, decoded) => {

        if (err) return res.status(403).json({ hata: 'Geçersiz Token' });

        req.user = decoded;

        next();

    });

};

 

app.get('/api/korunan-veri', kimlikKontrol, (req, res) => {

    res.json({ mesaj: 'Güvenli veritabanı alanına hoş geldiniz!', yetki: req.user.rol });

});

 

app.listen(8000, () => console.log('🚀 API Sunucusu 8000 portunda aktif!'));

Çalıştırma ve Test: Terminalde npm start yazın. Postman veya tarayıcı üzerinden http://localhost:8000/auth/login adresine giderek token alın. Ardından bu token'ı Bearer Token olarak ekleyip http://localhost:8000/api/korunan-veri adresine istek atın.


3. Modern Veri Katmanı (GraphQL - Apollo Server)

Mevcut projeniz açıkken, bağımsız çalışacak bir GraphQL oyun alanı (Playground) tasarlayalım.

Adım A: Kod Altyapısı

Projenizde graphql-server.js isimli bir dosya oluşturun:

const { ApolloServer, gql } = require('apollo-server');

 

// Şema Tanımı

const typeDefs = gql`

    type Gorev {

        id: ID!

        baslik: String!

        tamamlandi: Boolean!

    }

    type Query {

        gorevler: [Gorev]

    }

`;

 

// Sahte Veri seti

const veriKumesi = [

    { id: '1', baslik: 'Event Loop Mülakat Sorusuna Çalış', tamamlandi: true },

    { id: '2', baslik: 'Docker İmajını AWS\'e Yükle', tamamlandi: false }

];

 

// Çözümleyiciler (Resolvers)

const resolvers = {

    Query: {

        gorevler: () => veriKumesi

    }

};

 

const server = new ApolloServer({ typeDefs, resolvers });

 

server.listen({ port: 4000 }).then(({ url }) => {

    console.log(`📊 GraphQL Sunucusu ${url} adresinde hazır!`);

});

Çalıştırma ve Test: Terminalde ayrı bir sekme açıp node graphql-server.js komutunu çalıştırın. Tarayıcınızdan http://localhost:4000 adresine girerek Apollo Sandbox arayüzünde sorgularınızı görsel olarak test edin.


4. Gerçek Zamanlı İletişim Katmanı (WebSockets - Socket.io)

Anlık veri transferlerini simüle etmek için entegre bir HTTP ve WebSocket sunucusu kuruyoruz.

Adım A: Kod Altyapısı

Projenizde socket-server.js isimli bir dosya oluşturun:

const express = require('express');

const http = require('http');

const { Server } = require('socket.io');

 

const app = express();

const sunucu = http.createServer(app);

const io = new Server(sunucu, { cors: { origin: "*" } });

 

// Statik HTML testi için basit bir arayüz sunalım

app.get('/', (req, res) => {

    res.send(`

        <h1>Soket Test Alanı</h1>

        <script src="/socket.io/socket.io.js"></script>

        <script>

            const socket = io();

            socket.on('baglanti_mesaji', (data) => console.log('Sunucudan gelen:', data));

        </script>

        <p>Konsolu (F12) açarak anlık bağlantı logunu inceleyin.</p>

    `);

});

 

io.on('connection', (socket) => {

    console.log(`🔌 Yeni bir cihaz bağlandı. Soket ID: ${socket.id}`);

   

    // Bağlanan istemciye anında mesaj gönder

    socket.emit('baglanti_mesaji', { mesaj: 'Canlı sisteme başarıyla bağlandınız.' });

 

    socket.on('disconnect', () => {

        console.log(`❌ Cihaz ayrıldı: ${socket.id}`);

    });

});

 

sunucu.listen(5000, () => console.log('💬 Soket Sunucusu 5000 portunda aktif!'));

Çalıştırma ve Test: Terminalde node socket-server.js çalıştırın ve tarayıcıdan http://localhost:5000 adresine gidin. Sayfayı her yenilediğinizde terminalde yeni bir Soket ID'sinin düştüğünü göreceksiniz.


🖥️ BÖLÜM 2: Kıdemli (Senior) Backend Mülakat Soruları ve Cevapları

Soru 1: Node.js tek iş parçacıklı (Single-Threaded) olmasına rağmen, binlerce eşzamanlı I/O isteğini veritabanını veya sunucuyu kilitlemeden nasıl bu kadar performanslı yönetebiliyor? Arka plandaki mimariyi açıklayınız.

Cevap: Node.js'in gücü, JavaScript motorunun (V8) tek iş parçacıklı olmasıyla sınırlı değildir. Node.js mimarisi altında libuv adında C++ ile yazılmış güçlü bir kütüphane barındırır.


Soru 2: Event Loop (Olay Döngüsü) üzerindeki "Microtask Queue" (Job Queue) ile "Macrotask Queue" (Task Queue) arasındaki fark nedir? Hangisi daha önceliklidir? Bir örnekle açıklayınız.

Cevap: İki kuyruk da asenkron işlemlerin geri çağırım fonksiyonlarını tutar ancak öncelikleri tamamen farklıdır.

Öncelik Kuralı: Event Loop, Macrotask kuyruğundaki tek bir görevi çalıştırmadan önce Microtask kuyruğundaki tüm görevlerin tamamen bitmesini bekler. Microtask kuyruğu boşalmadan Macrotask aşamasına asla geçilmez.

Örnek Kod Çıktı Analizi:

setTimeout(() => console.log('Macrotask: Timeout'), 0);

Promise.resolve().then(() => console.log('Microtask: Promise'));

console.log('Senkron Kod');

Çıktı Sırası:

  1. Senkron Kod (Call Stack anında çalıştırır)
  2. Microtask: Promise (Microtask kuyruğu önceliklidir)
  3. Macrotask: Timeout (En son Macrotask kuyruğuna geçilir)

Soru 3: Üretim (Production) ortamında çalışan büyük ölçekli bir Node.js uygulamasında "Memory Leak" (Bellek Sızıntısı) olduğunu nasıl anlarsınız, bunu tespit etmek ve çözmek için hangi stratejileri/araçları kullanırsınız?

Cevap: Bellek sızıntısı, Garbage Collector'ın (Çöp Toplayıcı) artık kullanılmayan nesneleri hafızadan (Memory Heap) temizleyememesi durumudur. Zamanla sunucunun RAM kullanımı sürekli artar ve en sonunda Out of Memory (OOM) hatasıyla süreç çöker.

Tespit ve İzleme Stratejileri:

En Sık Yaşanan Sebepler ve Çözümler: Unutulan global değişkenler, temizlenmeyen setInterval zamanlayıcıları ve kapatılmayan WebSocket/Stream bağlantılarıdır. Kod kalitesini artırmak için event listener'ların işi bittiğinde removeListener ile temizlenmesi gerekir.


Soru 4: REST mimarisi ile GraphQL mimarisini kurumsal bir API projesi ölçeğinde karşılaştırınız. Hangi senaryoda hangisini tercih etmelisiniz?

Cevap: İki mimarinin kurumsal kıyaslaması şu kriterlere dayanır:

Kriter

REST API

GraphQL

Veri Taşınması

Sabit uç noktalar (endpoints) tüm veri modelini döner. Over-fetching (gereksiz fazla veri) sık yaşanır.

İstemci sadece ihtiyacı olan alanları talep eder. Ağ trafiği optimize edilir.

Ağ İstek Sayısı

İlişkili veriler için ardışık istekler gerekir (Under-fetching).

Tek bir sorgu (Query) ile iç içe geçmiş tüm ilişkili veriler tek seferde çekilir.

Önbellekleme (Caching)

HTTP seviyesinde (URL bazlı) CDN ve tarayıcı önbelleklemesi çok kolaydır.

Tüm istekler tek bir uç noktaya (/graphql) POST olarak atıldığı için HTTP önbelleklemesi zordur; Apollo Client gibi uygulama seviyesi caching çözümleri gerekir.

Tercih Senaryoları:


Soru 5: Node.js kümeleme (Clustering) mimarisi ile Worker Threads (İş Parçacıkları) arasındaki fark nedir? Bir e-ticaret sisteminde "Fatura PDF'i Oluşturma" ve "Gelen HTTP İsteklerini Karşılama" görevlerini bu iki yapıya nasıl dağıtırsınız?

Cevap: İki yapı tamamen farklı katmanları ölçeklemek için tasarlanmıştır:

E-Ticaret Senaryo Dağıtımı: