1. Pengenalan Node.js
Node.js adalah runtime environment JavaScript yang berjalan di luar browser β di server, desktop, atau perangkat IoT. Dikembangkan oleh Ryan Dahl pada tahun 2009, Node.js memungkinkan pengembang menggunakan JavaScript untuk membangun backend, API, dan aplikasi jaringan yang scalable.
Node.js dibangun di atas mesin JavaScript V8 dari Google Chrome dan menggunakan model event-driven, non-blocking I/O yang membuatnya sangat efisien untuk menangani banyak koneksi secara bersamaan. Ini menjadikan Node.js pilihan ideal untuk aplikasi real-time seperti chat, streaming, dan API berperforma tinggi.
Mengapa Memilih Node.js?
| Keunggulan | Penjelasan |
|---|---|
| Non-blocking I/O | Menangani ribuan koneksi secara bersamaan tanpa blocking thread |
| Full-stack JavaScript | Bahasa yang sama untuk frontend dan backend β mempercepat pengembangan |
| NPM Ecosystem | Lebih dari 2 juta package siap pakai di npm registry |
| Event-driven | Cocok untuk aplikasi real-time seperti chat, notifikasi, dan streaming |
| Performa Tinggi | V8 engine mengkompilasi JavaScript ke native machine code |
| Komunitas Besar | Dukungan luas dari perusahaan seperti Netflix, PayPal, LinkedIn |
Arsitektur Node.js
βββββββββββββββββββββββββββββββββββββββββββββββββββββββ β NODE.JS ARCHITECTURE β β β β βββββββββββββββ βββββββββββββββββββββββββββββ β β β Request βββββΊβ Event Loop (Single β β β β (Client) β β Thread) β β β βββββββββββββββ β β β β β βββββββββββββββββββββββ β β β βββββββββββββββ β β Callback Queue β β β β β Response ββββββ β (Microtask / β β β β β (Server) β β β Macrotask) β β β β βββββββββββββββ β βββββββββββββββββββββββ β β β βββββββββββ¬ββββββββββββββββββ β β β β β βββββββββββΌββββββββββββββββββ β β β C++ Thread Pool β β β β (File I/O, DNS, Crypto) β β β βββββββββββββββββββββββββββββ β β β β βββββββββββββββββββββββββββββββββββββββββββββββββ β β β V8 JavaScript Engine β β β β (Kompilasi JS β Native Machine Code) β β β βββββββββββββββββββββββββββββββββββββββββββββββββ β βββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Instalasi Node.js
Unduh Node.js dari situs resmi nodejs.org atau gunakan nvm (Node Version Manager) untuk mengelola beberapa versi:
# Cek versi Node.js yang terinstal
node --version
# v20.x.x
# Cek versi npm
npm --version
# 10.x.x
# Instal nvm (Linux/macOS)
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.0/install.sh | bash
# Instal Node.js terbaru dengan nvm
nvm install --lts
nvm use --lts
# Membuat proyek baru
mkdir my-server && cd my-server
npm init -y
# Hasilnya file package.json:
# {
# "name": "my-server",
# "version": "1.0.0",
# "description": "",
# "main": "index.js",
# "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }
# }
Node.js Dasar: Menjalankan JavaScript di Server
// File: hello.js
// Jalankan dengan: node hello.js
// Menggunakan module bawaan (built-in)
const os = require('os');
const path = require('path');
// Informasi sistem
console.log('Platform:', os.platform());
console.log('Architecture:', os.arch());
console.log('CPUs:', os.cpus().length);
console.log('Free Memory:', Math.round(os.freemem() / 1024 / 1024), 'MB');
console.log('Home Directory:', os.homedir());
console.log('Current Directory:', __dirname);
console.log('File:', path.basename(__filename));
// Membuat web server sederhana TANPA framework
const http = require('http');
const server = http.createServer((req, res) => {
res.writeHead(200, { 'Content-Type': 'application/json' });
res.end(JSON.stringify({
message: 'Hello dari Node.js!',
timestamp: new Date().toISOString()
}));
});
server.listen(3000, () => {
console.log('Server berjalan di http://localhost:3000');
});
2. NPM & Package Management
NPM (Node Package Manager) adalah package manager default yang disertai dengan Node.js. NPM memungkinkan Anda menginstal, mengelola, dan berbagi package (library) JavaScript. Saat ini, npm memiliki lebih dari 2 juta package di registry-nya.
Perintah NPM yang Sering Digunakan
| Perintah | Fungsi |
|---|---|
npm init -y | Membuat file package.json dengan nilai default |
npm install <pkg> | Menginstal package (dependencies) |
npm install -D <pkg> | Menginstal sebagai devDependencies |
npm uninstall <pkg> | Menghapus package |
npm update | Memperbarui semua package |
npm run <script> | Menjalankan script dari package.json |
npm list | Menampilkan daftar package terinstal |
npm audit | Memeriksa kerentanan keamanan |
# Inisialisasi proyek npm init -y # Instal Express npm install express # Instal beberapa package sekaligus npm install express cors helmet morgan dotenv # Instal dev dependencies npm install -D nodemon # Lihat daftar package yang terinstal npm list --depth=0
Konfigurasi package.json
{
"name": "express-server",
"version": "1.0.0",
"description": "Web server dengan Express.js",
"main": "index.js",
"scripts": {
"start": "node index.js",
"dev": "nodemon index.js",
"test": "jest --coverage"
},
"keywords": ["express", "node", "api"],
"author": "BeebaneLabs",
"license": "MIT",
"dependencies": {
"express": "^4.18.2",
"cors": "^2.8.5",
"helmet": "^7.1.0",
"morgan": "^1.10.0",
"dotenv": "^16.3.1"
},
"devDependencies": {
"nodemon": "^3.0.2"
}
}
Dependencies adalah package yang dibutuhkan aplikasi saat berjalan di production (misal: Express, Mongoose). DevDependencies hanya dibutuhkan selama pengembangan (misal: Nodemon, Jest, ESLint). Pisahkan keduanya agar ukuran deployment lebih kecil.
3. Memulai dengan Express.js
Express.js adalah framework web minimalis dan fleksibel untuk Node.js. Express menyediakan fitur-fitur yang kuat untuk membuat web server dan API β seperti routing, middleware, dan template engine β tanpa menghilangkan kesederhanaan Node.js.
Server Pertama dengan Express
/*
* Web Server Sederhana dengan Express.js
* BeebaneLabs - https://beebanelabs.pages.dev
*/
const express = require('express');
const app = express();
const PORT = process.env.PORT || 3000;
// Middleware bawaan: parsing JSON body
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
// Route utama β GET /
app.get('/', (req, res) => {
res.json({
message: 'Selamat datang di Express.js!',
status: 'running',
timestamp: new Date().toISOString()
});
});
// Route health check β GET /health
app.get('/health', (req, res) => {
res.json({
status: 'healthy',
uptime: process.uptime(),
memory: process.memoryUsage()
});
});
// Menjalankan server
app.listen(PORT, () => {
console.log(`Server berjalan di http://localhost:${PORT}`);
});
# Jalankan server
node index.js
# Atau dengan nodemon (auto-reload saat kode berubah)
npx nodemon index.js
# Output:
# Server berjalan di http://localhost:3000
# Test dengan curl:
$ curl http://localhost:3000/
{"message":"Selamat datang di Express.js!","status":"running","timestamp":"2026-06-25T10:30:00.000Z"}
4. Routing di Express
Routing menentukan bagaimana aplikasi merespons request client ke endpoint tertentu (URL) dengan HTTP method tertentu (GET, POST, PUT, DELETE). Express menyediakan API routing yang sangat fleksibel dan ekspresif.
Dasar-dasar Routing
// Basic routing
app.get('/', (req, res) => {
res.send('Halaman Beranda');
});
app.get('/tentang', (req, res) => {
res.send('Halaman Tentang Kami');
});
app.get('/kontak', (req, res) => {
res.send('Halaman Kontak');
});
// Route dengan parameter (path parameter)
app.get('/pengguna/:id', (req, res) => {
const { id } = req.params;
res.json({
message: `Profil pengguna ${id}`,
userId: id
});
});
// Route dengan multiple parameters
app.get('/post/:kategori/:postId', (req, res) => {
const { kategori, postId } = req.params;
res.json({
kategori: kategori,
postId: postId,
url: `/post/${kategori}/${postId}`
});
});
// Query parameters (?key=value&key2=value2)
app.get('/cari', (req, res) => {
const { q, halaman = 1, limit = 10 } = req.query;
res.json({
query: q,
halaman: parseInt(halaman),
limit: parseInt(limit)
});
// Contoh: GET /cari?q=laptop&halaman=2&limit=5
});
// POST route β menerima data dari client
app.post('/pengguna', (req, res) => {
const { nama, email } = req.body;
res.status(201).json({
message: 'Pengguna berhasil dibuat',
pengguna: { nama, email }
});
});
// PUT route β memperbarui data
app.put('/pengguna/:id', (req, res) => {
const { id } = req.params;
const data = req.body;
res.json({
message: `Pengguna ${id} berhasil diperbarui`,
data: data
});
});
// DELETE route β menghapus data
app.delete('/pengguna/:id', (req, res) => {
const { id } = req.params;
res.json({
message: `Pengguna ${id} berhasil dihapus`
});
});
Express Router (Modular Routing)
Untuk proyek besar, pisahkan route ke beberapa file menggunakan express.Router():
// File: routes/produk.js
const express = require('express');
const router = express.Router();
let produk = [
{ id: 1, nama: 'Laptop', harga: 12000000 },
{ id: 2, nama: 'Mouse', harga: 250000 },
{ id: 3, nama: 'Keyboard', harga: 800000 },
];
// GET semua produk
router.get('/', (req, res) => {
res.json(produk);
});
// GET produk berdasarkan ID
router.get('/:id', (req, res) => {
const item = produk.find(p => p.id === parseInt(req.params.id));
if (!item) return res.status(404).json({ error: 'Produk tidak ditemukan' });
res.json(item);
});
// POST produk baru
router.post('/', (req, res) => {
const newItem = {
id: produk.length + 1,
nama: req.body.nama,
harga: req.body.harga
};
produk.push(newItem);
res.status(201).json(newItem);
});
module.exports = router;
// ==========================================
// File: index.js (menggunakan router)
// ==========================================
const produkRoutes = require('./routes/produk');
app.use('/api/produk', produkRoutes);
// Sekarang: GET /api/produk, GET /api/produk/1, POST /api/produk
5. Middleware
Middleware adalah fungsi yang berjalan di antara request dan response. Middleware bisa mengakses objek req, res, dan next. Middleware digunakan untuk logging, autentikasi, validasi, CORS, dan banyak lagi.
Cara Kerja Middleware
ββββββββββ ββββββββββββββββ ββββββββββββββββ ββββββββββββ
β Request βββββΊβ Middleware 1 βββββΊβ Middleware 2 βββββΊβ Route β
β (Client)β β (Logger) β β (Auth) β β Handler β
ββββββββββ ββββββββββββββββ ββββββββββββββββ ββββββ¬ββββββ
β
ββββββββββ ββββββββββββββββ ββββββββββββββββ β
βResponse ββββββ Middleware N ββββββ Middleware 3 βββββββββββ
β (Client)β β (Error) β β (CORS) β
ββββββββββ ββββββββββββββββ ββββββββββββββββ
Membuat dan Menggunakan Middleware
// 1. Custom Logger Middleware
const logger = (req, res, next) => {
const waktu = new Date().toISOString();
console.log(`[${waktu}] ${req.method} ${req.url}`);
next(); // Lanjutkan ke middleware/route berikutnya
};
app.use(logger);
// 2. Auth Middleware
const autentikasi = (req, res, next) => {
const token = req.headers['authorization'];
if (!token || token !== 'Bearer my-secret-token') {
return res.status(401).json({
error: 'Unauthorized',
message: 'Token tidak valid atau tidak ditemukan'
});
}
req.user = { id: 1, role: 'admin' }; // Attach user ke request
next();
};
// Menggunakan middleware hanya untuk route tertentu
app.get('/admin/dashboard', autentikasi, (req, res) => {
res.json({
message: `Selamat datang, ${req.user.role}!`,
data: { stats: 'Semua data admin di sini' }
});
});
// 3. Rate Limiting Middleware (sederhana)
const rateLimit = {};
const rateLimiter = (req, res, next) => {
const ip = req.ip;
const now = Date.now();
if (!rateLimit[ip]) {
rateLimit[ip] = { count: 1, firstRequest: now };
} else if (now - rateLimit[ip].firstRequest < 60000) {
rateLimit[ip].count++;
if (rateLimit[ip].count > 100) {
return res.status(429).json({
error: 'Terlalu banyak request. Coba lagi dalam 1 menit.'
});
}
} else {
rateLimit[ip] = { count: 1, firstRequest: now };
}
next();
};
app.use(rateLimiter);
// 4. Middleware untuk parsing request body
app.use(express.json({ limit: '10mb' }));
app.use(express.urlencoded({ extended: true }));
// 5. CORS Middleware
const cors = require('cors');
app.use(cors({
origin: ['http://localhost:5173', 'https://beebanelabs.pages.dev'],
methods: ['GET', 'POST', 'PUT', 'DELETE'],
credentials: true
}));
// 6. Security Middleware
const helmet = require('helmet');
app.use(helmet());
// 7. HTTP Request Logger
const morgan = require('morgan');
app.use(morgan('combined'));
- Bawaan Express:
express.json(),express.urlencoded(),express.static() - Pihak ketiga:
cors,helmet,morgan,express-validator,multer - Custom: Buat sendiri sesuai kebutuhan β sangat fleksibel!
6. Template Engine (EJS)
Template engine memungkinkan Anda membuat halaman HTML dinamis dengan menyisipkan data dari server ke dalam template. Salah satu template engine paling populer untuk Express adalah EJS (Embedded JavaScript) karena sintaksnya yang langsung menggunakan JavaScript biasa di dalam HTML.
Setup EJS
# Instal EJS npm install ejs # Buat folder views mkdir views
// Konfigurasi EJS di Express
app.set('view engine', 'ejs');
app.set('views', './views');
// Route yang me-render template
app.get('/', (req, res) => {
res.render('index', {
judul: 'BeebaneLabs',
pesan: 'Selamat datang di tutorial Express!',
menu: ['Beranda', 'Tutorial', 'Kontak']
});
});
app.get('/produk', (req, res) => {
const daftarProduk = [
{ nama: 'Laptop ASUS', harga: 12000000, stok: 5 },
{ nama: 'Mouse Logitech', harga: 250000, stok: 20 },
{ nama: 'Keyboard Mekanik', harga: 800000, stok: 12 },
];
res.render('produk', {
judul: 'Daftar Produk',
produk: daftarProduk
});
});
Template EJS
<!DOCTYPE html>
<html lang="id">
<head>
<meta charset="UTF-8">
<title><%= judul %></title>
</head>
<body>
<nav>
<ul>
<% menu.forEach(item => { %>
<li><a href="#"><%= item %></a></li>
<% }); %>
</ul>
</nav>
<main>
<h1><%= judul %></h1>
<p><%= pesan %></p>
</main>
<%- include('partials/footer') %>
</body>
</html>
<!DOCTYPE html>
<html lang="id">
<head>
<meta charset="UTF-8">
<title><%= judul %></title>
</head>
<body>
<h1><%= judul %></h1>
<% if (produk.length === 0) { %>
<p>Tidak ada produk tersedia.</p>
<% } else { %>
<table border="1">
<thead>
<tr>
<th>Nama</th>
<th>Harga</th>
<th>Stok</th>
</tr>
</thead>
<tbody>
<% produk.forEach(item => { %>
<tr>
<td><%= item.nama %></td>
<td>Rp <%= item.harga.toLocaleString('id-ID') %></td>
<td><%= item.stok %></td>
</tr>
<% }); %>
</tbody>
</table>
<% } %>
</body>
</html>
7. Membangun REST API
Mari kita bangun REST API lengkap untuk mengelola data artikel. API ini mendukung operasi CRUD (Create, Read, Update, Delete) dengan data disimpan di memory (array). Untuk production, Anda bisa menggantinya dengan database seperti MongoDB atau PostgreSQL.
const express = require('express');
const app = express();
app.use(express.json());
// Simpan data di memory
let artikel = [
{ id: 1, judul: 'Belajar Node.js', penulis: 'Budi', tanggal: '2026-06-01' },
{ id: 2, judul: 'Tutorial Express', penulis: 'Sari', tanggal: '2026-06-15' },
{ id: 3, judul: 'REST API Design', penulis: 'Andi', tanggal: '2026-06-20' },
];
// GET semua artikel (dengan filter & pagination)
app.get('/api/artikel', (req, res) => {
let hasil = [...artikel];
// Filter berdasarkan penulis
if (req.query.penulis) {
hasil = hasil.filter(a =>
a.penulis.toLowerCase().includes(req.query.penulis.toLowerCase())
);
}
// Pagination
const halaman = parseInt(req.query.halaman) || 1;
const limit = parseInt(req.query.limit) || 10;
const mulai = (halaman - 1) * limit;
const totalArtikel = hasil.length;
hasil = hasil.slice(mulai, mulai + limit);
res.json({
status: 'success',
data: hasil,
pagination: {
halaman: halaman,
limit: limit,
total: totalArtikel,
totalPages: Math.ceil(totalArtikel / limit)
}
});
});
// GET satu artikel berdasarkan ID
app.get('/api/artikel/:id', (req, res) => {
const item = artikel.find(a => a.id === parseInt(req.params.id));
if (!item) {
return res.status(404).json({
status: 'error',
message: 'Artikel tidak ditemukan'
});
}
res.json({ status: 'success', data: item });
});
// POST artikel baru
app.post('/api/artikel', (req, res) => {
const { judul, penulis } = req.body;
// Validasi
if (!judul || !penulis) {
return res.status(400).json({
status: 'error',
message: 'Judul dan penulis wajib diisi'
});
}
const newItem = {
id: artikel.length > 0 ? Math.max(...artikel.map(a => a.id)) + 1 : 1,
judul,
penulis,
tanggal: new Date().toISOString().split('T')[0]
};
artikel.push(newItem);
res.status(201).json({
status: 'success',
message: 'Artikel berhasil dibuat',
data: newItem
});
});
// PUT memperbarui artikel
app.put('/api/artikel/:id', (req, res) => {
const index = artikel.findIndex(a => a.id === parseInt(req.params.id));
if (index === -1) {
return res.status(404).json({
status: 'error',
message: 'Artikel tidak ditemukan'
});
}
const { judul, penulis } = req.body;
artikel[index] = {
...artikel[index],
judul: judul || artikel[index].judul,
penulis: penulis || artikel[index].penulis
};
res.json({
status: 'success',
message: 'Artikel berhasil diperbarui',
data: artikel[index]
});
});
// DELETE artikel
app.delete('/api/artikel/:id', (req, res) => {
const index = artikel.findIndex(a => a.id === parseInt(req.params.id));
if (index === -1) {
return res.status(404).json({
status: 'error',
message: 'Artikel tidak ditemukan'
});
}
const deleted = artikel.splice(index, 1);
res.json({
status: 'success',
message: 'Artikel berhasil dihapus',
data: deleted[0]
});
});
app.listen(3000, () => console.log('API berjalan di http://localhost:3000'));
8. Error Handling
Error handling yang baik sangat penting untuk web server production. Express memiliki mekanisme khusus untuk menangkap error melalui error-handling middleware β middleware dengan 4 parameter: (err, req, res, next).
// Custom Error class
class AppError extends Error {
constructor(pesan, statusCode) {
super(pesan);
this.statusCode = statusCode;
this.status = statusCode < 500 ? 'fail' : 'error';
this.isOperational = true;
}
}
// Async wrapper untuk menangkap error di async route
const asyncHandler = (fn) => (req, res, next) => {
Promise.resolve(fn(req, res, next)).catch(next);
};
// Menggunakan asyncHandler pada route
app.get('/api/data/:id', asyncHandler(async (req, res) => {
const data = await ambilDataDariDB(req.params.id);
if (!data) {
throw new AppError('Data tidak ditemukan', 404);
}
res.json({ status: 'success', data });
}));
// Contoh route dengan error
app.get('/api/test-error', (req, res, next) => {
// Cara 1: Menggunakan next(error)
const err = new AppError('Contoh error sengaja', 400);
next(err);
});
// Error-handling middleware (HARUS 4 parameter!)
app.use((err, req, res, next) => {
const statusCode = err.statusCode || 500;
const status = err.status || 'error';
// Log error di server
console.error(`[ERROR] ${new Date().toISOString()}`);
console.error(` Status: ${statusCode}`);
console.error(` Pesan: ${err.message}`);
console.error(` Stack: ${err.stack}`);
// Kirim response ke client
res.status(statusCode).json({
status: status,
message: err.isOperational ? err.message : 'Terjadi kesalahan internal',
...(process.env.NODE_ENV === 'development' && {
stack: err.stack,
detail: err.message
})
});
});
// Handle 404 β route tidak ditemukan
app.use((req, res) => {
res.status(404).json({
status: 'error',
message: `Endpoint ${req.method} ${req.url} tidak ditemukan`
});
});
Di production, jangan pernah mengirim err.stack ke client. Cukup tampilkan pesan error yang ramah dan log detail error di server. Gunakan environment variable NODE_ENV=production untuk membedakan mode development dan production.
9. Serving Static Files
Express dapat melayani file statis seperti HTML, CSS, JavaScript, gambar, dan font menggunakan middleware express.static(). Ini sangat berguna untuk menyajikan frontend atau asset bersamaan dengan API.
const path = require('path');
// Setup folder statis
// Semua file di folder 'public' bisa diakses langsung
app.use(express.static(path.join(__dirname, 'public')));
// Bisa juga menambahkan prefix path
app.use('/assets', express.static(path.join(__dirname, 'assets')));
// Beberapa folder statis sekaligus
app.use(express.static('public'));
app.use(express.static('uploads'));
// Dengan opsi caching untuk performa
app.use(express.static('public', {
maxAge: '1d', // Cache selama 1 hari
etag: true, // Gunakan ETag
lastModified: true // Kirim Last-Modified header
}));
// Contoh struktur folder:
// my-server/
// βββ public/
// β βββ css/
// β β βββ style.css
// β βββ js/
// β β βββ app.js
// β βββ images/
// β β βββ logo.png
// β βββ index.html
// βββ assets/
// β βββ fonts/
// β βββ icons/
// βββ index.js
// Mengakses file statis:
// http://localhost:3000/css/style.css
// http://localhost:3000/js/app.js
// http://localhost:3000/images/logo.png
// http://localhost:3000/index.html
// Mengakses file di /assets:
// http://localhost:3000/assets/fonts/myfont.woff2
Serving HTML Page untuk SPA
// Untuk Single Page Application (React, Vue, dll.)
// Semua route yang tidak cocok dengan API akan mengirim index.html
app.use(express.static(path.join(__dirname, 'client/build')));
// Fallback ke index.html untuk client-side routing
app.get('*', (req, res) => {
// Hanya untuk route non-API
if (!req.url.startsWith('/api')) {
res.sendFile(path.join(__dirname, 'client/build', 'index.html'));
}
});
10. Quiz: Uji Pemahamanmu!
Setelah membaca tutorial di atas, jawablah 5 pertanyaan berikut untuk menguji pemahamanmu tentang Node.js dan Express: