Catatan Harian Mas Andri

Silahkan digunakan dengan bijaksana

back

Membuat Layanan API Cuaca dengan Google Apps Script dan wttr.in

04 April 2025 || 14:47:58 WIB || ClassyID

Membuat API cuaca sendiri tanpa perlu hosting khusus atau infrastruktur kompleks

Dalam dunia pengembangan aplikasi modern, data cuaca merupakan salah satu informasi yang sering dibutuhkan. Banyak aplikasi memerlukan informasi cuaca, mulai dari aplikasi pertanian, transportasi, hingga aplikasi kesehatan dan olahraga.

Namun, sebagian besar layanan API cuaca komersial memiliki batasan penggunaan atau biaya yang cukup tinggi untuk penggunaan skala besar. Bagaimana jika kita bisa membuat layanan API cuaca sendiri yang gratis, mudah di-deploy, dan dilengkapi dengan sistem logging yang komprehensif?

Dalam artikel ini, saya akan membahas cara membuat layanan API cuaca menggunakan Google Apps Script yang memanfaatkan data dari wttr.in, dilengkapi dengan sistem pencatatan log dan notifikasi Telegram.

Apa itu wttr.in?

wttr.in adalah layanan cuaca berbasis konsol yang dikembangkan oleh Igor Chubin. Layanan ini menyajikan informasi cuaca dalam format text-based yang mudah dibaca dan kompatibel dengan terminal. Yang menarik, wttr.in juga menyediakan format JSON yang bisa diakses dengan menambahkan parameter ?format=j1.

Mengapa Google Apps Script?

Google Apps Script adalah platform pengembangan yang dibangun di atas infrastruktur Google Cloud. Dengan Google Apps Script, kita bisa membuat aplikasi web tanpa perlu mengkhawatirkan hosting, domain, atau infrastruktur backend kompleks lainnya. Kelebihan utamanya adalah:

  1. Gratis untuk penggunaan dalam batas kuota normal
  2. Terintegrasi dengan layanan Google lainnya seperti Spreadsheet, Gmail, dll
  3. Mudah di-deploy tanpa setup server yang rumit
  4. Reliable karena berjalan di infrastruktur Google

Mari Mulai Membuat API Cuaca

Apa yang akan kita buat?

Kita akan membuat sebuah API yang:

  1. Mengambil data cuaca dari wttr.in berdasarkan koordinat lokasi
  2. Mengubah data tersebut menjadi format JSON yang lebih terstruktur
  3. Menyediakan dokumentasi API yang informatif
  4. Mencatat setiap akses ke Google Spreadsheet
  5. Mengirim notifikasi Telegram untuk error dan aktivitas penting

Langkah 1: Membuat Project Google Apps Script

  1. Buka Google Apps Script
  2. Klik "New Project"
  3. Ganti nama project menjadi "Weather API Grabber"

Langkah 2: Menyiapkan Konfigurasi

Pertama, kita perlu menyiapkan konfigurasi dasar untuk layanan kita:

// KONFIGURASI
var CONFIG = {
  SPREADSHEET_ID: "YOUR_SPREADSHEET_ID",
  LOG_SHEET_NAME: "logAPI",
  TELEGRAM_BOT_TOKEN: "YOUR_BOT_TOKEN",
  TELEGRAM_CHAT_ID: "YOUR_CHAT_ID"
};

Ganti nilai-nilai di atas dengan:

Langkah 3: Fungsi Utama untuk Menangani Permintaan

Selanjutnya, kita membuat fungsi doGet() yang menangani semua request HTTP GET:

