Guide
Get started & deploy
Try dbAPI locally in about five minutes, then run the published container against your own MySQL or MariaDB.
Quick start
From zero to your first JSON:API responses with the local Docker stack.
1. Clone the repository
git clone https://github.com/dbAPIator/dbapi.git
cd dbapi
2. Start dbAPI
From the repository root:
docker compose up -d
Wait until the container is healthy, then:
curl -sS http://localhost:8888/health
Expect {"status":"ok","service":"dbAPI"}. The stack runs in single mode: one API (default), data under /v1/data/....
3. List a resource
Tables in the demo database are API resources. List customers:
curl -sS 'http://localhost:8888/v1/data/customers?page[limit]=2' | jq .
You get a JSON:API document: data[] with type, id, attributes (columns), and relationships (foreign keys / children).
Fetch one row:
curl -sS http://localhost:8888/v1/data/customers/1 | jq .
4. Filter and include
curl -sS 'http://localhost:8888/v1/data/customers?filter=country_code=US&page[limit]=5' | jq .
curl -sS 'http://localhost:8888/v1/data/customers/1?include=orders' | jq .
Field and relationship names come from your schema — check OpenAPI before guessing:
http://localhost:8888/swagger.html?url=v1/swagger
5. Create a record (optional)
curl -sS -X POST http://localhost:8888/v1/data/customers \
-H 'Content-Type: application/vnd.api+json' \
-d '{
"data": {
"type": "customers",
"attributes": {
"name": "Five Minute Co",
"email": "five@example.com",
"country_code": "RO"
}
}
}' | jq .
The local stack starts with auth mode none so you can explore without a JWT. Production setups usually use dbAuth — see the authentication tutorial on GitHub.
Docker deployment
Run dbAPI from the published container without cloning the repo or building PHP locally. Images ship to GitHub Container Registry on each release tag.
For live code mounts and a bundled MariaDB/Redis stack, use the quick start above (docker compose up -d in the repository). For consumer projects, copy docker/base/ from the repo into your app.
Image location and tags
| Registry | ghcr.io |
|---|---|
| Image | ghcr.io/dbapiator/dbapi |
| Package | ghcr.io/dbapiator/dbapi |
| Tag | Meaning |
|---|---|
latest | Most recent release |
1.5.0 | Exact version (pin in production) |
1.5 | Latest patch in 1.5.x |
1 | Latest release in major 1.x.x |
Pin a version in production rather than latest.
Pull the image
Public package
docker pull ghcr.io/dbapiator/dbapi:1.5.0
Private package
echo "$GITHUB_TOKEN" | docker login ghcr.io -u YOUR_GITHUB_USERNAME --password-stdin
docker pull ghcr.io/dbapiator/dbapi:1.5.0
Use a GitHub personal access token with the read:packages scope.
Deployment modes
| Mode | DEPLOYMENT_MODE | Data plane | API id |
|---|---|---|---|
| Single-API | single |
/v1/data/{resource} |
default (fixed) |
| Multi-API | multi (default) |
/v1/apis/{apiId}/data/{resource} |
Per API |
Single-API mode
On container start the entrypoint waits for MySQL/MariaDB, scaffolds the default API under CONFIGS_DIR, pre-fills connection from DB_*, then tests, builds schema, and activates when the database is reachable. No manual Management API call is required for a first run.
Inspect status with GET /mgmt/v1. OpenAPI for management: /management-openapi-single.yaml.
Multi-API mode
The container starts the web server only. Create each API through the Management API and keep configs on a persistent volume at CONFIGS_DIR.
curl -sS -X POST 'http://localhost:8888/mgmt/v1/apis?provision=immediate' \
-H 'Content-Type: application/json' \
-H 'X-Management-Key: YOUR_SECRET' \
-d '{
"name": "demo",
"connection": {
"driver": "mysql",
"host": "mysql.example.com",
"port": 3306,
"database": "myapp",
"username": "user",
"password": "password"
}
}'
Data endpoints: http://localhost:8888/v1/apis/demo/data/{resource}
Requirements
| Component | Required | Notes |
|---|---|---|
| MySQL or MariaDB | Yes | via mysqli |
| Writable config dir | Yes | Volume at CONFIGS_DIR |
| Redis | No | Only for webhook dispatch |
The container listens on port 80 internally. Map it with -p 8888:80.
Environment variables
Core
| Variable | Required | Default | Description |
|---|---|---|---|
CONFIGS_DIR | Recommended | internal path | Use /app/apis in Docker |
CONFIG_API_SECRET | Yes (prod) | dev default | Header X-Management-Key |
CONFIG_API_IPS_ACLS | No | allow all | JSON IP ACL for management |
DEPLOYMENT_MODE | No | multi | Set single for auto-provision |
Single-mode database
| Variable | Required | Default |
|---|---|---|
DB_HOST | Yes | — |
DB_PORT | No | 3306 |
DB_NAME | Yes | — |
DB_USER | Yes | — |
DB_PASSWORD | No | empty |
Optional metadata: API_TITLE, API_DESCRIPTION, API_VERSION, license and contact API_* vars.
Limits (defaults)
DEFAULT_PAGE_SIZE=100, MAX_PAGE_SIZE=1000, REQUEST_TIMEOUT_SECONDS=60, MAX_INCLUDE_DEPTH=5.
Redis (optional webhooks)
REDIS_HOST, REDIS_PORT, REDIS_PASSWORD, REDIS_STREAM, REDIS_GROUP.
Single-API: docker run
docker run -d --name dbapi \
-p 8888:80 \
-e DEPLOYMENT_MODE=single \
-e CONFIGS_DIR=/app/apis \
-e CONFIG_API_SECRET='change-me-in-production' \
-e DB_HOST=mysql.example.com \
-e DB_PORT=3306 \
-e DB_NAME=myapp \
-e DB_USER=dbapi \
-e DB_PASSWORD='secret' \
-v dbapi-configs:/app/apis \
ghcr.io/dbapiator/dbapi:1.5.0
Verify:
curl -sS http://localhost:8888/
curl -sS http://localhost:8888/v1/data/
curl -sS http://localhost:8888/mgmt/v1/apis/default \
-H 'X-Management-Key: change-me-in-production'
Swagger UI: http://localhost:8888/swagger.html?url=v1/swagger
Single-API: Docker Compose
Use the starter in the repo under docker/base/:
cp -r path/to/dbapi/docker/base ./docker/dbapi
cd docker/dbapi
cp .env.example .env # CONFIG_API_SECRET, DB_*, DBAPI_IMAGE_TAG
docker compose up -d
Replace secrets and pin the image tag before production. Optional Adminer: docker compose --profile tools up -d.
Multi-API: docker run
docker run -d --name dbapi \
-p 8888:80 \
-e CONFIGS_DIR=/app/apis \
-e CONFIG_API_SECRET='change-me-in-production' \
-v dbapi-configs:/app/apis \
ghcr.io/dbapiator/dbapi:1.5.0
Create APIs via the Management API.
Volumes and persistence
Mount /app/apis (or your CONFIGS_DIR) as a named volume. It holds per-API config, policies, and OpenAPI. Application code is in the image — do not mount src/. Back up the config volume; deleting it removes API definitions.
Upgrades
- Pin semver tags in production.
- Read the changelog.
- Pull the new tag and recreate the container; keep the config volume.
docker pull ghcr.io/dbapiator/dbapi:1.5.0
docker stop dbapi && docker rm dbapi
# re-run docker run or compose with the new tag
Health check
GET /health is an unauthenticated liveness probe ({"status":"ok","service":"dbAPI"}). It does not test the database — use Management API connection:test for that.
curl -fsS http://localhost:8888/health
Troubleshooting
| Symptom | Likely cause | Check |
|---|---|---|
denied on pull | Private GHCR | docker login or public package |
| Exits on start | MySQL unreachable | DB_HOST, network, depends_on |
| 404 on data routes | API inactive / wrong mode | Single: /mgmt/v1/apis/default |
| 401 on management | Wrong secret | CONFIG_API_SECRET → X-Management-Key |
| Empty config after restart | No volume | Mount /app/apis |
docker logs -f dbapi