Using the Server¶
This page describes the XMDB server and its API.
The server allows you to expose your database to the network. For now, only the HTTP(S) protocol is supported, but a custom application layer protocol is planned to be implemented in the future.
The choice of HTTP as a primary network protocol might look weird, unconventional or unsafe, but there are some advantages of using it.
Simplicity - implemnting a custom application layer network procotocol was never the focus of the project. HTTP is very simple to get started with.
Frontend use - first-class support for querying the database straight from the browser is a big advantage, considering the media-first focus of the XMDB project. No proxies needed!
Deployment¶
System requirements¶
A POSIX-compatible operating system (only Linux tested)
OpenSSL – required as a transitive dependency from
libweb, even when not using HTTPS
Running the server¶
After building the project, start the server with:
./build/src/Server/xmdb_server
The server listens for HTTP connections on its configured port.
Storage¶
Each persistent table is stored as a set of files in the working directory from which the server was launched:
`<hash>.sdb` - record data. Contains table records.
`<hash>.xdb` - B-Tree index. A page-based file that stores the primary-key index for the table.
`<table>-<column>.idb` - image data (one per image column). Stores image chunks.
<hash> is the hex-encoded SHA-256 digest of the table name.
All files are written relative to the current working directory. There is currently no configuration option to change the storage path, so make sure to always start the server from the same directory.
Backups¶
XMDB does not provide a built-in backup mechanism. Backups are fully the user’s responsibility. A few approaches to consider:
Filesystem snapshots - if the underlying filesystem supports snapshots (ZFS, Btrfs, LVM), take a snapshot of the directory that contains the
.sdb,.xdb, and.idbfiles. This is the fastest and most consistent option.File copy - stop the server and copy all
.sdb,.xdb, and.idbfiles to a backup location. Stopping the server first avoids copying partially-written files.Periodic rsync - use
rsyncto mirror the storage directory to a remote host on a schedule. Combining this with a brief server stop ensures consistency; without stopping, you may capture an inconsistent state.Block-level replication - replicate the entire block device or partition with tools like DRBD for real-time redundancy.
Regardless of the approach, verify your backups periodically by restoring them into a test environment.
Scaling¶
XMDB does not support horizontal scaling or replication. The only way to scale the server is vertically - by adding more CPU, memory, or faster storage to the machine it runs on.
If the application that talks to the database is bottlenecked by query latency, consider placing a caching layer (e.g. Redis or Memcached) between the application and the server to avoid repeated queries for the same data.
API¶
HTTP API¶
POST /connect¶
Authenticates a user against a database and returns a connection ID for use in subsequent requests.
Request body
Field |
Type |
Description |
|---|---|---|
|
|
The username to authenticate as. |
|
|
SHA-256 digest of the user’s password, encoded as a hexadecimal string. |
|
|
Name of the database to connect to. |
Response
On success the response body is the connection ID as a plain integer (not JSON). Use this value in subsequent requests.
Errors
Status |
Condition |
|---|---|
|
Missing or malformed fields, invalid hex string, or incorrect password. |
|
Database or user not found. |
Example
{
"username": "admin",
"password_hash": "5e884898da28047151d0e56f8dc6292773603d0d6aabbdd62a11ef721d1542d8",
"db_name": "mydb"
}
POST /run-query¶
Executes a SQL query on an existing connection and returns the results.
Request body
Field |
Type |
Description |
|---|---|---|
|
|
The connection ID obtained from |
|
|
The SQL query to execute. |
Response
The response is a JSON object. On success:
{
"ok": true,
"column_names": ["id", "name"],
"column_types": ["INTEGER", "TEXT"],
"rows": [
{"id": 1, "name": "Alice"},
{"id": 2, "name": "Bob"}
]
}
If the query succeeds but produces no result set (e.g. INSERT), the
column_names, column_types, and rows fields are omitted.
On failure:
{
"ok": false,
"error_message": "description of the error"
}
Value encoding
Column type |
JSON encoding |
|---|---|
|
|
|
|
|
|
|
Object with |
Errors
Status |
Condition |
|---|---|
|
Missing fields, non-integral connection ID, unknown connection, or
query compilation/execution failure (returned inside JSON with
|
POST /get-db-objects¶
Returns the list of tables and their schemas for the database associated with the given connection.
Request body
Field |
Type |
Description |
|---|---|---|
|
|
The connection ID obtained from |
Response
{
"ok": true,
"tables": [
{
"name": "users",
"column_names": ["id", "name", "email"],
"column_types": ["INTEGER", "TEXT", "TEXT"]
}
]
}
Each entry in tables describes one table with its column names and types.
Errors
Status |
Condition |
|---|---|
|
Missing |