function doGet(e) {
  var startTime = new Date();
  var userIP = getIpAddress();
  
  // Jika tidak ada parameter, tampilkan dokumentasi API
  if (!e.parameter.loc) {
    logAccess(startTime, new Date(), userIP, "/", "DOCS", "Success", 200, "Menampilkan dokumentasi API");
    return serveApiDocs();
  }
  
  try {
    // Ambil parameter lokasi
    var location = e.parameter.loc;
    
    // URL untuk wttr.in dengan format plain
    var url = "https://wttr.in/" + location + "?format=j1";
    
    // Lakukan request ke wttr.in
    var response = UrlFetchApp.fetch(url);
    var jsonData = JSON.parse(response.getContentText());
    
    // Ekstrak data cuaca yang relevan
    var weatherData = processWeatherData(jsonData, "", location);
    
    // Log akses sukses
    logAccess(startTime, new Date(), userIP, "/loc=" + location, "GET", "Success", 200, "Data cuaca berhasil diambil");
    
    // Kembalikan data dalam format JSON
    return ContentService.createTextOutput(JSON.stringify(weatherData))
      .setMimeType(ContentService.MimeType.JSON);
    
  } catch (error) {
    // Log akses gagal
    logAccess(startTime, new Date(), userIP, "/loc=" + location, "GET", "Error", 500, error.toString());
    
    // Handling error
    return ContentService.createTextOutput(JSON.stringify({
      error: true,
      message: "Error: " + error.toString()
    })).setMimeType(ContentService.MimeType.JSON);
  }
}

Langkah 4: Fungsi untuk Memproses Data Cuaca

Kita perlu mengolah data dari wttr.in untuk mendapatkan format yang lebih terstruktur:

function processWeatherData(jsonData, htmlContent, location) {
  // Ambil data saat ini
  var current = jsonData.current_condition[0];
  
  // Ambil ramalan 3 hari
  var forecast = jsonData.weather.map(function(day) {
    return {
      date: day.date,
      astronomy: day.astronomy[0],
      maxTempC: day.maxtempC,
      minTempC: day.mintempC,
      hourly: day.hourly.map(function(hour) {
        return {
          time: hour.time,
          tempC: hour.tempC,
          weatherDesc: hour.weatherDesc[0].value,
          precipMM: hour.precipMM,
          humidity: hour.humidity,
          windspeedKmph: hour.windspeedKmph,
          winddir16Point: hour.winddir16Point
        };
      })
    };
  });
  
  // Ekstrak informasi lokasi
  var locationInfo = {
    coordinates: location,
    name: jsonData.nearest_area ? jsonData.nearest_area[0].areaName[0].value : "Unknown",
    region: jsonData.nearest_area ? jsonData.nearest_area[0].region[0].value : "Unknown",
    country: jsonData.nearest_area ? jsonData.nearest_area[0].country[0].value : "Unknown"
  };
  
  // Menggabungkan semua informasi
  return {
    location: locationInfo,
    current: {
      tempC: current.temp_C,
      weatherDesc: current.weatherDesc[0].value,
      windspeedKmph: current.windspeedKmph,
      humidity: current.humidity,
      precipMM: current.precipMM,
      visibility: current.visibility,
      pressure: current.pressure,
      cloudcover: current.cloudcover,
      feelsLikeC: current.FeelsLikeC,
      uvIndex: current.uvIndex
    },
    forecast: forecast,
    timestamp: new Date().toISOString(),
    source: "wttr.in"
  };
}

Langkah 5: Fungsi untuk Mencatat Log dan Mengirim Notifikasi

Sistem logging dan notifikasi adalah fitur penting dari API kita:

function logAccess(startTime, endTime, ip, endpoint, method, status, statusCode, message) {
  try {
    // Log ke spreadsheet
    logToSpreadsheet(startTime, endTime, ip, endpoint, method, status, statusCode, message);
    
    // Kirim notifikasi Telegram untuk error atau aktivitas penting
    if (status === "Error" || endpoint.includes("new") || statusCode >= 400) {
      sendTelegramNotification(startTime, ip, endpoint, method, status, statusCode, message);
    }
  } catch (error) {
    console.error("Gagal mencatat log: " + error.toString());
  }
}

