Proyek Web: Membangun Galeri Foto Dinamis dengan API
Halo Sobat Jurnal Coding! Selamat datang di proyek penutup dari rangkaian artikel awal kita. Jika sebelumnya kamu sudah mahir membuat aplikasi pengingat waktu, daftar tugas, hingga kuis interaktif, kini kita akan melangkah ke level yang lebih menantang: berkomunikasi dengan dunia luar! Proyek ini bukan sekadar latihan biasa, melainkan sebuah gerbang menuju pemahaman yang lebih dalam tentang bagaimana aplikasi web modern benar-benar bekerja. Kita akan belajar bagaimana mengambil data dari internet secara langsung dan menampilkannya dengan cara yang menarik dan interaktif.
Pernahkah kamu bertanya-tanya bagaimana sebuah aplikasi seperti Instagram, Pinterest, atau bahkan Google Images bisa menampilkan ribuan bahkan jutaan foto tanpa harus menyimpannya satu per satu di perangkatmu? Rahasianya terletak pada teknologi yang disebut API (Application Programming Interface). Bayangkan API seperti seorang pelayan restoran. Kamu (aplikasi) duduk di meja dan memesan makanan (meminta data). Pelayan (API) lalu menyampaikan pesananmu ke dapur (server) dan mengantarkan makanan (data) yang kamu minta kembali ke mejamu. Proses ini terjadi dalam hitungan detik dan memungkinkan aplikasi untuk mendapatkan data terbaru kapan pun diperlukan, tanpa perlu menyimpan semuanya secara lokal.
Pada proyek terakhir ini, kita akan membuat sebuah Galeri Foto Dinamis. Alih-alih menuliskan daftar foto secara manual di kode HTML, kita akan menyuruh JavaScript untuk pergi ke internet, mengambil daftar foto terbaru dari penyedia layanan gratis, lalu menampilkannya secara otomatis di halaman website kita. Ini adalah kemampuan yang akan membuatmu merasa seperti penyihir digital! Dengan menguasai teknik ini, kamu tidak hanya bisa membuat galeri foto, tetapi juga aplikasi cuaca, berita terkini, atau bahkan dashboard analitik yang terhubung dengan berbagai sumber data.
Mengenal API dan Sumber Data
Sebelum kita mulai menulis kode, mari kita kenali lebih dekat dengan API yang akan kita gunakan. Dalam contoh ini, kita akan memanfaatkan API publik dari JSONPlaceholder. JSONPlaceholder adalah layanan gratis yang menyediakan data palsu (dummy data) untuk keperluan pengujian dan pengembangan. Data yang disediakan mencakup berbagai macam format seperti postingan blog, komentar, album, hingga foto-foto. Ini adalah tempat yang sempurna untuk belajar karena kita tidak perlu khawatir akan biaya atau batasan akses yang rumit.
API yang akan kita gunakan adalah endpoint `https://jsonplaceholder.typicode.com/photos`. Endpoint ini akan mengembalikan daftar foto dalam format JSON (JavaScript Object Notation). Format JSON sangat populer karena ringan, mudah dibaca oleh manusia, dan mudah diproses oleh mesin. Setiap foto dalam daftar tersebut memiliki properti seperti `albumId`, `id`, `title` (judul), `url` (tautan ke gambar ukuran besar), dan `thumbnailUrl` (tautan ke gambar versi mini). Dalam proyek ini, kita akan menampilkan gambar mini (thumbnail) beserta judul singkatnya.
Untuk memperkaya pemahamanmu, perlu diketahui bahwa ada banyak jenis API lain di luar sana. Ada API yang memerlukan kunci akses (API key) untuk digunakan, seperti API dari Google Maps atau Twitter. Ada pula API yang bersifat publik dan terbuka untuk siapa saja, seperti yang kita gunakan kali ini. Mempelajari cara kerja API akan membuka banyak peluang, karena hampir semua aplikasi modern, dari e-commerce hingga sistem perbankan, mengandalkan API untuk berkomunikasi antar layanan.
Langkah 1: Menyusun Kerangka Galeri (HTML)
Langkah pertama dalam membangun galeri foto dinamis adalah menyiapkan struktur HTML yang bersih dan terorganisir. Kita membutuhkan wadah yang tepat untuk menampilkan foto-foto tersebut. Dalam hal ini, kita akan membuat sebuah elemen `div` dengan ID khusus, misalnya `galeri-foto`. Elemen ini akan berfungsi sebagai kontainer utama yang nantinya akan diisi oleh JavaScript dengan gambar-gambar yang diambil dari internet.
Berikut adalah contoh kerangka HTML yang sederhana namun efektif:
<!DOCTYPE html>
<html lang="id">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Galeri Foto Dinamis</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<div class="container">
<h1>📸 Galeri Foto Dinamis</h1>
<p>Foto-foto di bawah ini diambil secara otomatis dari internet menggunakan API.</p>
<div id="galeri-foto" class="kotak-galeri">
<!-- Foto-foto akan muncul secara otomatis di sini -->
</div>
<button id="tombol-muat-ulang">🔄 Muat Ulang Foto</button>
</div>
<script src="script.js"></script>
</body>
</html>
Pada contoh di atas, kita juga menambahkan elemen `button` yang nantinya bisa digunakan untuk memuat ulang foto-foto tanpa perlu me-refresh halaman. Ini adalah contoh kecil bagaimana kita bisa membuat aplikasi yang lebih interaktif dan responsif. Selain itu, kita juga membungkus seluruh konten dalam sebuah `div` dengan kelas `container` untuk memudahkan pengaturan tata letak.
Langkah 2: Sentuhan Estetika Glassmorphism (CSS)
Setelah struktur HTML siap, langkah selanjutnya adalah memberikan sentuhan visual yang menarik. Salah satu tren desain yang populer saat ini adalah *glassmorphism* atau efek kaca. Efek ini memberikan tampilan yang modern, elegan, dan futuristik dengan memanfaatkan transparansi, blur, dan bayangan. Galeri foto akan terlihat sangat memukau jika kita menerapkan efek ini pada kartu-kartu foto.
Berikut adalah kode CSS yang akan kita gunakan untuk menciptakan tampilan yang memukau:
/* Reset dasar dan pengaturan body */
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
background: linear-gradient(135deg, #1a1a2e, #16213e, #0f3460);
min-height: 100vh;
display: flex;
align-items: center;
justify-content: center;
padding: 20px;
color: #E2E8F0;
}
.container {
max-width: 1200px;
width: 100%;
text-align: center;
}
h1 {
font-size: 2.5rem;
margin-bottom: 10px;
background: linear-gradient(to right, #00ffff, #ff00ff);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
}
p {
margin-bottom: 30px;
opacity: 0.8;
}
/* Gaya untuk galeri */
.kotak-galeri {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
gap: 20px;
padding: 20px;
margin-bottom: 30px;
}
/* Gaya untuk setiap kartu foto */
.kartu-foto {
background: rgba(255, 255, 255, 0.05);
border-radius: 16px;
padding: 15px;
border: 1px solid rgba(255, 255, 255, 0.1);
backdrop-filter: blur(10px);
-webkit-backdrop-filter: blur(10px);
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3);
transition: transform 0.3s ease, box-shadow 0.3s ease;
}
.kartu-foto:hover {
transform: translateY(-10px);
box-shadow: 0 12px 40px rgba(0, 0, 0, 0.5);
border-color: rgba(255, 255, 255, 0.3);
}
.kartu-foto img {
width: 100%;
border-radius: 12px;
aspect-ratio: 1 / 1;
object-fit: cover;
display: block;
}
.kartu-foto p {
margin-top: 12px;
font-size: 0.9rem;
text-align: center;
opacity: 0.9;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
padding: 0 5px;
}
/* Gaya untuk tombol */
#tombol-muat-ulang {
background: rgba(255, 255, 255, 0.1);
border: 1px solid rgba(255, 255, 255, 0.2);
color: white;
padding: 12px 30px;
border-radius: 30px;
font-size: 1rem;
cursor: pointer;
backdrop-filter: blur(5px);
transition: all 0.3s ease;
}
#tombol-muat-ulang:hover {
background: rgba(255, 255, 255, 0.2);
transform: scale(1.05);
box-shadow: 0 0 20px rgba(0, 255, 255, 0.3);
}
Pada kode CSS di atas, kita menggunakan beberapa teknik penting. Pertama, `display: grid` dengan `grid-template-columns: repeat(auto-fit, minmax(250px, 1fr))` memastikan bahwa galeri kita responsif. Jumlah kolom akan menyesuaikan secara otomatis dengan lebar layar, sehingga tampilan tetap rapi baik di desktop, tablet, maupun ponsel. Kedua, efek *glassmorphism* dicapai dengan `background: rgba(255, 255, 255, 0.05)`, `backdrop-filter: blur(10px)`, dan `border: 1px solid rgba(255, 255, 255, 0.1)`. Ketiga, kita menambahkan efek hover yang halus untuk meningkatkan interaktivitas.
Langkah 3: Sihir API dengan JavaScript
Sekarang tibalah pada bagian yang paling seru dan paling dinanti-nantikan! Kita akan menulis kode JavaScript yang akan menghubungkan aplikasi kita dengan API, mengambil data foto, dan menampilkannya di halaman. Kita akan menggunakan fungsi bawaan bernama `fetch()` yang merupakan cara modern dan standar untuk melakukan permintaan HTTP di JavaScript.
Berikut adalah kode JavaScript lengkap yang akan kita gunakan, lengkap dengan penjelasan setiap bagiannya:
// 1. Menangkap elemen wadah galeri dan tombol
const wadahGaleri = document.getElementById("galeri-foto");
const tombolMuatUlang = document.getElementById("tombol-muat-ulang");
// 2. Fungsi untuk mengambil dan menampilkan foto
function ambilDanTampilkanFoto() {
// Tampilkan pesan loading saat proses pengambilan data
wadahGaleri.innerHTML = '
// 3. Mengambil data dari API publik
fetch("https://jsonplaceholder.typicode.com/photos?_limit=12")
.then(response => {
// Periksa apakah respons berhasil (status 200-299)
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
return response.json(); // Ubah respons menjadi objek JavaScript
})
.then(data => {
// Kosongkan wadah galeri sebelum menambahkan foto baru
wadahGaleri.innerHTML = '';
// 4. Loop melalui setiap item data dan buat elemen kartu
data.forEach(item => {
// Buat elemen div untuk kartu foto
const kartu = document.createElement("div");
kartu.className = "kartu-foto";
// Buat elemen gambar
const gambar = document.createElement("img");
gambar.src = item.thumbnailUrl; // Gunakan thumbnailUrl untuk gambar mini
gambar.alt = item.title; // Teks alternatif untuk aksesibilitas
// Buat elemen paragraf untuk judul
const judul = document.createElement("p");
// Potong judul jika terlalu panjang
judul.textContent = item.title.length > 25 ? item.title.substring(0, 25) + "..." : item.title;
// Tambahkan gambar dan judul ke dalam kartu
kartu.appendChild(gambar);
kartu.appendChild(judul);
// Tambahkan kartu ke dalam wadah galeri
wadahGaleri.appendChild(kartu);
});
// Tampilkan pesan sukses jika foto berhasil dimuat
console.log(`Berhasil memuat ${data.length} foto!`);
})
.catch(error => {
// 5. Tangani error jika terjadi masalah
console.error("Terjadi kesalahan:", error);
wadahGaleri.innerHTML = `
`;
});
}
// 6. Panggil fungsi pertama kali saat halaman dimuat
ambilDanTampilkanFoto();
// 7. Tambahkan event listener pada tombol untuk memuat ulang
tombolMuatUlang.addEventListener("click", ambilDanTampilkanFoto);
Mari kita bedah kode di atas secara lebih mendalam:
- **Fungsi `fetch()`**: Ini adalah inti dari seluruh operasi. `fetch()` menerima URL endpoint API sebagai argumen dan mengembalikan sebuah *Promise*. Promise adalah objek yang merepresentasikan operasi asinkron yang akan selesai di masa depan. Ini memungkinkan kita untuk menangani operasi yang memakan waktu (seperti permintaan jaringan) tanpa memblokir eksekusi kode lainnya.
- **`.then(response => response.json())`**: Setelah `fetch()` selesai, kita mendapatkan objek `Response`. Kita perlu mengubahnya menjadi format JSON yang bisa kita gunakan. Metode `.json()` juga mengembalikan Promise, sehingga kita perlu menambahkan `.then()` lagi.
- **`.then(data => { ... })`**: Di sini kita menerima data yang sudah diubah menjadi objek JavaScript. Data ini berupa array yang berisi objek-objek foto. Kita kemudian melakukan iterasi (loop) menggunakan `forEach()` untuk membuat elemen HTML baru untuk setiap foto.
- **`document.createElement()`**: Ini adalah cara dinamis untuk membuat elemen HTML dari JavaScript. Kita membuat `div` untuk kartu, `img` untuk gambar, dan `p` untuk judul. Ini jauh lebih fleksibel dan aman daripada menulis string HTML secara manual.
- **`appendChild()`**: Metode ini digunakan untuk menambahkan elemen anak ke dalam elemen induk. Kita menambahkan gambar dan judul ke kartu, lalu kartu ke wadah galeri.
- **Penanganan Error (`catch`)**: Jaringan internet tidak selalu stabil. API bisa saja sedang down, atau ada masalah lain. Dengan `catch`, kita bisa menangani error dengan anggun dan menampilkan pesan yang ramah kepada pengguna, bukan hanya membiarkan aplikasi mogok.
- **Event Listener**: Kita menambahkan fungsi `ambilDanTampilkanFoto` sebagai event listener untuk tombol "Muat Ulang". Setiap kali tombol diklik, fungsi akan dijalankan lagi, mengambil data terbaru dari API.
Memahami Konsep Asinkronus dan Promise
Bagi pemula, konsep asinkronus dan Promise mungkin terasa membingungkan. Namun, pemahaman tentang ini sangat penting dalam pengembangan web modern. Mari kita sederhanakan: JavaScript secara default berjalan secara sinkronus, artinya kode dieksekusi baris per baris secara berurutan. Namun, ketika kita melakukan permintaan ke server (seperti mengambil data dari API), kita tidak tahu berapa lama waktu yang dibutuhkan. Jika kita menunggu respons sebelum melanjutkan eksekusi kode, aplikasi kita akan terasa "lag" atau bahkan freeze.
Di sinilah Promise dan `async/await` berperan. Promise memungkinkan kita untuk "berjanji" bahwa kita akan melakukan sesuatu ketika operasi selesai, baik itu berhasil maupun gagal. Kita bisa menggunakan `.then()` untuk menangani keberhasilan dan `.catch()` untuk menangani kegagalan.
Sebagai alternatif, kita juga bisa menggunakan sintaks `async/await` yang membuat kode asinkronus terlihat lebih seperti kode sinkronus. Berikut adalah contoh bagaimana kita bisa menulis ulang fungsi kita dengan `async/await`:
async function ambilDanTampilkanFoto() {
try {
wadahGaleri.innerHTML = '
const response = await fetch("https://jsonplaceholder.typicode.com/photos?_limit=12");
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const data = await response.json();
wadahGaleri.innerHTML = '';
data.forEach(item => {
const kartu = document.createElement("div");
kartu.className = "kartu-foto";
kartu.innerHTML = `

`;
wadahGaleri.appendChild(kartu);
});
} catch (error) {
console.error("Terjadi kesalahan:", error);
wadahGaleri.innerHTML = `
}
}
Kedua pendekatan (Promise dengan `.then()` dan `async/await`) sama-sama valid. Pilihlah yang paling nyaman dan mudah dipahami olehmu.
Memperkaya Proyek: Fitur Tambahan
Proyek dasar ini sudah sangat keren, tetapi kita bisa membuatnya lebih hebat lagi dengan menambahkan beberapa fitur tambahan:
1. **Pencarian Foto**: Tambahkan kotak input dan tombol pencarian. Ketika pengguna mengetikkan kata kunci, kita bisa memfilter foto-foto yang judulnya mengandung kata kunci tersebut. Ini bisa dilakukan dengan mudah menggunakan metode `filter()` pada array data.
2. **Paginasi**: Daripada menampilkan semua foto sekaligus, kita bisa menampilkan foto dalam beberapa halaman. Kita bisa menambahkan tombol "Sebelumnya" dan "Selanjutnya" untuk navigasi antar halaman. Parameter `_page` dan `_limit` pada URL API memungkinkan kita untuk mengontrol data yang diambil.
3. **Mode Gelap/Terang**: Kita bisa menambahkan tombol toggle untuk mengganti tema antara mode terang dan gelap. Ini bisa dilakukan dengan mengubah kelas pada elemen `body` dan menyesuaikan gaya CSS.
4. **Animasi Loading**: Alih-alih hanya teks "Sedang memuat...", kita bisa menambahkan animasi spinner atau skeleton loading yang lebih menarik secara visual.
5. **Penyimpanan Cache**: Kita bisa menyimpan data foto di `localStorage` sehingga jika pengguna membuka halaman lagi, foto-foto bisa langsung ditampilkan tanpa harus menunggu permintaan API lagi. Ini akan meningkatkan kecepatan dan pengalaman pengguna.
Kesimpulan Proyek dan Perjalanan Belajar
Selamat! Kamu baru saja menyelesaikan proyek tingkat lanjut yang menghubungkan aplikasimu dengan sumber data eksternal. Dengan memahami bagaimana `fetch()` bekerja dan bagaimana menangani data dari API, kamu kini bisa membuat website yang datanya selalu segar dan otomatis diperbarui setiap kali ada data baru di internet. Kamu tidak lagi terbatas pada konten statis, tetapi bisa menciptakan aplikasi yang hidup dan dinamis.
Setiap proyek mengajarkan konsep-konsep penting dalam pengembangan web, mulai dari manipulasi DOM, event handling, penyimpanan data, hingga komunikasi dengan server. Jangan berhenti di sini! Teruslah bereksperimen, tambahkan fitur-fitur baru, dan jadikan blog 'Jurnal Coding' ini sebagai saksi perjalanan hebatmu menjadi seorang Software Engineer masa depan.
Ingatlah bahwa dunia pemrograman adalah dunia yang terus berkembang. Selalu ada hal baru untuk dipelajari. API, misalnya, memiliki banyak variasi seperti REST API, GraphQL, dan WebSocket. Masing-masing memiliki kegunaan dan kelebihannya sendiri. Teruslah belajar, teruslah berkarya, dan jangan pernah takut untuk mencoba hal-hal baru.
Sampai jumpa di petualangan berikutnya! Tetap semangat dan selamat mengoding! 🚀
Pernahkah kamu bertanya-tanya bagaimana sebuah aplikasi seperti Instagram, Pinterest, atau bahkan Google Images bisa menampilkan ribuan bahkan jutaan foto tanpa harus menyimpannya satu per satu di perangkatmu? Rahasianya terletak pada teknologi yang disebut API (Application Programming Interface). Bayangkan API seperti seorang pelayan restoran. Kamu (aplikasi) duduk di meja dan memesan makanan (meminta data). Pelayan (API) lalu menyampaikan pesananmu ke dapur (server) dan mengantarkan makanan (data) yang kamu minta kembali ke mejamu. Proses ini terjadi dalam hitungan detik dan memungkinkan aplikasi untuk mendapatkan data terbaru kapan pun diperlukan, tanpa perlu menyimpan semuanya secara lokal.
Pada proyek terakhir ini, kita akan membuat sebuah Galeri Foto Dinamis. Alih-alih menuliskan daftar foto secara manual di kode HTML, kita akan menyuruh JavaScript untuk pergi ke internet, mengambil daftar foto terbaru dari penyedia layanan gratis, lalu menampilkannya secara otomatis di halaman website kita. Ini adalah kemampuan yang akan membuatmu merasa seperti penyihir digital! Dengan menguasai teknik ini, kamu tidak hanya bisa membuat galeri foto, tetapi juga aplikasi cuaca, berita terkini, atau bahkan dashboard analitik yang terhubung dengan berbagai sumber data.
Mengenal API dan Sumber Data
Sebelum kita mulai menulis kode, mari kita kenali lebih dekat dengan API yang akan kita gunakan. Dalam contoh ini, kita akan memanfaatkan API publik dari JSONPlaceholder. JSONPlaceholder adalah layanan gratis yang menyediakan data palsu (dummy data) untuk keperluan pengujian dan pengembangan. Data yang disediakan mencakup berbagai macam format seperti postingan blog, komentar, album, hingga foto-foto. Ini adalah tempat yang sempurna untuk belajar karena kita tidak perlu khawatir akan biaya atau batasan akses yang rumit.
API yang akan kita gunakan adalah endpoint `https://jsonplaceholder.typicode.com/photos`. Endpoint ini akan mengembalikan daftar foto dalam format JSON (JavaScript Object Notation). Format JSON sangat populer karena ringan, mudah dibaca oleh manusia, dan mudah diproses oleh mesin. Setiap foto dalam daftar tersebut memiliki properti seperti `albumId`, `id`, `title` (judul), `url` (tautan ke gambar ukuran besar), dan `thumbnailUrl` (tautan ke gambar versi mini). Dalam proyek ini, kita akan menampilkan gambar mini (thumbnail) beserta judul singkatnya.
Untuk memperkaya pemahamanmu, perlu diketahui bahwa ada banyak jenis API lain di luar sana. Ada API yang memerlukan kunci akses (API key) untuk digunakan, seperti API dari Google Maps atau Twitter. Ada pula API yang bersifat publik dan terbuka untuk siapa saja, seperti yang kita gunakan kali ini. Mempelajari cara kerja API akan membuka banyak peluang, karena hampir semua aplikasi modern, dari e-commerce hingga sistem perbankan, mengandalkan API untuk berkomunikasi antar layanan.
Langkah 1: Menyusun Kerangka Galeri (HTML)
Langkah pertama dalam membangun galeri foto dinamis adalah menyiapkan struktur HTML yang bersih dan terorganisir. Kita membutuhkan wadah yang tepat untuk menampilkan foto-foto tersebut. Dalam hal ini, kita akan membuat sebuah elemen `div` dengan ID khusus, misalnya `galeri-foto`. Elemen ini akan berfungsi sebagai kontainer utama yang nantinya akan diisi oleh JavaScript dengan gambar-gambar yang diambil dari internet.
Berikut adalah contoh kerangka HTML yang sederhana namun efektif:
<!DOCTYPE html>
<html lang="id">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Galeri Foto Dinamis</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<div class="container">
<h1>📸 Galeri Foto Dinamis</h1>
<p>Foto-foto di bawah ini diambil secara otomatis dari internet menggunakan API.</p>
<div id="galeri-foto" class="kotak-galeri">
<!-- Foto-foto akan muncul secara otomatis di sini -->
</div>
<button id="tombol-muat-ulang">🔄 Muat Ulang Foto</button>
</div>
<script src="script.js"></script>
</body>
</html>
Pada contoh di atas, kita juga menambahkan elemen `button` yang nantinya bisa digunakan untuk memuat ulang foto-foto tanpa perlu me-refresh halaman. Ini adalah contoh kecil bagaimana kita bisa membuat aplikasi yang lebih interaktif dan responsif. Selain itu, kita juga membungkus seluruh konten dalam sebuah `div` dengan kelas `container` untuk memudahkan pengaturan tata letak.
Langkah 2: Sentuhan Estetika Glassmorphism (CSS)
Setelah struktur HTML siap, langkah selanjutnya adalah memberikan sentuhan visual yang menarik. Salah satu tren desain yang populer saat ini adalah *glassmorphism* atau efek kaca. Efek ini memberikan tampilan yang modern, elegan, dan futuristik dengan memanfaatkan transparansi, blur, dan bayangan. Galeri foto akan terlihat sangat memukau jika kita menerapkan efek ini pada kartu-kartu foto.
Berikut adalah kode CSS yang akan kita gunakan untuk menciptakan tampilan yang memukau:
/* Reset dasar dan pengaturan body */
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
background: linear-gradient(135deg, #1a1a2e, #16213e, #0f3460);
min-height: 100vh;
display: flex;
align-items: center;
justify-content: center;
padding: 20px;
color: #E2E8F0;
}
.container {
max-width: 1200px;
width: 100%;
text-align: center;
}
h1 {
font-size: 2.5rem;
margin-bottom: 10px;
background: linear-gradient(to right, #00ffff, #ff00ff);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
}
p {
margin-bottom: 30px;
opacity: 0.8;
}
/* Gaya untuk galeri */
.kotak-galeri {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
gap: 20px;
padding: 20px;
margin-bottom: 30px;
}
/* Gaya untuk setiap kartu foto */
.kartu-foto {
background: rgba(255, 255, 255, 0.05);
border-radius: 16px;
padding: 15px;
border: 1px solid rgba(255, 255, 255, 0.1);
backdrop-filter: blur(10px);
-webkit-backdrop-filter: blur(10px);
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3);
transition: transform 0.3s ease, box-shadow 0.3s ease;
}
.kartu-foto:hover {
transform: translateY(-10px);
box-shadow: 0 12px 40px rgba(0, 0, 0, 0.5);
border-color: rgba(255, 255, 255, 0.3);
}
.kartu-foto img {
width: 100%;
border-radius: 12px;
aspect-ratio: 1 / 1;
object-fit: cover;
display: block;
}
.kartu-foto p {
margin-top: 12px;
font-size: 0.9rem;
text-align: center;
opacity: 0.9;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
padding: 0 5px;
}
/* Gaya untuk tombol */
#tombol-muat-ulang {
background: rgba(255, 255, 255, 0.1);
border: 1px solid rgba(255, 255, 255, 0.2);
color: white;
padding: 12px 30px;
border-radius: 30px;
font-size: 1rem;
cursor: pointer;
backdrop-filter: blur(5px);
transition: all 0.3s ease;
}
#tombol-muat-ulang:hover {
background: rgba(255, 255, 255, 0.2);
transform: scale(1.05);
box-shadow: 0 0 20px rgba(0, 255, 255, 0.3);
}
Pada kode CSS di atas, kita menggunakan beberapa teknik penting. Pertama, `display: grid` dengan `grid-template-columns: repeat(auto-fit, minmax(250px, 1fr))` memastikan bahwa galeri kita responsif. Jumlah kolom akan menyesuaikan secara otomatis dengan lebar layar, sehingga tampilan tetap rapi baik di desktop, tablet, maupun ponsel. Kedua, efek *glassmorphism* dicapai dengan `background: rgba(255, 255, 255, 0.05)`, `backdrop-filter: blur(10px)`, dan `border: 1px solid rgba(255, 255, 255, 0.1)`. Ketiga, kita menambahkan efek hover yang halus untuk meningkatkan interaktivitas.
Langkah 3: Sihir API dengan JavaScript
Sekarang tibalah pada bagian yang paling seru dan paling dinanti-nantikan! Kita akan menulis kode JavaScript yang akan menghubungkan aplikasi kita dengan API, mengambil data foto, dan menampilkannya di halaman. Kita akan menggunakan fungsi bawaan bernama `fetch()` yang merupakan cara modern dan standar untuk melakukan permintaan HTTP di JavaScript.
Berikut adalah kode JavaScript lengkap yang akan kita gunakan, lengkap dengan penjelasan setiap bagiannya:
// 1. Menangkap elemen wadah galeri dan tombol
const wadahGaleri = document.getElementById("galeri-foto");
const tombolMuatUlang = document.getElementById("tombol-muat-ulang");
// 2. Fungsi untuk mengambil dan menampilkan foto
function ambilDanTampilkanFoto() {
// Tampilkan pesan loading saat proses pengambilan data
wadahGaleri.innerHTML = '
⏳ Sedang memuat foto-foto terbaru...
';// 3. Mengambil data dari API publik
fetch("https://jsonplaceholder.typicode.com/photos?_limit=12")
.then(response => {
// Periksa apakah respons berhasil (status 200-299)
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
return response.json(); // Ubah respons menjadi objek JavaScript
})
.then(data => {
// Kosongkan wadah galeri sebelum menambahkan foto baru
wadahGaleri.innerHTML = '';
// 4. Loop melalui setiap item data dan buat elemen kartu
data.forEach(item => {
// Buat elemen div untuk kartu foto
const kartu = document.createElement("div");
kartu.className = "kartu-foto";
// Buat elemen gambar
const gambar = document.createElement("img");
gambar.src = item.thumbnailUrl; // Gunakan thumbnailUrl untuk gambar mini
gambar.alt = item.title; // Teks alternatif untuk aksesibilitas
// Buat elemen paragraf untuk judul
const judul = document.createElement("p");
// Potong judul jika terlalu panjang
judul.textContent = item.title.length > 25 ? item.title.substring(0, 25) + "..." : item.title;
// Tambahkan gambar dan judul ke dalam kartu
kartu.appendChild(gambar);
kartu.appendChild(judul);
// Tambahkan kartu ke dalam wadah galeri
wadahGaleri.appendChild(kartu);
});
// Tampilkan pesan sukses jika foto berhasil dimuat
console.log(`Berhasil memuat ${data.length} foto!`);
})
.catch(error => {
// 5. Tangani error jika terjadi masalah
console.error("Terjadi kesalahan:", error);
wadahGaleri.innerHTML = `
❌ Gagal memuat foto. Silakan coba lagi nanti.
Detail: ${error.message}
`;
});
}
// 6. Panggil fungsi pertama kali saat halaman dimuat
ambilDanTampilkanFoto();
// 7. Tambahkan event listener pada tombol untuk memuat ulang
tombolMuatUlang.addEventListener("click", ambilDanTampilkanFoto);
Mari kita bedah kode di atas secara lebih mendalam:
- **Fungsi `fetch()`**: Ini adalah inti dari seluruh operasi. `fetch()` menerima URL endpoint API sebagai argumen dan mengembalikan sebuah *Promise*. Promise adalah objek yang merepresentasikan operasi asinkron yang akan selesai di masa depan. Ini memungkinkan kita untuk menangani operasi yang memakan waktu (seperti permintaan jaringan) tanpa memblokir eksekusi kode lainnya.
- **`.then(response => response.json())`**: Setelah `fetch()` selesai, kita mendapatkan objek `Response`. Kita perlu mengubahnya menjadi format JSON yang bisa kita gunakan. Metode `.json()` juga mengembalikan Promise, sehingga kita perlu menambahkan `.then()` lagi.
- **`.then(data => { ... })`**: Di sini kita menerima data yang sudah diubah menjadi objek JavaScript. Data ini berupa array yang berisi objek-objek foto. Kita kemudian melakukan iterasi (loop) menggunakan `forEach()` untuk membuat elemen HTML baru untuk setiap foto.
- **`document.createElement()`**: Ini adalah cara dinamis untuk membuat elemen HTML dari JavaScript. Kita membuat `div` untuk kartu, `img` untuk gambar, dan `p` untuk judul. Ini jauh lebih fleksibel dan aman daripada menulis string HTML secara manual.
- **`appendChild()`**: Metode ini digunakan untuk menambahkan elemen anak ke dalam elemen induk. Kita menambahkan gambar dan judul ke kartu, lalu kartu ke wadah galeri.
- **Penanganan Error (`catch`)**: Jaringan internet tidak selalu stabil. API bisa saja sedang down, atau ada masalah lain. Dengan `catch`, kita bisa menangani error dengan anggun dan menampilkan pesan yang ramah kepada pengguna, bukan hanya membiarkan aplikasi mogok.
- **Event Listener**: Kita menambahkan fungsi `ambilDanTampilkanFoto` sebagai event listener untuk tombol "Muat Ulang". Setiap kali tombol diklik, fungsi akan dijalankan lagi, mengambil data terbaru dari API.
Memahami Konsep Asinkronus dan Promise
Bagi pemula, konsep asinkronus dan Promise mungkin terasa membingungkan. Namun, pemahaman tentang ini sangat penting dalam pengembangan web modern. Mari kita sederhanakan: JavaScript secara default berjalan secara sinkronus, artinya kode dieksekusi baris per baris secara berurutan. Namun, ketika kita melakukan permintaan ke server (seperti mengambil data dari API), kita tidak tahu berapa lama waktu yang dibutuhkan. Jika kita menunggu respons sebelum melanjutkan eksekusi kode, aplikasi kita akan terasa "lag" atau bahkan freeze.
Di sinilah Promise dan `async/await` berperan. Promise memungkinkan kita untuk "berjanji" bahwa kita akan melakukan sesuatu ketika operasi selesai, baik itu berhasil maupun gagal. Kita bisa menggunakan `.then()` untuk menangani keberhasilan dan `.catch()` untuk menangani kegagalan.
Sebagai alternatif, kita juga bisa menggunakan sintaks `async/await` yang membuat kode asinkronus terlihat lebih seperti kode sinkronus. Berikut adalah contoh bagaimana kita bisa menulis ulang fungsi kita dengan `async/await`:
async function ambilDanTampilkanFoto() {
try {
wadahGaleri.innerHTML = '
⏳ Sedang memuat...
';const response = await fetch("https://jsonplaceholder.typicode.com/photos?_limit=12");
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const data = await response.json();
wadahGaleri.innerHTML = '';
data.forEach(item => {
const kartu = document.createElement("div");
kartu.className = "kartu-foto";
kartu.innerHTML = `
${item.title.length > 25 ? item.title.substring(0, 25) + "..." : item.title}
`;
wadahGaleri.appendChild(kartu);
});
} catch (error) {
console.error("Terjadi kesalahan:", error);
wadahGaleri.innerHTML = `
Gagal memuat foto: ${error.message}
`;}
}
Kedua pendekatan (Promise dengan `.then()` dan `async/await`) sama-sama valid. Pilihlah yang paling nyaman dan mudah dipahami olehmu.
Memperkaya Proyek: Fitur Tambahan
Proyek dasar ini sudah sangat keren, tetapi kita bisa membuatnya lebih hebat lagi dengan menambahkan beberapa fitur tambahan:
1. **Pencarian Foto**: Tambahkan kotak input dan tombol pencarian. Ketika pengguna mengetikkan kata kunci, kita bisa memfilter foto-foto yang judulnya mengandung kata kunci tersebut. Ini bisa dilakukan dengan mudah menggunakan metode `filter()` pada array data.
2. **Paginasi**: Daripada menampilkan semua foto sekaligus, kita bisa menampilkan foto dalam beberapa halaman. Kita bisa menambahkan tombol "Sebelumnya" dan "Selanjutnya" untuk navigasi antar halaman. Parameter `_page` dan `_limit` pada URL API memungkinkan kita untuk mengontrol data yang diambil.
3. **Mode Gelap/Terang**: Kita bisa menambahkan tombol toggle untuk mengganti tema antara mode terang dan gelap. Ini bisa dilakukan dengan mengubah kelas pada elemen `body` dan menyesuaikan gaya CSS.
4. **Animasi Loading**: Alih-alih hanya teks "Sedang memuat...", kita bisa menambahkan animasi spinner atau skeleton loading yang lebih menarik secara visual.
5. **Penyimpanan Cache**: Kita bisa menyimpan data foto di `localStorage` sehingga jika pengguna membuka halaman lagi, foto-foto bisa langsung ditampilkan tanpa harus menunggu permintaan API lagi. Ini akan meningkatkan kecepatan dan pengalaman pengguna.
Kesimpulan Proyek dan Perjalanan Belajar
Selamat! Kamu baru saja menyelesaikan proyek tingkat lanjut yang menghubungkan aplikasimu dengan sumber data eksternal. Dengan memahami bagaimana `fetch()` bekerja dan bagaimana menangani data dari API, kamu kini bisa membuat website yang datanya selalu segar dan otomatis diperbarui setiap kali ada data baru di internet. Kamu tidak lagi terbatas pada konten statis, tetapi bisa menciptakan aplikasi yang hidup dan dinamis.
Setiap proyek mengajarkan konsep-konsep penting dalam pengembangan web, mulai dari manipulasi DOM, event handling, penyimpanan data, hingga komunikasi dengan server. Jangan berhenti di sini! Teruslah bereksperimen, tambahkan fitur-fitur baru, dan jadikan blog 'Jurnal Coding' ini sebagai saksi perjalanan hebatmu menjadi seorang Software Engineer masa depan.
Ingatlah bahwa dunia pemrograman adalah dunia yang terus berkembang. Selalu ada hal baru untuk dipelajari. API, misalnya, memiliki banyak variasi seperti REST API, GraphQL, dan WebSocket. Masing-masing memiliki kegunaan dan kelebihannya sendiri. Teruslah belajar, teruslah berkarya, dan jangan pernah takut untuk mencoba hal-hal baru.
Sampai jumpa di petualangan berikutnya! Tetap semangat dan selamat mengoding! 🚀