Skip to content

Technical — Database Connect

RAGA's database proxy service, built on Node.js + Express. Accepts database connection parameters via per-request HTTP headers, forwards SQL queries to PostgreSQL or MariaDB/MySQL, and returns the result as JSON. Used by the Raga Engine (Text-to-SQL) in api-tarantula to execute LLM-generated queries against externally configured user databases.

Note: this service is stateless — no database configuration is stored. All credentials are sent by the caller via request headers on every request.

Repository

KeyValue
Git Remotehttps://git.tlab.co.id/tarantula/service/database-connect.git
Active Branchmain
bash
git clone https://git.tlab.co.id/tarantula/service/database-connect.git
cd database-connect

Tech Stack

LayerTechnology
RuntimeNode.js 18
FrameworkExpress 4
PostgreSQL Clientpg (node-postgres)
MariaDB/MySQL Clientmariadb
API Docsswagger-ui-express + swagger.json
Dev Runnernodemon
ContainerizationDocker (node:18)

Folder Structure

database-connect/
├── index.js             # Express app + all connection & query logic
├── swagger.json         # Swagger/OpenAPI 3.0 spec (mounted at /api-docs)
├── package.json
├── Dockerfile
├── Dockerfile.stag
└── docker-compose.dev.yml

Environment Variables

This service does not use environment variables for database configuration. All connection parameters are sent via per-request HTTP headers by the caller.

Request Headers (Required on Every Request)

HeaderExampleDescription
x-db-modepostgresqlDatabase mode: postgresql, mariadb, or mysql
x-db-host10.1.102.15Database server host
x-db-port5432Database server port
x-db-userpostgresDatabase username
x-db-passwordsecretDatabase password
x-db-nameraga_dbDatabase / schema name

The connection is created per request (not a connection pool) with a 15-second timeout. The connection is closed automatically once the query finishes.

Operational note: index.js currently writes the full connection details — including x-db-password in plaintext — to console.log every time a connection is created, and logs the raw query text on every /execute call. Make sure this service's container logs are not stored anywhere broadly accessible (a shared log aggregator, etc.) until this behavior is changed to mask credentials.

Endpoints

MethodPathDescription
GET/healthService health check
GET/check-connectionTests the database connection
GET/tablesLists all tables + columns in the database
POST/executeExecutes a raw SQL query
GET/api-docsSwagger UI (OpenAPI 3.0)

GET /check-connection

Tests whether a connection to the database can be established, then immediately closes it.

200 Response:

json
{ "status": "Connected successfully" }

500 Response:

json
{ "error": "Connection timeout" }

GET /tables

Returns a list of all tables in the database along with their column names and data types. The information_schema query is adapted per database engine.

200 Response:

json
{
  "tables": {
    "users": [
      { "column_name": "id", "data_type": "integer" },
      { "column_name": "name", "data_type": "character varying" },
      { "column_name": "created_at", "data_type": "timestamp without time zone" }
    ],
    "orders": [
      { "column_name": "id", "data_type": "integer" },
      { "column_name": "user_id", "data_type": "integer" }
    ]
  }
}

POST /execute

Executes a raw SQL query (SELECT, INSERT, UPDATE, DELETE, etc.) and returns the result.

Request body:

json
{
  "query": "SELECT id, name FROM users WHERE created_at > '2026-01-01' LIMIT 10"
}

200 Response:

json
{
  "result": [
    { "id": 1, "name": "Budi Santoso" },
    { "id": 2, "name": "Sari Dewi" }
  ]
}

400 Response:

json
{ "error": "Query is required" }

GET /health

json
{ "status": "OK", "timestamp": "2026-06-30T10:00:00.000Z" }

Request Flow

Data Type Normalization

The database response is normalized so it can be safely serialized to JSON:

DB TypeConverted ToExample
BigIntstring9007199254740993
DateISO 8601 string"2026-06-30T10:00:00.000Z"
BufferBase64 string"SGVsbG8="
OtherUnchanged

Query per Database Engine

OperationPostgreSQLMariaDB / MySQL
List tablesinformation_schema.tables WHERE table_schema='public'information_schema.tables WHERE table_schema = ?
List columnsinformation_schema.columns WHERE table_name = $1information_schema.columns WHERE table_schema = ? AND table_name = ?

Build & Run

bash
# Install dependencies
npm install

# Run development (nodemon)
npm start

# Docker Compose (dev)
docker compose -f docker-compose.dev.yml up --build

# Standalone Docker build & run
docker build -t database-connect .
docker run -p 3000:3000 database-connect

Example calls once the service is running:

bash
# Test a PostgreSQL connection
curl -X GET http://localhost:3000/check-connection \
  -H "x-db-mode: postgresql" \
  -H "x-db-host: 10.1.102.15" \
  -H "x-db-port: 5432" \
  -H "x-db-user: postgres" \
  -H "x-db-password: secret" \
  -H "x-db-name: raga_db"

# Execute a query
curl -X POST http://localhost:3000/execute \
  -H "Content-Type: application/json" \
  -H "x-db-mode: postgresql" \
  -H "x-db-host: 10.1.102.15" \
  -H "x-db-port: 5432" \
  -H "x-db-user: postgres" \
  -H "x-db-password: secret" \
  -H "x-db-name: raga_db" \
  -d '{"query": "SELECT * FROM users LIMIT 5"}'