function logToSpreadsheet(startTime, endTime, ip, endpoint, method, status, statusCode, message) {
  try {
    var ss = SpreadsheetApp.openById(CONFIG.SPREADSHEET_ID);
    var sheet = ss.getSheetByName(CONFIG.LOG_SHEET_NAME);
    
    // Buat sheet jika belum ada
    if (!sheet) {
      sheet = ss.insertSheet(CONFIG.LOG_SHEET_NAME);
      sheet.appendRow([
        "Timestamp", 
        "Durasi (ms)", 
        "IP", 
        "Endpoint", 
        "Method", 
        "Status", 
        "Status Code", 
        "Message"
      ]);
    }
    
    // Hitung durasi dalam milidetik
    var duration = endTime.getTime() - startTime.getTime();
    
    // Tambahkan log baru
    sheet.appendRow([
      new Date(), 
      duration, 
      ip, 
      endpoint, 
      method, 
      status, 
      statusCode, 
      message
    ]);
  } catch (error) {
    console.error("Gagal mencatat log ke spreadsheet: " + error.toString());
  }
}

function sendTelegramNotification(startTime, ip, endpoint, method, status, statusCode, message) {
  try {
    var telegramApiUrl = "https://api.telegram.org/bot" + CONFIG.TELEGRAM_BOT_TOKEN + "/sendMessage";
    
    // Format pesan
    var formattedDate = Utilities.formatDate(startTime, "Asia/Jakarta", "dd-MM-yyyy HH:mm:ss");
    var telegramMessage = 
      " *Weather API Alert*\n" +
      " *Time:* " + formattedDate + "\n" +
      " *IP:* " + ip + "\n" +
      " *Endpoint:* " + endpoint + "\n" +
      " *Method:* " + method + "\n" +
      " *Status:* " + status + " (" + statusCode + ")\n" +
      " *Message:* " + message;
    
    // Kirim pesan ke Telegram
    var payload = {
      "chat_id": CONFIG.TELEGRAM_CHAT_ID,
      "text": telegramMessage,
      "parse_mode": "Markdown"
    };
    
    var options = {
      "method": "post",
      "contentType": "application/json",
      "payload": JSON.stringify(payload)
    };
    
    UrlFetchApp.fetch(telegramApiUrl, options);
  } catch (error) {
    console.error("Gagal mengirim notifikasi Telegram: " + error.toString());
  }
}

Langkah 6: Fungsi untuk Mendapatkan IP

Untuk melengkapi log, kita perlu mendapatkan alamat IP:

function getIpAddress() {
  var url = 'https://api.ipify.org';
  var options = {
    'method': 'GET',
    'muteHttpExceptions': true
  };

  try {
    var response = UrlFetchApp.fetch(url, options);
    if (response.getResponseCode() === 200) {
      return response.getContentText();
    } else {
      console.error('Error fetching IP address. Response code:', response.getResponseCode());
      return 'Unknown';
    }
  } catch (e) {
    console.error('Error fetching IP address:', e);
    return 'Unknown';
  }
}

Langkah 7: Fungsi untuk Menyajikan Dokumentasi API

Terakhir, kita perlu membuat dokumentasi yang informatif namun sederhana:

