Files
air-quality-webserver/api/server.js

306 lines
6.2 KiB
JavaScript

const express = require("express");
const mysql = require("mysql2");
const app = express();
const PORT = 3000;
app.use(express.json());
// ============================
// DB CONFIG
// ============================
const dbConfig = {
host: "db", // docker service name
user: "leman",
password: "leman123",
database: "air_quality"
};
let db;
// ============================
// CONNECT WITH RETRY
// ============================
function connectDB() {
db = mysql.createConnection(dbConfig);
db.connect(err => {
if (err) {
console.error("❌ DB connection failed:", err.message);
console.log("🔄 Retrying in 5 seconds...");
setTimeout(connectDB, 5000);
} else {
console.log("✅ Connected to MariaDB");
}
});
db.on("error", err => {
console.error("⚠️ DB error:", err.message);
if (err.code === "PROTOCOL_CONNECTION_LOST") {
console.log("🔄 Reconnecting...");
connectDB();
} else {
throw err;
}
});
}
connectDB();
// ============================
// ROOT CHECK
// ============================
app.get("/", (req, res) => {
res.send("API is running 🚀");
});
// ============================
// GET LATEST DATA
// ============================
app.get("/data", (req, res) => {
const sql = `
SELECT * FROM air_data
ORDER BY updated_at DESC
LIMIT 1
`;
db.query(sql, (err, results) => {
if (err) {
console.error(err);
return res.status(500).json({ error: "DB error" });
}
res.json(results[0] || {});
});
});
// ============================
// INSERT DATA
// ============================
app.get("/update", (req, res) => {
const { co2, co, bz, aq, id } = req.query;
if (!co2 || !co || !bz || !aq || !id) {
return res.status(400).json({
error: "Parameter wajib: co2, co, bz, aq, id"
});
}
const sql = `
INSERT INTO air_data (co2, co, bz, aq, id)
VALUES (?, ?, ?, ?, ?)
`;
db.query(
sql,
[
Number(co2),
Number(co),
Number(bz),
Number(aq),
String(id) // sensor id
],
(err, result) => {
if (err) {
console.error(err);
return res.status(500).json({ error: "DB error" });
}
res.json({
message: "Data berhasil disimpan",
insertId: result.insertId
});
}
);
});
app.get("/sensordata/:id", (req, res) => {
const sensorId = req.params.id;
const sql = `
SELECT
air_data.co2,
air_data.co,
air_data.bz,
air_data.aq,
air_data.updated_at,
sensor_data.alamat,
kelurahan.nama AS kelurahan,
kecamatan.nama AS kecamatan
FROM air_data
JOIN sensor_data
ON air_data.id = sensor_data.id
JOIN kelurahan
ON sensor_data.kelurahan = kelurahan.id
JOIN kecamatan
ON kelurahan.kecamatan_id = kecamatan.id
WHERE air_data.id = ?
ORDER BY air_data.updated_at DESC
LIMIT 1
`;
db.query(sql, [sensorId], (err, results) => {
if (err) {
console.error(err);
return res.status(500).json({ error: "DB error" });
}
if (results.length === 0) {
return res.status(404).json({
error: "Sensor not found"
});
}
res.json(results[0]);
});
});
app.get("/sensors", (req, res) => {
const sql = `SELECT id FROM sensor_data`;
db.query(sql, (err, results) => {
if (err) {
return res.status(500).json({ error: "DB error" });
}
res.json(results);
});
});
// ============================
// ADD SENSOR
// ============================
app.post("/addSensor", (req, res) => {
const { kelurahan, alamat } = req.body;
// ============================
// VALIDATION
// ============================
if (!kelurahan || !alamat) {
return res.status(400).json({
error: "kelurahan dan alamat wajib diisi"
});
}
// ============================
// VALIDATE KELURAHAN EXISTS
// ============================
const checkSql = `SELECT id FROM kelurahan WHERE id = ?`;
db.query(checkSql, [kelurahan], (err, rows) => {
if (err) {
console.error(err);
return res.status(500).json({ error: "DB error" });
}
if (rows.length === 0) {
return res.status(400).json({
error: "Kelurahan tidak valid"
});
}
// ============================
// INSERT SENSOR
// ============================
const insertSql = `
INSERT INTO sensor_data (kelurahan, alamat)
VALUES (?, ?)
`;
db.query(insertSql, [kelurahan, alamat], (err, result) => {
if (err) {
console.error(err);
return res.status(500).json({
error: "DB error saat insert"
});
}
res.json({
message: "Sensor berhasil ditambahkan",
sensor_id: result.insertId
});
});
});
});
// ============================
// GET ALL DATA (OPTIONAL)
// ============================
app.get("/history", (req, res) => {
const sql = `
SELECT * FROM air_data
ORDER BY updated_at DESC
LIMIT 100
`;
db.query(sql, (err, results) => {
if (err) {
return res.status(500).json({ error: "DB error" });
}
res.json(results);
});
});
// get kecamatan
app.get("/kecamatan", (req, res) => {
const sql = `SELECT id, nama FROM kecamatan ORDER BY nama ASC`;
db.query(sql, (err, results) => {
if (err) {
console.error(err);
return res.status(500).json({ error: "DB error" });
}
res.json(results);
});
});
// get kelurahan by kecamatan_id
app.get("/kelurahan", (req, res) => {
const { kecamatan_id } = req.query;
let sql = `
SELECT
kelurahan.id,
kelurahan.nama,
kecamatan.nama AS kecamatan
FROM kelurahan
JOIN kecamatan ON kelurahan.kecamatan_id = kecamatan.id
`;
let params = [];
if (kecamatan_id) {
sql += ` WHERE kelurahan.kecamatan_id = ?`;
params.push(kecamatan_id);
}
sql += ` ORDER BY kelurahan.nama ASC`;
db.query(sql, params, (err, results) => {
if (err) {
console.error(err);
return res.status(500).json({ error: "DB error" });
}
res.json(results);
});
});
// ============================
// START SERVER
// ============================
app.listen(PORT, () => {
console.log(`🚀 API running on port ${PORT}`);
});