Tutorial Membuat Aplikasi Prediksi Cuaca dengan API Gratis (Tanpa API Key) Menggunakan HTML, Bootstrap & JavaScript
Admin
Penulis Artikel
Tutorial Membuat Aplikasi Prediksi Cuaca dengan API Gratis (Tanpa API Key) Menggunakan HTML, Bootstrap & JavaScript
Membangun aplikasi cuaca adalah salah satu proyek portofolio terbaik bagi pengembang web pemula. Proyek ini melatih kemampuan kita dalam melakukan HTTP Request, memanipulasi DOM (Document Object Model), dan merender antarmuka pengguna yang dinamis.
Namun, banyak API cuaca (seperti OpenWeatherMap) mengharuskan kita mendaftar dan menggunakan API Key, yang kadang merepotkan. Dalam tutorial ini, kita akan membuat Aplikasi Prakiraan Cuaca 5 Hari menggunakan Open-Meteo API. Layanan ini 100% gratis untuk penggunaan non-komersial dan tidak membutuhkan API Key sama sekali!
Persiapan dan Alat
Kamu tidak perlu menginstal backend rumit atau framework berat. Cukup siapkan:
Teks Editor (VS Code, Sublime Text, atau Notepad).
Browser web modern (Chrome, Firefox, Safari).
Koneksi internet aktif.
Alur Kerja Aplikasi
Sebelum masuk ke kode, mari kita pahami logika cara kerja aplikasi kita:
Input Pengguna: Pengguna memasukkan nama kota melalui kolom pencarian.
Geocoding API: JavaScript mengirim nama kota ke server Open-Meteo untuk mencari titik koordinatnya (Latitude & Longitude).
Forecast API: Setelah koordinat didapat, JavaScript melakukan permintaan kedua ke server untuk meminta data cuaca 5 hari ke depan di koordinat tersebut.
Render HTML: Data yang diterima dalam format JSON akan diubah menjadi kartu-kartu visual menggunakan kelas styling dari Bootstrap 5.
Penjelasan Inti Kode JavaScript
Kita akan menggunakan fungsi Asynchronous (async/await) agar aplikasi tidak freeze atau membeku saat menunggu balasan dari server. Berikut adalah bedah kode intinya:
1. Mengubah Nama Kota Menjadi Koordinat (Geocoding)
API cuaca umumnya tidak mengerti nama kota secara langsung; mereka bekerja dengan koordinat. Oleh karena itu, kita harus mengonversi input pengguna (misal: "Jakarta") menjadi koordinat.
JavaScript
// Memanggil Geocoding API
const geoResponse = await fetch(`https://geocoding-api.open-meteo.com/v1/search?name=${encodeURIComponent(city)}&count=1&language=id`);
const geoData = await geoResponse.json();
// Mengambil data kota pertama yang paling relevan
const location = geoData.results[0];
Penjelasan: Fungsi
fetch()bertugas menghubungi URL server.encodeURIComponent(city)memastikan spasi atau karakter khusus pada nama kota diubah menjadi format URL yang valid. Hasilnya (geoData) akan memberikan array objek berisi lintang (latitude) dan bujur (longitude).
2. Mengambil Data Cuaca (Forecast API)
Setelah memiliki koordinat, kita bisa menanyakan cuaca di titik tersebut kepada server.
JavaScript
// Meminta cuaca berdasarkan latitude & longitude
const weatherResponse = await fetch(`https://api.open-meteo.com/v1/forecast?latitude=${location.latitude}&longitude=${location.longitude}&daily=weathercode,temperature_2m_max,temperature_2m_min&timezone=auto`);
const weatherData = await weatherResponse.json();
Penjelasan: Parameter
daily=menentukan spesifik data apa yang kita minta (kode cuaca, suhu maksimal, dan suhu minimal). Parametertimezone=automemastikan perhitungan hari disesuaikan dengan zona waktu lokal kota tersebut.
3. Menerjemahkan "Weather Code"
Open-Meteo tidak mengembalikan teks "Hujan" atau "Cerah", melainkan mengembalikan angka yang disebut WMO Code. Misalnya, angka 0 berarti cerah, dan angka 61 berarti hujan ringan. Kita harus membuat fungsi bantuan untuk menerjemahkannya.
JavaScript
function getWeatherDescription(code) {
if (code === 0) return { desc: 'Cerah', emoji: '☀️' };
if (code >= 61 && code <= 67) return { desc: 'Hujan', emoji: '🌧️' };
if (code >= 95) return { desc: 'Badai Petir', emoji: '⚡' };
// ... kondisi lainnya
}
Penjelasan: Dengan memisahkan logika ini ke dalam fungsi tersendiri (
getWeatherDescription), kode utama kita tetap bersih. Fungsi ini mengembalikan objek berisi teks deskripsi dan emoji visual, sehingga kita tidak perlu repot mencari dan memuat aset gambar dari luar.
4. Menampilkan ke Layar (DOM Manipulation)
Setelah semua data terkumpul, kita melakukan pengulangan (looping) maksimal 5 kali untuk merakit kode HTML dan menampilkannya di halaman.
JavaScript
let cardsHtml = '';
for (let i = 0; i < 5; i++) {
const maxTemp = weatherData.daily.temperature_2m_max[i];
const minTemp = weatherData.daily.temperature_2m_min[i];
// Memasukkan data ke dalam template literal HTML
cardsHtml += `
<div class="col-lg-2">
<div class="card">
<h4>${maxTemp}°C</h4>
<p>Min: ${minTemp}°C</p>
</div>
</div>`;
}
// Menyuntikkan HTML yang sudah dirakit ke dalam container
document.getElementById('forecastContainer').innerHTML = cardsHtml;
Penjelasan: Kita mengekstrak data dari array
weatherData.dailyberdasarkan indeksnya ([i]). Data ini dimasukkan ke dalam kerangka Bootstrap menggunakan Template Literals (tanda backtick ****). Terakhir, metode.innerHTML` menempelkan semua elemen kartu tersebut ke dalam halaman HTML.
Kode Lengkap & Preview Interaktif
Bagi kamu yang ingin langsung mempraktikkannya, berikut adalah keseluruhan kode HTML, CSS, dan JavaScript yang sudah digabungkan ke dalam satu file. Kamu cukup menyalinnya dan menyimpannya sebagai file index.html.
HTML
<!DOCTYPE html>
<html lang="id">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Prakiraan Cuaca 5 Hari (Tanpa API Key)</title>
<!-- Menggunakan Bootstrap 5 via CDN -->
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
<style>
body { background-color: #f4f7f6; }
.weather-icon { font-size: 3rem; }
</style>
</head>
<body>
<div class="container py-5">
<div class="row justify-content-center">
<div class="col-md-8 text-center">
<h2 class="mb-4 text-primary">🌤️ Info Cuaca Nusantara</h2>
<!-- Kolom Pencarian -->
<div class="input-group mb-4 shadow-sm">
<input type="text" id="cityInput" class="form-control form-control-lg" placeholder="Masukkan nama kota (Misal: Salatiga, Jakarta, Bali...)" aria-label="Nama Kota">
<button class="btn btn-primary btn-lg" type="button" onclick="searchWeather()">Cari Cuaca</button>
</div>
<!-- Pesan Loading & Error -->
<div id="loading" class="spinner-border text-primary d-none mb-3" role="status">
<span class="visually-hidden">Loading...</span>
</div>
<div id="errorMsg" class="text-danger mb-3 fw-bold"></div>
<!-- Nama Kota yang Ditemukan -->
<h4 id="cityName" class="mb-4 text-secondary"></h4>
</div>
</div>
<!-- Container Hasil Prakiraan 5 Hari -->
<div class="row justify-content-center" id="forecastContainer">
<!-- Kartu cuaca akan dimunculkan di sini oleh JavaScript -->
</div>
</div>
<script>
// Fungsi utama untuk mencari cuaca
async function searchWeather() {
const city = document.getElementById('cityInput').value.trim();
const errorMsg = document.getElementById('errorMsg');
const cityName = document.getElementById('cityName');
const forecastContainer = document.getElementById('forecastContainer');
const loading = document.getElementById('loading');
// Reset tampilan
errorMsg.innerText = '';
cityName.innerText = '';
forecastContainer.innerHTML = '';
if (!city) {
errorMsg.innerText = 'Silakan masukkan nama kota terlebih dahulu!';
return;
}
loading.classList.remove('d-none'); // Tampilkan loading
try {
// 1. Cari Koordinat Kota (Geocoding API dari Open-Meteo, tanpa key)
const geoResponse = await fetch(`https://geocoding-api.open-meteo.com/v1/search?name=${encodeURIComponent(city)}&count=1&language=id`);
const geoData = await geoResponse.json();
if (!geoData.results || geoData.results.length === 0) {
throw new Error("Kota tidak ditemukan. Coba nama kota yang lain.");
}
const location = geoData.results[0];
cityName.innerText = `Prakiraan Cuaca: ${location.name}, ${location.country}`;
// 2. Ambil Data Cuaca (Forecast API berdasarkan Latitude & Longitude)
const weatherResponse = await fetch(`https://api.open-meteo.com/v1/forecast?latitude=${location.latitude}&longitude=${location.longitude}&daily=weathercode,temperature_2m_max,temperature_2m_min&timezone=auto`);
const weatherData = await weatherResponse.json();
// 3. Render 5 Hari ke layar
let cardsHtml = '';
for (let i = 0; i < 5; i++) {
const date = weatherData.daily.time[i];
const maxTemp = weatherData.daily.temperature_2m_max[i];
const minTemp = weatherData.daily.temperature_2m_min[i];
const code = weatherData.daily.weathercode[i];
const weatherInfo = getWeatherDescription(code);
cardsHtml += `
<div class="col-lg-2 col-md-4 col-sm-6 mb-3 mx-auto">
<div class="card h-100 text-center shadow-sm border-0">
<div class="card-header bg-white border-bottom-0 pt-3 fw-bold text-secondary">
${formatDate(date)}
</div>
<div class="card-body">
<div class="weather-icon mb-2">${weatherInfo.emoji}</div>
<h6 class="card-title text-dark">${weatherInfo.desc}</h6>
<h4 class="text-primary mt-3 mb-0">${maxTemp}°C</h4>
<small class="text-muted">Min: ${minTemp}°C</small>
</div>
</div>
</div>`;
}
forecastContainer.innerHTML = cardsHtml;
} catch (error) {
errorMsg.innerText = error.message;
} finally {
loading.classList.add('d-none'); // Sembunyikan loading
}
}
// Fungsi bantuan: Mengubah Format Tanggal (YYYY-MM-DD ke Hari, DD Bulan)
function formatDate(dateString) {
const options = { weekday: 'short', day: 'numeric', month: 'short' };
const date = new Date(dateString);
return date.toLocaleDateString('id-ID', options);
}
// Fungsi bantuan: Menerjemahkan WMO Weather Code ke Emoji dan Teks
function getWeatherDescription(code) {
if (code === 0) return { desc: 'Cerah', emoji: '☀️' };
if (code === 1 || code === 2) return { desc: 'Cerah Berawan', emoji: '⛅' };
if (code === 3) return { desc: 'Mendung', emoji: '☁️' };
if (code >= 45 && code <= 48) return { desc: 'Berkabut', emoji: '🌫️' };
if (code >= 51 && code <= 57) return { desc: 'Gerimis', emoji: '🌦️' };
if (code >= 61 && code <= 67) return { desc: 'Hujan', emoji: '🌧️' };
if (code >= 71 && code <= 77) return { desc: 'Salju', emoji: '❄️' };
if (code >= 80 && code <= 82) return { desc: 'Hujan Deras', emoji: '⛈️' };
if (code >= 95) return { desc: 'Badai Petir', emoji: '⚡' };
return { desc: 'Tidak Diketahui', emoji: '❓' };
}
// Picu pencarian jika user menekan tombol 'Enter' pada keyboard
document.getElementById("cityInput").addEventListener("keypress", function(event) {
if (event.key === "Enter") {
event.preventDefault();
searchWeather();
}
});
</script>
<!-- Script Bootstrap -->
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
</body>
</html>
Untuk melihat hasil akhir, mengubah tampilan, atau mencoba aplikasinya secara langsung tanpa harus repot membuat file baru di kodemu, kamu bisa mengunjungi tautan CodePen yang sudah saya sediakan di bawah ini:
Selamat mencoba dan bereksperimen! Karena berjalan di sisi klien, kamu bebas memodifikasi warna, gaya, maupun logika Javascript-nya agar sesuai dengan seleramu. Semoga tutorial ini bermanfaat untuk menambah proyek di portofoliomu.
Artikel Terkait
Cara Restrukturisasi CRUD Node.js: Dari Function ke Folder Controller-Service-Model
cara merestrukturisasi kode CRUD dari kumpulan function menjadi struktur folder yang rapi menggunakan pola Controller-Service-Model.
Panduan Lengkap Membuat Aplikasi Web dengan React JS
Pelajari cara membuat aplikasi web menggunakan React JS dalam tutorial langkah demi langkah ini.
Cara Membuat Efek Parallax Mudah dengan parallaxx.js
Pelajari cara membuat efek parallax yang menakjubkan menggunakan parallax.js dalam tutorial ini.