function serveApiDocs() {
  var apiName = "Weather API Grabber";
  var version = "v1.0";
  var lastUpdate = new Date().toISOString().split('T')[0];
  
  var html = `
  <!DOCTYPE html>
  <html>
  <head>
    <title>${apiName}</title>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <style>
      body {
        font-family: Arial, sans-serif;
        line-height: 1.6;
        margin: 0;
        padding: 20px;
        color: #333;
        background-color: #f9f9f9;
      }
      .container {
        max-width: 700px;
        margin: 0 auto;
        background-color: white;
        padding: 30px;
        border-radius: 8px;
        box-shadow: 0 2px 10px rgba(0,0,0,0.1);
      }
      h1 {
        color: #2c3e50;
        margin-top: 0;
      }
      code {
        background-color: #f0f0f0;
        padding: 2px 6px;
        border-radius: 3px;
        font-family: monospace;
      }
      .example {
        background-color: #f0f8ff;
        padding: 15px;
        border-radius: 5px;
        margin: 15px 0;
        border-left: 4px solid #3498db;
      }
      .endpoint {
        font-weight: bold;
        color: #2980b9;
      }
    </style>
  </head>
  <body>
    <div class="container">
      <h1>${apiName}</h1>
      <p>Versi: ${version} | Terakhir Diperbarui: ${lastUpdate}</p>
      
      <h2>Cara Penggunaan:</h2>
      <p>Tambahkan parameter <code>loc</code> dengan nilai koordinat lokasi (latitude,longitude).</p>
      
      <div class="example">
        <p><span class="endpoint">GET</span> <code>${ScriptApp.getService().getUrl()}?loc=-7.8603934,112.0381211</code></p>
      </div>
      
      <h2>Contoh Respons:</h2>
      <div class="example">
        <code>
        {<br>
        &nbsp;&nbsp;"location": {<br>
        &nbsp;&nbsp;&nbsp;&nbsp;"coordinates": "-7.8603934,112.0381211",<br>
        &nbsp;&nbsp;&nbsp;&nbsp;"name": "Kediri"<br>
        &nbsp;&nbsp;},<br>
        &nbsp;&nbsp;"current": {<br>
        &nbsp;&nbsp;&nbsp;&nbsp;"tempC": "24",<br>
        &nbsp;&nbsp;&nbsp;&nbsp;"weatherDesc": "Cerah"<br>
        &nbsp;&nbsp;},<br>
        &nbsp;&nbsp;"forecast": [ ... ],<br>
        &nbsp;&nbsp;"timestamp": "2025-04-04T08:30:45.123Z"<br>
        }
        </code>
      </div>
      
      <p><strong>Catatan:</strong> Data cuaca disediakan oleh wttr.in. Gunakan API ini dengan bijak.</p>
      
      <footer style="margin-top: 30px; font-size: 12px; color: #777; text-align: center;">
        <p>&copy; ${new Date().getFullYear()} Weather API Grabber</p>
      </footer>
    </div>
  </body>
  </html>
  `;
  
  return HtmlService.createHtmlOutput(html);
}

Langkah 8: Deploy API

Setelah semua kode ditulis, kita perlu men-deploy API kita:

  1. Klik "Deploy" > "New deployment"
  2. Pilih "Web app" sebagai tipe
  3. Masukkan deskripsi (opsional)
  4. Atur akses ke "Anyone"
  5. Klik "Deploy"
  6. Salin URL web app yang dihasilkan

Menggunakan API

Setelah di-deploy, API kita siap digunakan. Berikut cara mengaksesnya:

  1. Melihat Dokumentasi

    https://script.google.com/macros/s/YOUR_DEPLOYMENT_ID/exec
    
  2. Mendapatkan Data Cuaca

    https://script.google.com/macros/s/YOUR_DEPLOYMENT_ID/exec?loc=-7.8603934,112.0381211
    

Melihat Log dan Notifikasi

Semua akses ke API akan dicatat dalam spreadsheet yang telah ditentukan. Untuk akses yang menghasilkan error atau aktivitas penting lainnya, notifikasi akan dikirim ke Telegram.

Kesimpulan

Dengan memanfaatkan Google Apps Script dan data dari wttr.in, kita telah berhasil membuat layanan API cuaca yang fungsional, mudah dipelihara, dan dilengkapi dengan fitur monitoring yang komprehensif.

API ini sangat berguna untuk:

Langkah Selanjutnya

API ini masih bisa dikembangkan lebih lanjut dengan menambahkan fitur-fitur seperti:

Mari eksplor kemungkinan ini di artikel selanjutnya!


Apakah artikel ini bermanfaat bagi Anda? Bagikan pengalaman atau pertanyaan Anda di kolom komentar di bawah. Jangan lupa untuk melihat kode lengkapnya di GitHub.


Tentang Penulis

Andri Wiratmono adalah seorang developer dan content creator yang berfokus pada teknologi web dan pengembangan API. Temukan lebih banyak tutorial dan proyek di GitHub