📚 Tutorial Node.js

Ghid complet de instalare și configurare pentru Node.js

← Înapoi la Tutoriale

🚀 Tutorial Node.js/Express.js - Feed JSON Mixbox

🎯 Acest tutorial te va ajuta să creezi un server Express.js pentru generarea feed-ului JSON cu produse.

📋 Cerințe Preliminare

  • Node.js 16.x sau mai nou
  • npm sau yarn
  • Bază de date (MongoDB, PostgreSQL, MySQL)
  • ORM/ODM (Mongoose pentru MongoDB, Sequelize pentru SQL)
  • Bază de date (MongoDB, PostgreSQL, MySQL)
  • ORM/ODM (Mongoose pentru MongoDB, Sequelize pentru SQL)
  • 📄 Formatul feed-ului JSON

    Feed-ul generează un obiect JSON cu toate produsele indexate după SKU:

    {
      "SKU12345": {
        "sku": "SKU12345",
        "name": "Numele produsului",
        "qty": "10",
        "price": 150.50,
        "sale_price": 120.00,
        "last_update_date": "2025-08-08 10:30:00",
        "description": "Descrierea completă a produsului...",
        "weight": "2.5",
        "images": [
          {"src": "https://site-ul-vostru.com/wp-content/uploads/image1.jpg"},
          {"src": "https://site-ul-vostru.com/wp-content/uploads/image2.jpg"}
        ],
        "permalink": "https://site-ul-vostru.com/product/numele-produsului/",
        "categories_tree": [
          {
            "id": 25,
            "name": "Categoria Principală",
            "parent": 0,
            "image": "https://site-ul-vostru.com/category-image.jpg",
            "subcategories": [
              {
                "id": 30,
                "name": "Subcategoria",
                "parent": 25,
                "image": "https://site-ul-vostru.com/subcategory-image.jpg",
                "subcategories": []
              }
            ]
          }
        ],
        "breadcrumbs": [
          "Categoria Principală > Subcategoria"
        ],
        "brands": [
          {
            "name": "NUMELE BRANDULUI",
            "image": "https://site-ul-vostru.com/brand-logo.jpg"
          }
        ]
      }
    }
    

    📦 Pasul 1: Instalare Pachet

    Descarcă pachetul Node.js pentru feed JSON:

    După descărcare, extrage fișierele și navighează în director:

    cd nodejs-product-feed
    npm install

    🔧 Pasul 2: Configurare Bază de Date

    Creează modelul pentru produse (exemplu cu Mongoose):

    // models/Product.js
    const mongoose = require('mongoose');
    
    const productSchema = new mongoose.Schema({
        name: {
            type: String,
            required: true,
            trim: true
        },
        description: {
            type: String,
            trim: true
        },
        price: {
            type: Number,
            required: true,
            min: 0
        },
        salePrice: {
            type: Number,
            min: 0
        },
        sku: {
            type: String,
            required: true,
            unique: true,
            trim: true
        },
        category: {
            type: String,
            required: true,
            trim: true
        },
        brand: {
            type: String,
            trim: true
        },
        subcategories: [{
            type: String,
            trim: true
        }],
        imageUrl: {
            type: String,
            trim: true
        },
        stockQuantity: {
            type: Number,
            default: 0,
            min: 0
        },
        isActive: {
            type: Boolean,
            default: true
        },
        tags: [String],
        attributes: {
            type: Map,
            of: String
        },
        weight: {
            type: Number,
            min: 0
        }
    }, {
        timestamps: true
    });
    
    // Index pentru căutări rapide
    productSchema.index({ name: 'text', description: 'text' });
    productSchema.index({ category: 1 });
    productSchema.index({ price: 1 });
    productSchema.index({ isActive: 1 });
    
    module.exports = mongoose.model('Product', productSchema);

    🌐 Pasul 3: Creare Server Express

    Creează server-ul principal:

    // server.js
    const express = require('express');
    const mongoose = require('mongoose');
    const cors = require('cors');
    const helmet = require('helmet');
    const compression = require('compression');
    const rateLimit = require('express-rate-limit');
    require('dotenv').config();
    
    const Product = require('./models/Product');
    
    const app = express();
    const PORT = process.env.PORT || 3000;
    
    // Middleware de securitate
    app.use(helmet());
    app.use(compression());
    app.use(cors({
        origin: process.env.ALLOWED_ORIGINS?.split(',') || ['http://localhost:3000'],
        credentials: true
    }));
    
    // Rate limiting
    const limiter = rateLimit({
        windowMs: 15 * 60 * 1000, // 15 minute
        max: 100, // limit each IP to 100 requests per windowMs
        message: {
            error: 'Too many requests from this IP, please try again later.'
        }
    });
    
    app.use('/api/', limiter);
    
    // Middleware pentru parsing JSON
    app.use(express.json({ limit: '10mb' }));
    app.use(express.urlencoded({ extended: true }));
    
    // Conexiune la baza de date
    mongoose.connect(process.env.MONGODB_URI || 'mongodb://localhost:27017/productdb', {
        useNewUrlParser: true,
        useUnifiedTopology: true,
    })
    .then(() => console.log('Connected to MongoDB'))
    .catch(err => console.error('MongoDB connection error:', err));
    
    // Middleware pentru autentificare API (opțional)
    const authenticateApiKey = (req, res, next) => {
        const apiKey = req.query.api_key || req.headers['x-api-key'];
    
        if (process.env.API_KEY && apiKey !== process.env.API_KEY) {
            return res.status(401).json({ error: 'Invalid API key' });
        }
    
        next();
    };
    
    // Ruta principală pentru feed
    app.get('/api/products/feed', authenticateApiKey, async (req, res) => {
        try {
            const {
                limit = 100,
                page = 1,
                category,
                min_price,
                max_price,
                search,
                sort = 'createdAt',
                order = 'desc'
            } = req.query;
    
            // Construiește query-ul
            let query = { isActive: true };
    
            // Filtrare după categorie
            if (category) {
                query.category = category;
            }
    
            // Filtrare după preț
            if (min_price || max_price) {
                query.price = {};
                if (min_price) query.price.$gte = parseFloat(min_price);
                if (max_price) query.price.$lte = parseFloat(max_price);
            }
    
            // Căutare text
            if (search) {
                query.$text = { $search: search };
            }
    
            // Calculează offset pentru paginare
            const offset = (parseInt(page) - 1) * parseInt(limit);
    
            // Sortează
            const sortOptions = {};
            sortOptions[sort] = order === 'desc' ? -1 : 1;
    
            // Execută query-ul
            const products = await Product.find(query)
                .sort(sortOptions)
                .skip(offset)
                .limit(parseInt(limit))
                .select('-__v'); // Exclude versiunea mongoose
    
            // Numără totalul pentru paginare
            const totalProducts = await Product.countDocuments(query);
    
            // Formatează răspunsul în formatul Mixbox
            const feedData = {};
    
            products.forEach(product => {
                const sku = product.sku || 'PROD-' + product._id.toString();
    
                feedData[sku] = {
                    sku: sku,
                    name: product.name,
                    qty: product.stockQuantity?.toString() || '0',
                    price: parseFloat(product.price),
                    sale_price: product.salePrice || null,
                    last_update_date: product.updatedAt?.toISOString().slice(0, 19).replace('T', ' ') || new Date().toISOString().slice(0, 19).replace('T', ' '),
                    description: product.description,
                    weight: product.weight || null,
                    images: product.imageUrl ? [{ src: product.imageUrl }] : [],
                    permalink: `${process.env.BASE_URL || 'https://your-site.com'}/products/${product._id}`,
                    categories_tree: [{
                        id: 25,
                        name: product.category || 'Categoria Principală',
                        parent: 0,
                        image: 'https://site-ul-vostru.com/category-image.jpg',
                        subcategories: product.subcategories || [{
                            id: 30,
                            name: 'Subcategoria',
                            parent: 25,
                            image: 'https://site-ul-vostru.com/subcategory-image.jpg',
                            subcategories: []
                        }]
                    }],
                    breadcrumbs: [product.category ? product.category + ' > Subcategoria' : 'Categoria Principală > Subcategoria'],
                    brands: product.brand ? [{
                        name: product.brand,
                        image: 'https://site-ul-vostru.com/brand-logo.jpg'
                    }] : []
                };
            });
    
            // Cache headers
            res.set({
                'Cache-Control': 'public, max-age=300', // Cache 5 minute
                'Content-Type': 'application/json'
            });
    
            res.json(feedData);
    
        } catch (error) {
            console.error('Feed error:', error);
            res.status(500).json({
                error: 'Internal server error',
                message: process.env.NODE_ENV === 'development' ? error.message : undefined
            });
        }
    });
    
    // Endpoint pentru sănătatea aplicației
    app.get('/health', (req, res) => {
        res.json({
            status: 'OK',
            timestamp: new Date().toISOString(),
            uptime: process.uptime()
        });
    });
    
    // Middleware pentru erori 404
    app.use((req, res) => {
        res.status(404).json({ error: 'Endpoint not found' });
    });
    
    // Middleware pentru erori generale
    app.use((error, req, res, next) => {
        console.error('Unhandled error:', error);
        res.status(500).json({
            error: 'Internal server error',
            message: process.env.NODE_ENV === 'development' ? error.message : undefined
        });
    });
    
    // Începe server-ul
    app.listen(PORT, () => {
        console.log(`Server running on port ${PORT}`);
        console.log(`Feed available at: http://localhost:${PORT}/api/products/feed`);
    });
    
    module.exports = app;

    ⚙️ Pasul 4: Configurare Environment

    Creează fișierul .env:

    # Server Configuration
    PORT=3000
    NODE_ENV=development
    
    # Database
    MONGODB_URI=mongodb://localhost:27017/productdb
    
    # Security
    API_KEY=your_secret_api_key_here
    ALLOWED_ORIGINS=http://localhost:3000,https://yourdomain.com
    
    # Rate Limiting
    RATE_LIMIT_WINDOW=15
    RATE_LIMIT_MAX_REQUESTS=100

    📦 Pasul 5: Package.json

    Fișierul package.json pentru dependințe:

    {
      "name": "nodejs-product-feed",
      "version": "1.0.0",
      "description": "Node.js Express server for JSON product feed",
      "main": "server.js",
      "scripts": {
        "start": "node server.js",
        "dev": "nodemon server.js",
        "test": "jest",
        "seed": "node scripts/seed.js"
      },
      "dependencies": {
        "express": "^4.18.2",
        "mongoose": "^7.5.0",
        "cors": "^2.8.5",
        "helmet": "^7.0.0",
        "compression": "^1.7.4",
        "express-rate-limit": "^6.10.0",
        "dotenv": "^16.3.1"
      },
      "devDependencies": {
        "nodemon": "^3.0.1",
        "jest": "^29.6.4",
        "supertest": "^6.3.3"
      },
      "keywords": ["express", "api", "products", "feed", "json"],
      "author": "Mixbox",
      "license": "MIT"
    }

    🧪 Pasul 6: Testare Feed

    Pornește server-ul și testează feed-ul:

    # Pornește server-ul
    npm run dev
    
    # Testează feed-ul de bază
    curl "http://localhost:3000/api/products/feed"
    
    # Cu parametri
    curl "http://localhost:3000/api/products/feed?limit=10&page=1&category=electronics"
    
    # Cu API key
    curl "http://localhost:3000/api/products/feed?api_key=your_api_key"
    
    # Verifică sănătatea
    curl "http://localhost:3000/health"

    🚀 Pasul 7: Deployment

    Pentru deployment în producție:

    # 1. Instalează doar dependințele de producție
    npm ci --only=production
    
    # 2. Configurează variabilele de mediu pentru producție
    NODE_ENV=production
    MONGODB_URI=mongodb://production-server/productdb
    
    # 3. Pornește server-ul
    npm start

    📊 Pasul 8: Monitorizare

    Adaugă logging pentru monitorizare:

    // Adaugă winston pentru logging avansat
    const winston = require('winston');
    
    const logger = winston.createLogger({
        level: 'info',
        format: winston.format.json(),
        transports: [
            new winston.transports.File({ filename: 'logs/error.log', level: 'error' }),
            new winston.transports.File({ filename: 'logs/combined.log' }),
        ],
    });
    
    // În middleware-ul pentru feed
    logger.info('Feed accessed', {
        ip: req.ip,
        userAgent: req.get('User-Agent'),
        query: req.query,
        timestamp: new Date().toISOString()
    });
    ✅ Felicitări! Ai implementat cu succes un server Express.js pentru feed JSON. API-ul tău este acum gata să servească date pentru alte aplicații!

    🔗 Link-uri Utile