Perché Node.js per il Backend?
Node.js ti permette di eseguire JavaScript sul server. Questa è la spiegazione in una frase. Ma perché conta? Tre ragioni ne hanno guidato l'adozione da quando Ryan Dahl lo ha creato nel 2009:
- Un solo linguaggio ovunque. Se il tuo team frontend scrive React o Vue (JavaScript), il tuo team backend può scrivere JavaScript anche lui. Linguaggio condiviso significa conoscenza condivisa, funzioni utility condivise e assunzioni più facili. Confrontiamo i framework frontend nel nostro confronto React vs Vue.
- I/O non bloccante. Node.js gestisce migliaia di connessioni simultanee in modo efficiente perché non crea un nuovo thread per ogni richiesta. Questo lo rende eccellente per applicazioni real-time, API e carichi di lavoro con molte operazioni I/O.
- Ecosistema npm. Il Node Package Manager ti dà accesso a oltre 1,5 milioni di pacchetti. (Questo è anche un rischio per la supply chain, come abbiamo discusso nel nostro articolo su Log4j e le dipendenze software.)
Node.js è usato in produzione da Netflix, LinkedIn, PayPal, Uber, NASA e migliaia di aziende. Non è una tecnologia di nicchia. È una scelta backend mainstream.
L'Event Loop: Cosa Rende Node.js Diverso
La maggior parte dei linguaggi backend (PHP, Python con WSGI tradizionale, Java con thread) gestisce le richieste concorrenti creando un nuovo thread o processo per ciascuna. Se 1.000 utenti colpiscono il tuo server simultaneamente, hai bisogno di risorse per 1.000 thread. Ogni thread resta inattivo mentre aspetta query al database, letture di file o chiamate API.
Node.js funziona diversamente. Gira su un singolo thread con un event loop. Quando arriva una richiesta che deve aspettare qualcosa (una query al database, una lettura di file, una chiamata HTTP a un altro servizio), Node.js non si blocca. Registra un callback e passa alla richiesta successiva. Quando la query al database finisce, il callback si attiva e Node.js processa il risultato.
Pensalo come un ristorante con un solo cameriere estremamente veloce. Invece di stare fermo al tavolo 1 aspettando che il cibo arrivi dalla cucina, il cameriere prende l'ordine del tavolo 2, poi del tavolo 3, poi consegna il cibo del tavolo 1 quando la cucina suona la campanella.
Quando Questo Modello Eccelle
- Server API che gestiscono molte richieste concorrenti
- Applicazioni real-time (chat, notifiche, dashboard live)
- Microservizi che aggregano dati da fonti multiple
- Applicazioni di streaming (upload/download file, video)
- Server-side rendering per framework frontend (Next.js, Nuxt)
Quando Questo Modello Soffre
- Task CPU-intensive (elaborazione immagini, encoding video, calcoli complessi). Questi bloccano il singolo thread e fanno aspettare tutto il resto.
Express.js: La Base della Maggior Parte delle API Node.js
Express.js è un framework web minimale per Node.js. È stata la scelta predefinita per costruire API e applicazioni web in Node.js dal 2010.
Configurare un Server Express Base
const express = require('express');
const app = express();
const PORT = process.env.PORT || 3000;
app.use(express.json());
app.get('/api/health', (req, res) => {
res.json({ status: 'ok', timestamp: new Date().toISOString() });
});
app.listen(PORT, () => {
console.log(`Server in esecuzione sulla porta ${PORT}`);
});
Middleware: Il Pattern di Express
Express è costruito attorno ai middleware: funzioni che si eseguono in sequenza per ogni richiesta. Ogni funzione middleware può leggere la richiesta, modificare la risposta o passare il controllo al middleware successivo. Questo pattern è ciò che rende Express flessibile.
Costruire una REST API: Passo Dopo Passo
Struttura del Progetto
project/
src/
routes/
products.js
controllers/
productController.js
middleware/
auth.js
errorHandler.js
config/
database.js
app.js
server.js
package.json
Questa struttura separa le responsabilità: le route definiscono gli endpoint, i controller gestiscono la logica di business, i middleware gestiscono le preoccupazioni trasversali e config gestisce le connessioni esterne.
Connessioni Database
PostgreSQL con pg
PostgreSQL è il database più comune abbinato a Node.js nelle applicazioni in produzione. Usare un connection pool (non una singola connessione) è fondamentale. Il pool gestisce multiple connessioni e le riusa, il che impedisce al tuo server di aprire migliaia di connessioni sotto carico.
MongoDB con Mongoose
Se i tuoi dati sono document-oriented (schemi variabili, oggetti annidati, iterazione rapida), MongoDB con Mongoose è popolare nell'ecosistema Node.js.
Quale Database Scegliere?
PostgreSQL quando: hai bisogno di dati relazionali, transazioni, query complesse, consistenza forte. Questo copre la maggior parte delle applicazioni aziendali.
MongoDB quando: la struttura dei dati varia significativamente tra i record, hai bisogno di scalabilità orizzontale dall'inizio, o stai prototipando rapidamente e il tuo schema sta ancora evolvendo.
Per la maggior parte delle applicazioni business costruite da PMI in Svizzera, PostgreSQL è il default più sicuro.
Autenticazione con JWT
I JSON Web Token (JWT) sono il modo standard per gestire l'autenticazione nelle API Node.js. Note di sicurezza: fai sempre l'hash delle password con bcrypt (mai testo in chiaro). Usa un segreto JWT forte e casuale (almeno 256 bit). Imposta tempi di scadenza ragionevoli. Conserva i token in cookie httpOnly per le applicazioni browser, non in localStorage (localStorage è accessibile a JavaScript, il che significa che gli attacchi XSS possono rubare i token).
Pattern di Gestione Errori
La gestione corretta degli errori separa il codice Node.js amatoriale da quello pronto per la produzione. Il principio chiave: distingui tra errori operazionali (input non valido, risorsa non trovata, fallimento autenticazione) e errori di programmazione (riferimento null, errori di tipo, rejection non gestite). Gli errori operazionali restituiscono messaggi significativi al client. Gli errori di programmazione restituiscono un messaggio generico e vengono registrati per l'indagine.
Testing con Jest
Jest è il framework di testing più popolare per Node.js. Fornisce esecuzione test, asserzioni e mocking in un singolo pacchetto. Scrivi test per ogni endpoint. Testa il percorso felice, i casi di errore, i casi limite e l'autenticazione. Supertest rende facile inviare richieste HTTP alla tua app Express senza avviare un server.
Node.js vs PHP vs Python: Quando Usare Cosa
| Aspetto | Node.js | PHP | Python |
|---|---|---|---|
| Ideale per | API, app real-time, microservizi | Siti di contenuti, WordPress, sistemi legacy | Data science, ML, script, API Django/Flask |
| Modello concorrenza | Event loop (non bloccante) | Processo per richiesta (tradizionale) | Thread/async (varia per framework) |
| Curva di apprendimento | Moderata (pattern asincroni) | Facile (per le basi) | Facile-moderata |
| Hosting | VPS, PaaS, container | Hosting condiviso, VPS, ovunque | VPS, PaaS, container |
| Sicurezza tipi | TypeScript (opzionale) | Tipizzazione debole (PHP 8 migliorato) | Type hints (opzionali) |
| Uso tipico in CH | Startup, agenzie, stack moderni | Web tradizionale, siti WordPress | Finanza, farmaceutica, dati, accademia |
Considerazioni di Sicurezza per Backend Node.js
Un'API Node.js esposta a internet ha bisogno di diversi livelli di protezione:
Helmet.js
Helmet imposta vari header HTTP per proteggere la tua app dagli attacchi comuni. Una riga di codice, miglioramento significativo della sicurezza. Aggiunge Content-Security-Policy, X-Content-Type-Options, X-Frame-Options e altri header di sicurezza.
Rate Limiting
Senza rate limiting, un attaccante può sommergere la tua API con richieste (attacchi brute force, denial of service, scraping dati).
Validazione Input
Non fidarti mai dell'input dell'utente. Valida e sanifica tutto. La validazione dell'input previene SQL injection, XSS e altri attacchi di injection. Per una comprensione più profonda di XSS, vedi la nostra spiegazione degli attacchi XSS. L'OWASP Top 10, che copriamo nella nostra guida OWASP Top 10, elenca l'injection come uno dei rischi più comuni.
Misure di Sicurezza Aggiuntive
- Usa query parametrizzate per tutte le operazioni database. Non concatenare mai input utente nelle stringhe SQL.
- Configura CORS correttamente specificando le origini permesse, non usando
*in produzione. - Mantieni le dipendenze aggiornate. Esegui
npm auditregolarmente. - Usa sempre HTTPS. In produzione, termina SSL al load balancer o reverse proxy.
- Memorizza i segreti in variabili d'ambiente, mai nel codice.
Suggerimenti per le Performance
- Usa la compressione: riduce le dimensioni delle risposte del 60-80%.
- Aggiungi header di caching per i dati che non cambiano frequentemente.
- Usa il connection pooling: usa sempre un pool per le connessioni database.
- Esegui con PM2 o cluster mode: Node.js gira su un singolo core per default. PM2 o il modulo cluster eseguono multiple istanze per usare tutti i core CPU.
- Paginazione ovunque: non restituire mai risultati senza limiti.
Iniziare: Cosa Costruire Prima
Se sei nuovo nello sviluppo backend Node.js, ecco un percorso di apprendimento pratico. Costruisci una REST API semplice con Express, poi aggiungi PostgreSQL, autenticazione JWT, validazione input, gestione errori, test con Jest e infine fai il deploy.
Se il tuo team ha bisogno di aiuto per architettare un backend Node.js, o per fare un audit di un'applicazione Node.js esistente per sicurezza e performance, contattaci. Costruiamo e revisioniamo sistemi backend per aziende a Lugano e in tutta la Svizzera.
Vuoi sapere se il tuo sito è sicuro?
Richiedi un audit di sicurezza gratuito. In 48 ore ricevi un report completo.
Richiedi Audit Gratuito