Author: Kamil 'Nowik' Nowicki (kamil.nowak85@icloud.com)
Copyright © 2025
License: Apache License 2.0
This project is a simple REST API for a MariaDB database written in Python using FastAPI.
- The API listens on a configurable
IP:port(set inconfig.ini). - Normal users can only search data in the database.
- Admins can:
- search data,
- insert/modify/delete data in tables,
- create new users (including other admins),
- create new tables dynamically (with configurable columns and types).
Important: This is a generic example API. It assumes your tables use an integer primary key column named
idfor update/delete operations.
These are the minimal steps to get the API running on a single machine (Linux/Windows) and reach the web UI.
- Install prerequisites
- Install Python 3.9+.
- Install MariaDB server and make sure it is running.
- Get the project files
- Clone or download this repository.
- Open a terminal and change into the project directory (where
main.pyandrequirements.txtlive).
- Create and activate a virtual environment
- Linux/macOS (bash/zsh):
python3 -m venv .venv source .venv/bin/activate - Windows (PowerShell):
python -m venv .venv .\.venv\Scripts\Activate.ps1
- Linux/macOS (bash/zsh):
- Install Python dependencies
This installs FastAPI, Uvicorn, MariaDB driver, Passlib (with bcrypt) and pins
pip install -r requirements.txt
bcrypt==4.3.0. - Run the first-time setup wizard
- Make sure MariaDB is running and you know the host/port/user/password.
- From the project directory (venv active), run:
python main.py
- If
config.iniis missing or invalid, the wizard will ask you for:- MariaDB host, port, user, password, database name,
- and will create required tables and an initial admin user.
- Start the API server
- Easiest: keep using:
This reads host/port from
python main.py
config.ini. - Or using
uvicorndirectly (example):uvicorn main:app --host 0.0.0.0 --port 8000
- Easiest: keep using:
- Open the web UI in a browser
- Go to:
http://localhost:8000/app(or replacelocalhost:8000with your host/port). - Log in with the admin credentials created in the wizard.
- From there you can:
- search tables,
- manage users,
- create new tables and columns,
- insert/update/delete rows (admin only).
- Go to:
For more detailed information, see the sections below.
- Overview
- Quick start – step by step
- Requirements
- Installation
- Database preparation
- Configuration (
config.ini) - Running the API
- Project structure (modular layout)
- Web frontend
- API Usage
- Security Notes
- License
- Python 3.9 or newer (recommended)
- MariaDB server (local or remote)
- Ability to install Python packages with
pip
Place all files in a directory (for example this one: db/api).
python3 -m venv .venv
source .venv/bin/activatepython -m venv .venv
.\.venv\Scripts\Activate.ps1With the virtual environment activated:
pip install -r requirements.txtIf config.ini does not contain valid database credentials and you have not set
DB_HOST / DB_USER / DB_PASSWORD / DB_NAME environment variables, running
python main.pywill start an interactive first-time setup wizard:
- asks for MariaDB host, port, user, password and database name,
- connects to MariaDB and creates the database if it does not exist,
- creates required tables:
users– stores API users and their hashed passwords,audit_log– records admin operations,
- asks you to create an initial admin user (username + password),
- writes everything into
config.ini(and generates a randomsecret_keyif missing).
After the wizard finishes, you can start the API normally and log in with the admin user you just created.
If you prefer to create the schema manually, you need a MariaDB database and a
users table for authentication.
Example SQL (adjust as needed):
CREATE TABLE users (
id INT AUTO_INCREMENT PRIMARY KEY,
username VARCHAR(255) NOT NULL UNIQUE,
password_hash VARCHAR(255) NOT NULL,
role VARCHAR(20) NOT NULL
);
CREATE TABLE audit_log (
id INT AUTO_INCREMENT PRIMARY KEY,
actor VARCHAR(255) NOT NULL,
action VARCHAR(100) NOT NULL,
table_name VARCHAR(255) NOT NULL,
row_id INT NULL,
details TEXT NULL,
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
);- Create the database (if not already existing):
CREATE DATABASE your_database_name_here CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;- Create a user with permissions on that database (example):
CREATE USER 'api_user'@'%' IDENTIFIED BY 'your_strong_password';
GRANT ALL PRIVILEGES ON your_database_name_here.* TO 'api_user'@'%';
FLUSH PRIVILEGES;- Insert an initial admin user (you can either use the API to create it or insert a row manually with a bcrypt password hash).
Edit config.ini before running the API:
[server]
host = 0.0.0.0
port = 8000
[database]
host = localhost
port = 3306
user = api_user
password = your_strong_password
database = your_database_name_here
[security]
secret_key = CHANGE_ME_SECRET_KEY
access_token_expire_minutes = 60hostandportunder[server]define the IP and port the API will listen on.- Use
0.0.0.0to listen on all interfaces (necessary when the API is on a server and accessed from other machines).
- Use
- Under
[database], set the correct MariaDB connection values. - Under
[security], set a strong, randomsecret_keyfor JWT tokens.
Security tip: You can avoid storing DB credentials in
config.iniby using environment variables. The app will use these if set:DB_HOST,DB_PORT,DB_USER,DB_PASSWORD,DB_NAME.
If config.ini does not yet contain valid DB credentials, run:
python main.pyThe wizard will guide you through configuring the DB connection and creating the
initial admin. After that, you can run the API as a service or via uvicorn.
With your virtual environment active and inside the project directory:
uvicorn main:app --host 0.0.0.0 --port 8000Or to use the host/port from config.ini, you can run the module directly:
python main.pyIn PowerShell (after activating the virtual environment and going to the project directory):
uvicorn main:app --host 0.0.0.0 --port 8000Or:
python main.pyMake sure appropriate firewall rules allow incoming connections on the configured port.
The project is split into multiple modules for easier maintenance:
main.py– entry point that configures the app and starts Uvicorn.db_utils.py– database connection helpers, schema validation, and audit logging.static/– browser-based HTML+JS frontend.config.ini– server, database, security, and logging configuration.README.md,LICENSE,requirements.txt– documentation and metadata.
Once running, you can use the built-in web interface in a browser:
http://<server-ip>:<port>/app– simple HTML+JS frontend for users and admins.
The API root endpoint will be available at:
http://<server-ip>:<port>/
The interactive API documentation (Swagger UI) is available at:
http://<server-ip>:<port>/docs
- First, obtain a token via
/login.
- Endpoint:
POST /login - Form data (x-www-form-urlencoded):
usernamepassword
Response:
{
"access_token": "<JWT_TOKEN>",
"token_type": "bearer"
}Include the token in the Authorization header as Bearer <JWT_TOKEN> for all subsequent requests.
Admins can create new tables at runtime, either through the web UI or via REST.
- Log in as an admin at
http://<server-ip>:<port>/app. - In the right-hand Admin panel, scroll to Create table.
- Fill in:
- Table name – e.g.
contacts,orders_2025(letters/digits/_, not starting with a digit). - One or more column rows:
column name– name of the column (cannot beid, reserved for primary key).type– logical type, mapped to MariaDB:string→VARCHAR(length or 255)text→TEXTint→INTbigint→BIGINTfloat→DOUBLEbool→TINYINT(1)datetime→DATETIMEdate→DATEtime→TIME
length (for text)– optional length forstringcolumns.nullable– allow NULL values.unique– add a UNIQUE constraint to the column.default value– optional default value, interpreted based on type.
- Table name – e.g.
- Click Create table.
- On success, the new table appears in the Tables list and can be queried/edited like any other table.
Each created table automatically gets an id INT AUTO_INCREMENT PRIMARY KEY column so it works with the existing /tables/{table}/{row_id} endpoints.
- Endpoint:
POST /admin/tables - Auth: admin Bearer token
- Body (JSON):
{
"table": "orders",
"columns": [
{ "name": "order_no", "type": "bigint", "nullable": false, "unique": true },
{ "name": "customer_name", "type": "string", "nullable": false, "length": 200 },
{ "name": "status", "type": "string", "nullable": false, "length": 32, "default": "pending" },
{ "name": "total", "type": "float", "nullable": false, "default": "0" },
{ "name": "is_paid", "type": "bool", "nullable": false, "default": "false" },
{ "name": "order_date", "type": "date", "nullable": false },
{ "name": "order_time", "type": "time", "nullable": true },
{ "name": "created_at", "type": "datetime", "nullable": false }
]
}The API validates names, types, lengths, uniqueness and default values, and will return 400 with a clear error message if something is invalid or the table already exists.
- User (
role = "user"):- can call:
GET /tables,GET /tables/{table_name}(search only).
- can call:
- Admin (
role = "admin"):- can call everything a user can,
- plus admin endpoints and write operations:
POST /admin/users– create new user or admin,GET /admin/users– list existing users,POST /tables/{table_name}– insert new row,PUT /tables/{table_name}/{row_id}– update row byid,DELETE /tables/{table_name}/{row_id}– delete row byid.
- Endpoint:
GET /tables - Auth: Bearer token (user or admin)
- Endpoint:
GET /tables/{table_name} - Query parameters:
column(optional) – column to filter byvalue(optional) – value for equality filterlimit(optional, default100, max1000)
Examples:
GET /tables/customers– returns first 100 rows fromcustomersGET /tables/customers?column=last_name&value=Smith&limit=50
- Endpoint:
POST /tables/{table_name} - Body (JSON):
{
"data": {
"column1": "value1",
"column2": 123
}
}- Endpoint:
PUT /tables/{table_name}/{row_id} - Body (JSON): same as for insert.
- Endpoint:
DELETE /tables/{table_name}/{row_id}
- Always use HTTPS in production (behind a reverse proxy like Nginx or Apache).
- Keep your
SECRET_KEYconfidential and strong. - Restrict database user privileges according to the principle of least privilege.
This project is licensed under the Apache License, Version 2.0 – see the LICENSE file for details.