I’ve recently put together a basic backend template using MySQL and Express.js, mainly for learning purposes and possibly to use it later in some smaller full-stack projects.
I tried to keep the structure simple and modular, so it can easily be reused and adapted for different use cases.
I’m wondering what you think about it:
In what kinds of small projects do you think this setup would be most useful?
What are some things I could improve in terms of code structure, security, or performance?
I also included a very small part of the frontend code, just to demonstrate how it might connect to the backend.
Any feedback or suggestions would be really appreciated — I’m trying to get better at writing clean and practical code!
const express = require('express');
const mysql = require('mysql');
const path = require('path');
const app = express();
app.use(express.static('public'));
const port = 3000;
const db = mysql.createConnection({
host: 'localhost',
user: 'root',
password: '',
database: ''
});
app.listen(port, () => {
console.log(`Server is running at http://localhost:${port}`);
});
function lekerdez(sql) {
return new Promise((resolve, reject) => {
db.query(sql, (err, result) => {
if (err) reject(err);
else resolve(result);
});
});
}
function kuld(res, promise) {
promise.then((result) => {
res.json(result);
}).catch((err) => {
res.json(err);
});
}
app.get('/get_html/:filename', (req, res) => {
res.sendFile(path.join(__dirname, 'public', req.params.filename));
});
app.get('/get_tablak', (req, res) => {
const sql = 'SHOW TABLES';
kuld(res, lekerdez(sql));
});
$(document).ready(function() {
if ($("#content").attr("ures") == "true") {
load();
$("#content").attr("ures", "false");
}
});
function load(url) {
const urlToLoad = url ? url : 'tablak.html';
const xhr = new XMLHttpRequest();
xhr.open('GET', '/get_html/' + urlToLoad, true);
xhr.send();
xhr.onreadystatechange = function() {
if (xhr.readyState == 4 && xhr.status == 200) {
$("#content").html(xhr.responseText);
}
};
}
function selectTable() {
$('#tablazatHead #tablazatBody #tablazatHead2 #tablazatBody2').html('');
fillTable('tablazatHead', 'tablazatBody', '/get_tablak/' + $('#lista').val(), 'onclick="sortElemek(event)"', 'onclick="sorKatt(event)"');
}
function sortElemek(event, tablaNev) {
if (tablaNev == '') {
const column = $(event.target).index();
const table = $('#tablazatBody1');
const rows = table.find('tr').get();
rows.sort(function(a, b) {
const A = $(a).children('td').eq(column).text().toUpperCase();
const B = $(b).children('td').eq(column).text().toUpperCase();
if (A < B) return -1;
if (A > B) return 1;
return 0;
});
$.each(rows, function(index, row) { table.append(row); });
}
}
function sorKatt(event) {
const tableName = $('#lista').val();
if (tableName === '') {
const row = $(event.target).parent().children('td').get();
const id = $(row[0]).text();
fillTable('tablazatHead2', 'tablazatBody2', `something/${id}`);
}
}
function masikTabla() {
$('#tablazatHead #tablazatBody #tablazatHead2 #tablazatBody2').html('');
fillTable('tablazatHead', 'tablazatBody', '/other_something');
}
function fillTable(tablehead, tablebody, url) {
return new Promise((resolve, reject) => {
$(`#${tablehead}`).html('');
$(`#${tablebody}`).html('');
xhr = new XMLHttpRequest();
xhr.open('GET', url, true);
xhr.send();
xhr.onreadystatechange = function() {
var tabla = JSON.parse(xhr.responseText);
if (xhr.readyState == 4 && xhr.status == 200) {
if (url.search("/") != -1) {
xhr = new XMLHttpRequest();
xhr.open('GET', '/', true);
xhr.send();
xhr.onreadystatechange = function() {
if (xhr.readyState == 4 && xhr.status == 200) {
var moziidcount = JSON.parse(xhr.responseText);
var fejlec = '<tr>';
for (var key in tabla[0]) {
fejlec += `<th>` + key + '</th>';
}
fejlec += '</tr>';
var sorok = '';
for (var i = 0; i < tabla.length; i++) {
let szam = moziidcount.filter(m => m.moziid == tabla[i].id);
sorok += `<tr title="${szam.length > 0 ? szam[0].count : 0}">`
for (var k in tabla[i]) {
sorok += '<td>' + tabla[i][k] + '</td>';
}
sorok += '</tr>';
}
$(`#${tablehead}`).html(fejlec);
$(`#${tablebody}`).html(sorok);
resolve();
}
}
} else {
var fejlec = '<tr>';
for (var key in tabla[0]) {
fejlec += `<th>` + key + '</th>';
}
fejlec += '</tr>';
var sorok = '';
for (var i = 0; i < tabla.length; i++) {
sorok += `<tr>`;
for (var k in tabla[i]) {
sorok += '<td>' + tabla[i][k] + '</td>';
}
sorok += '</tr>';
}
$(`#${tablehead}`).html(fejlec);
$(`#${tablebody}`).html(sorok);
resolve();
}
}
};
});
}
<!DOCTYPE html>
<html lang="hu">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<script src="index.js"></script>
<link rel="stylesheet" href="https://cdn.datatables.net/2.2.2/css/dataTables.dataTables.css" />
<script src="https://cdn.datatables.net/2.2.2/js/dataTables.js"></script>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css">
<title></title>
<style>
nav a {
cursor: pointer;
}
</style>
</head>
<body>
<nav class="navbar navbar-expand navbar-light bg-light mb-2">
<div class="nav navbar-nav">
<a class="nav-item nav-link" onclick="load('1.html')"></a>
<a class="nav-item nav-link" onclick="load('2.html')"></a>
<a class="nav-item nav-link" onclick="load('3.html')"></a>
</div>
</nav>
<div id="content" ures=true>
</div>
</body>
</html>
<div class="row col-12 justify-content-center" style="height: calc(100vh - 100px);">
<div class="col-lg-5 h-100 mb-5" style="overflow: auto;">
<h2 id="tablazatCim0" class="tablazatCim"></h2>
<table id="tablazat0" class="table table-striped table-bordered table-hover table-responsive-xs">
<thead id="tablazatHead0"></thead>
<tbody id="tablazatBody0"></tbody>
</table>
</div>
<div class="col-lg-5 h-100 mb-5" style="overflow: auto;">
<h2 id="tablazatCim1" class="tablazatCim"></h2>
<table id="tablazat1" class="table table-striped table-bordered table-hover table-responsive-xs">
<thead id="tablazatHead1"></thead>
<tbody id="tablazatBody1"></tbody>
</table>
</div>
</div>
<script>
var xhrTablak = new XMLHttpRequest();
xhrTablak.open('GET', '/get_tablak', true);
xhrTablak.send();
xhrTablak.onreadystatechange = function() {
if (xhrTablak.readyState == 4 && xhrTablak.status == 200) {
var tablak = JSON.parse(xhrTablak.responseText);
tablaRekurziv(0, tablak);
}
};
function tablaRekurziv(i, tablak) {
if (i < tablak.length) {
$("#tablazatCim" + i).text(tablak[i].Tables_in_vetitesek);
fillTable('tablazatHead' + i, 'tablazatBody' + i, 'get_tablak/' + tablak[i].Tables_in_vetitesek).then((result) => {
tablaRekurziv(i + 1, tablak);
});
}
}
</script>
<div class="row col-12 justify-content-center" style="height: calc(100vh - 100px);">
<div class="col-auto h-100" style="overflow: auto;">
<table class="table table-striped table-bordered table-hover table-responsive-sm">
<thead id="tablazatHead"></thead>
<tbody id="tablazatBody"></tbody>
</table>
</div>
</div>
<script>
fillTable('tablazatHead', 'tablazatBody', 'get_szinkron_tipusonkent');
</script>
<div class="row col-12" style="height: calc(100vh - 100px);">
<div class="col-auto h-100">
<h2 class="">!</h2>
<select id="selectMozi"></select>
</div>
<div class="col-auto h-100" style="overflow: auto;">
<h2 class=""></h2>
<table class="table table-striped table-bordered table-hover table-responsive-sm">
<thead id="tablazatHead"></thead>
<tbody id="tablazatBody"></tbody>
</table>
</div>
</div>
<script>
var xhrVaros = new XMLHttpRequest();
xhrVaros.open('GET', '/get_tablak/tabla_name', true);
xhrVaros.send();
xhrVaros.onreadystatechange = function() {
if (xhrVaros.readyState == 4 && xhrVaros.status == 200) {
var mozik = JSON.parse(xhrVaros.responseText);
var opciok = '<option></option>';
mozik.forEach(d => {
opciok += `<option value=""</option>`;
});
$('#selectMozi').html(opciok);
}
};
$('#selectMozi').change(function() {
const moziid = $('#selectMozi').val();
fillTable('tablazatHead', 'tablazatBody', '/get_table_name/' + moziid);
});
</script>
